aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@qt.io>2021-04-19 16:43:21 +0200
committerFawzi Mohamed <fawzi.mohamed@qt.io>2021-06-05 00:08:00 +0200
commitdc5d14c3963e25a3664ed116856e7f604e43b7af (patch)
tree98370c3477b2bf07947a20cb71303de2cca4e6e4
parentde3d65009adf3c7ce0be6da77ee74b0a2610c9c5 (diff)
qmlformat: use QmlDom
Replace qmlformat with the formatter using qml dom Change-Id: Ie90814260f2d3b9e589ce04381d5ad1880c5b519 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--tests/auto/qml/qmlformat/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmlformat/data/Annotations.formatted.qml71
-rw-r--r--tests/auto/qml/qmlformat/data/Annotations.qml18
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml84
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.formatted.qml84
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml84
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.qml2
-rw-r--r--tests/auto/qml/qmlformat/data/FrontInline.formatted.qml1
-rw-r--r--tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml35
-rw-r--r--tests/auto/qml/qmlformat/data/QtBug85003.formatted.qml4
-rw-r--r--tests/auto/qml/qmlformat/data/arrowFunctions.formatted.qml6
-rw-r--r--tests/auto/qml/qmlformat/data/forOf.formatted.qml6
-rw-r--r--tests/auto/qml/qmlformat/data/inlineComponents.formatted.qml1
-rw-r--r--tests/auto/qml/qmlformat/data/largeBindings.formatted.qml12
-rw-r--r--tests/auto/qml/qmlformat/data/multilineComment.formatted.qml7
-rw-r--r--tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml10
-rw-r--r--tests/auto/qml/qmlformat/data/nestedIf.formatted.qml7
-rw-r--r--tests/auto/qml/qmlformat/data/propertyNames.formatted.qml1
-rw-r--r--tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml15
-rw-r--r--tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml9
-rw-r--r--tests/auto/qml/qmlformat/data/verbatimString.formatted.qml2
-rw-r--r--tests/auto/qml/qmlformat/tst_qmlformat.cpp3
-rw-r--r--tools/qmlformat/CMakeLists.txt7
-rw-r--r--tools/qmlformat/commentastvisitor.cpp288
-rw-r--r--tools/qmlformat/commentastvisitor.h141
-rw-r--r--tools/qmlformat/dumpastvisitor.cpp1434
-rw-r--r--tools/qmlformat/dumpastvisitor.h158
-rw-r--r--tools/qmlformat/qmlformat.cpp (renamed from tools/qmlformat/main.cpp)218
-rw-r--r--tools/qmlformat/restructureastvisitor.cpp196
-rw-r--r--tools/qmlformat/restructureastvisitor.h45
30 files changed, 371 insertions, 2579 deletions
diff --git a/tests/auto/qml/qmlformat/CMakeLists.txt b/tests/auto/qml/qmlformat/CMakeLists.txt
index 01f4fa2837..8d5133ccf7 100644
--- a/tests/auto/qml/qmlformat/CMakeLists.txt
+++ b/tests/auto/qml/qmlformat/CMakeLists.txt
@@ -20,6 +20,7 @@ qt_internal_add_test(tst_qmlformat
../../shared
PUBLIC_LIBRARIES
Qt::Gui
+ Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml
index ab56b5ce00..2fccb05e6e 100644
--- a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml
@@ -39,69 +39,100 @@ import QtCharts 2.0
@Annotation2 {
}
Item {
- //![1]
+ @Annotate {
+ }
+ anchors.fill: parent
@AnnotateMore {
property int x: 5
}
@AnnotateALot {
}
-
property variant othersSlice: 0
- @Annotate {
- }
- anchors.fill: parent
- @SuperComplete {
- binding: late
- }
- Component.onCompleted: {
- // You can also manipulate slices dynamically, like append a slice or set a slice exploded
- othersSlice = pieSeries.append("Others", 52);
- pieSeries.find("Volkswagen").exploded = true;
- }
//![1]
ChartView {
id: chart
-
title: "Top-5 car brand shares in Finland"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true
@ExtraAnnotation {
- signal pippo()
+ signal pippo
}
PieSeries {
+ @IdAnnotation {
+ des: "pippo"
+ }
id: pieSeries
-
+ @Maximum {
+ nTied: 0
+ }
PieSlice {
label: "Volkswagen"
value: 13.5
}
-
PieSlice {
label: "Toyota"
value: 10.9
}
-
PieSlice {
label: "Ford"
value: 8.6
}
-
PieSlice {
label: "Skoda"
value: 8.2
}
-
PieSlice {
label: "Volvo"
value: 6.8
}
+ }
+ @SignalAnnotation {
+ implicit: true
+ }
+ signal pippo2 // nice signal
+ @MethodAnnotation {
+ important: true
+ }
+ function foo(x) {
+ return 42;
}
+ @BindingAnn {
+ bType: 1
+ }
+ val: 34
+ @BindingAnn {
+ bType: 2
+ }
+ val2: Item {
+ }
+ @BindingAnn {
+ bType: 3
+ }
+ val3: [
+ Item {
+ }
+ ]
+ @BindingAnn {
+ bType: 4
+ }
+ Animation on val {
+ duration: 34
+ }
}
+ @SuperComplete {
+ binding: late
+ }
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52.0);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
}
diff --git a/tests/auto/qml/qmlformat/data/Annotations.qml b/tests/auto/qml/qmlformat/data/Annotations.qml
index 4638d4f7e9..0b4f3d8db9 100644
--- a/tests/auto/qml/qmlformat/data/Annotations.qml
+++ b/tests/auto/qml/qmlformat/data/Annotations.qml
@@ -56,13 +56,31 @@ Item {
signal pippo
}
PieSeries {
+ @IdAnnotation{ des: "pippo"}
id: pieSeries
+ @Maximum { nTied: 0 }
PieSlice { label: "Volkswagen"; value: 13.5 }
PieSlice { label: "Toyota"; value: 10.9 }
PieSlice { label: "Ford"; value: 8.6 }
PieSlice { label: "Skoda"; value: 8.2 }
PieSlice { label: "Volvo"; value: 6.8 }
}
+ @SignalAnnotation{ implicit: true }
+ signal pippo2 // nice signal
+ @MethodAnnotation{ important: true }
+ function foo(x){
+ return 42;
+ }
+ @BindingAnn{ bType: 1 }
+ val: 34
+ @BindingAnn{ bType: 2 }
+ val2: Item{ }
+ @BindingAnn{ bType: 3 }
+ val3: [ Item{} ]
+ @BindingAnn{ bType: 4 }
+ Animation on val {
+ duration: 34
+ }
}
@SuperComplete{
diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml
index 5e27aeec22..48a1acf483 100644
--- a/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml
+++ b/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml
@@ -19,34 +19,52 @@ import A.B.B.A
// This comment is related to Item
Item {
- // Orphan comment
- // Another orphan
- // More orphans
// This to id
// Also id. (line 2)
// This is the third id
// fourth id comment
id: foo
+ x: 3 // Very cool
// This to enum
enum Foo {
A = 3, // This is A
B, // This is B
C = 4, // This is C
- D // This is D
+ D // This is D
+ }
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
}
property bool some_bool: false
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo2
+ x: 3
+ y: x + 3
+ }
+
+ // Orphan comment
+
+ // Another orphan
+
+ // More orphans
property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
- property bool something_computed: function(x) {
- // This is an orphan inside something_computed
- // Are these getting duplicated?
- // Another orphan inside something_computed
+ property bool something_computed: function (x) {
const PI = 3, DAYS_PER_YEAR = 365.25;
var x = 3 + 2;
x["bla"] = 50;
+
+ // This is an orphan inside something_computed
+
+ // Are these getting duplicated?
+
// This one to var few!
var few = new WhatEver();
x += Math.sin(3);
@@ -62,23 +80,22 @@ Item {
y++;
console.log("Bar");
}
- while (true)
+ while (true) {
console.log("Wee");
-
+ }
with (foo) {
bar;
x += 5;
} // This is related to with!
- x3:
- do {
+ x3: do {
console.log("Hello");
- } while (3 == 0);
+ } while (3 == 0)
try {
dangerous();
} catch (e) {
console.log(e);
} finally {
- dangerous();
+ console.log("What else?");
}
switch (x) {
case 0:
@@ -91,12 +108,13 @@ Item {
x = 100;
break;
}
- if (x == 50)
+ if (x == 50) {
console.log("true");
- else if (x == 50)
+ } else if (x == 50) {
console.log("other thing");
- else
+ } else {
console.log("false");
+ }
if (x == 50) {
console.log("true");
} else if (x == 50) {
@@ -105,22 +123,12 @@ Item {
} else {
console.log("false");
}
+
+ // Another orphan inside something_computed
return "foobar";
}()
- default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
- // some_read_only_bool
- readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
-
- signal say(string name, bool caps)
-
- // This one to aFunc()
- function aFunc() {
- var x = 3;
- return x;
- }
- x: 3 // Very cool
- Component.onCompleted: console.log("Foo!")
+ default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
myFavouriteThings: [
// This is an orphan
@@ -132,20 +140,18 @@ Item {
}
]
- Text {
- required property string batman
+ // some_read_only_bool
+ readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
- signal boo(int count, int times, real duration)
+ signal say(string name, bool caps)
+ Text {
text: "Bla"
- }
- // This comment is related to the property animation
- PropertyAnimation on x {
- id: foo
+ signal boo(int count, int times, real duration)
- x: 3
- y: x + 3
+ required property string batman
}
+ Component.onCompleted: console.log("Foo!")
}
diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.qml
index fdc0b1f68c..a679e8a010 100644
--- a/tests/auto/qml/qmlformat/data/Example1.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/Example1.formatted.qml
@@ -19,34 +19,52 @@ import A.B.B.A
// This comment is related to Item
Item {
- // Orphan comment
- // Another orphan
- // More orphans
// This to id
// Also id. (line 2)
// This is the third id
// fourth id comment
id: foo
+ x: 3 // Very cool
// This to enum
enum Foo {
A = 3, // This is A
B, // This is B
C = 4, // This is C
- D // This is D
+ D // This is D
+ }
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
}
property bool some_bool: false
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo2
+ x: 3
+ y: x + 3
+ }
+
+ // Orphan comment
+
+ // Another orphan
+
+ // More orphans
property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
- property bool something_computed: function(x) {
- // This is an orphan inside something_computed
- // Are these getting duplicated?
- // Another orphan inside something_computed
+ property bool something_computed: function (x) {
const PI = 3, DAYS_PER_YEAR = 365.25;
var x = 3 + 2;
x["bla"] = 50;
+
+ // This is an orphan inside something_computed
+
+ // Are these getting duplicated?
+
// This one to var few!
var few = new WhatEver();
x += Math.sin(3);
@@ -62,23 +80,22 @@ Item {
y++;
console.log("Bar");
}
- while (true)
+ while (true) {
console.log("Wee");
-
+ }
with (foo) {
bar;
x += 5;
} // This is related to with!
- x3:
- do {
+ x3: do {
console.log("Hello");
- } while (3 == 0);
+ } while (3 == 0)
try {
dangerous();
} catch (e) {
console.log(e);
} finally {
- dangerous();
+ console.log("What else?");
}
switch (x) {
case 0:
@@ -91,12 +108,13 @@ Item {
x = 100;
break;
}
- if (x == 50)
+ if (x == 50) {
console.log("true");
- else if (x == 50)
+ } else if (x == 50) {
console.log("other thing");
- else
+ } else {
console.log("false");
+ }
if (x == 50) {
console.log("true");
} else if (x == 50) {
@@ -105,22 +123,12 @@ Item {
} else {
console.log("false");
}
+
+ // Another orphan inside something_computed
return "foobar";
}()
- default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
- // some_read_only_bool
- readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
-
- signal say(string name, bool caps)
-
- // This one to aFunc()
- function aFunc() {
- var x = 3;
- return x;
- }
- x: 3 // Very cool
- Component.onCompleted: console.log("Foo!")
+ default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
myFavouriteThings: [
// This is an orphan
@@ -132,20 +140,18 @@ Item {
}
]
- Text {
- required property string batman
+ // some_read_only_bool
+ readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
- signal boo(int count, int times, real duration)
+ signal say(string name, bool caps)
+ Text {
text: "Bla"
- }
- // This comment is related to the property animation
- PropertyAnimation on x {
- id: foo
+ signal boo(int count, int times, real duration)
- x: 3
- y: x + 3
+ required property string batman
}
+ Component.onCompleted: console.log("Foo!")
}
diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml
index d1c17c4c6b..34b3467cb4 100644
--- a/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml
+++ b/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml
@@ -19,34 +19,52 @@ import A.B.B.A
// This comment is related to Item
Item {
- // Orphan comment
- // Another orphan
- // More orphans
// This to id
// Also id. (line 2)
// This is the third id
// fourth id comment
id: foo
+ x: 3 // Very cool
// This to enum
enum Foo {
A = 3, // This is A
B, // This is B
C = 4, // This is C
- D // This is D
+ D // This is D
+ }
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
}
property bool some_bool: false
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo2
+ x: 3
+ y: x + 3
+ }
+
+ // Orphan comment
+
+ // Another orphan
+
+ // More orphans
property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
- property bool something_computed: function(x) {
- // This is an orphan inside something_computed
- // Are these getting duplicated?
- // Another orphan inside something_computed
+ property bool something_computed: function (x) {
const PI = 3, DAYS_PER_YEAR = 365.25;
var x = 3 + 2;
x["bla"] = 50;
+
+ // This is an orphan inside something_computed
+
+ // Are these getting duplicated?
+
// This one to var few!
var few = new WhatEver();
x += Math.sin(3);
@@ -62,23 +80,22 @@ Item {
y++;
console.log("Bar");
}
- while (true)
+ while (true) {
console.log("Wee");
-
+ }
with (foo) {
bar;
x += 5;
} // This is related to with!
- x3:
- do {
+ x3: do {
console.log("Hello");
- } while (3 == 0);
+ } while (3 == 0)
try {
dangerous();
} catch (e) {
console.log(e);
} finally {
- dangerous();
+ console.log("What else?");
}
switch (x) {
case 0:
@@ -91,12 +108,13 @@ Item {
x = 100;
break;
}
- if (x == 50)
+ if (x == 50) {
console.log("true");
- else if (x == 50)
+ } else if (x == 50) {
console.log("other thing");
- else
+ } else {
console.log("false");
+ }
if (x == 50) {
console.log("true");
} else if (x == 50) {
@@ -105,22 +123,12 @@ Item {
} else {
console.log("false");
}
+
+ // Another orphan inside something_computed
return "foobar";
}()
- default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
- // some_read_only_bool
- readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
-
- signal say(string name, bool caps)
-
- // This one to aFunc()
- function aFunc() {
- var x = 3;
- return x;
- }
- x: 3 // Very cool
- Component.onCompleted: console.log("Foo!")
+ default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
myFavouriteThings: [
// This is an orphan
@@ -132,20 +140,18 @@ Item {
}
]
- Text {
- required property string batman
+ // some_read_only_bool
+ readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
- signal boo(int count, int times, real duration)
+ signal say(string name, bool caps)
+ Text {
text: "Bla"
- }
- // This comment is related to the property animation
- PropertyAnimation on x {
- id: foo
+ signal boo(int count, int times, real duration)
- x: 3
- y: x + 3
+ required property string batman
}
+ Component.onCompleted: console.log("Foo!")
}
diff --git a/tests/auto/qml/qmlformat/data/Example1.qml b/tests/auto/qml/qmlformat/data/Example1.qml
index 0fb9053e3a..36ffc6b058 100644
--- a/tests/auto/qml/qmlformat/data/Example1.qml
+++ b/tests/auto/qml/qmlformat/data/Example1.qml
@@ -40,7 +40,7 @@ Item {
property bool some_bool : false
// This comment is related to the property animation
PropertyAnimation on x {
- id: foo; x: 3; y: x + 3
+ id: foo2; x: 3; y: x + 3
}
// Orphan comment
diff --git a/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml b/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml
index 620fbf4120..7dfe435ac0 100644
--- a/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml
@@ -1,3 +1,4 @@
// This comment should be directly above Item after formatting
+
Item {
}
diff --git a/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml b/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml
index d89260df5d..0db1801d8a 100644
--- a/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml
@@ -1,4 +1,5 @@
#!/she-bang
+
Item {
function test() {
//// The following if blocks should NOT HAVE braces
@@ -7,8 +8,9 @@ Item {
console.log("foo");
// Single branch, no braces
- if (true)
+ if (true) {
console.log("foo");
+ }
// Multiple branches, No braces
if (true)
@@ -17,46 +19,49 @@ Item {
console.log("bar");
else
console.log("baz");
+
// Multiple branches, all braces
- if (true)
+ if (true) {
console.log("foo");
- else if (false)
+ } else if (false) {
console.log("bar");
- else
+ } else {
console.log("baz");
+ }
+
//// The following if blocks should HAVE braces
// Single branch, braces
if (true) {
console.log("foo");
console.log("bar");
}
+
// Multiple branches, some braces
if (true) {
console.log("foo");
console.log("foo2");
- } else if (false) {
+ } else if (false)
console.log("bar");
- } else {
+ else
console.log("baz");
- }
+
// Multiple branches, some braces
- if (true) {
+ if (true)
console.log("foo");
- } else if (false) {
+ else if (false) {
console.log("bar");
console.log("bar2");
- } else {
+ } else
console.log("baz");
- }
+
// Multiple branches, some braces
- if (true) {
+ if (true)
console.log("foo");
- } else if (false) {
+ else if (false)
console.log("bar");
- } else {
+ else {
console.log("baz");
console.log("baz2");
}
}
-
}
diff --git a/tests/auto/qml/qmlformat/data/QtBug85003.formatted.qml b/tests/auto/qml/qmlformat/data/QtBug85003.formatted.qml
index 53e278ab9c..5d8d7a5fb4 100644
--- a/tests/auto/qml/qmlformat/data/QtBug85003.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/QtBug85003.formatted.qml
@@ -1,10 +1,12 @@
#!/she-bang
// extra comment
+
Item {
Component.onCompleted: {
if (3 < 2)
console.log("Foo");
- else
+ else {
console.log("Bar");
+ }
}
}
diff --git a/tests/auto/qml/qmlformat/data/arrowFunctions.formatted.qml b/tests/auto/qml/qmlformat/data/arrowFunctions.formatted.qml
index e4bc1f6747..b9b3fdf319 100644
--- a/tests/auto/qml/qmlformat/data/arrowFunctions.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/arrowFunctions.formatted.qml
@@ -1,5 +1,5 @@
Item {
- arrow1: (x) => x
- arrow2: (x) => x + x
- arrow3: () => x > 3 ? x * x : x
+ arrow1: x => x;
+ arrow2: x => x + x;
+ arrow3: () => x > 3 ? x * x : x;
}
diff --git a/tests/auto/qml/qmlformat/data/forOf.formatted.qml b/tests/auto/qml/qmlformat/data/forOf.formatted.qml
index fa29f16b81..fa9ff9c631 100644
--- a/tests/auto/qml/qmlformat/data/forOf.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/forOf.formatted.qml
@@ -3,7 +3,9 @@ import QtQml 2.0
QtObject {
Component.onCompleted: {
var list = [[1, 2], [3, 4], [5, 6]];
- for (const [x, y] of list) console.log("X: " + x + "; Y: " + y)
- for (let [x, y] of list) console.log("X: " + x + "; Y: " + y)
+ for (const [x, y] of list)
+ console.log("X: " + x + "; Y: " + y);
+ for (let [x, y] of list)
+ console.log("X: " + x + "; Y: " + y);
}
}
diff --git a/tests/auto/qml/qmlformat/data/inlineComponents.formatted.qml b/tests/auto/qml/qmlformat/data/inlineComponents.formatted.qml
index fd5ab99197..9d35f763fa 100644
--- a/tests/auto/qml/qmlformat/data/inlineComponents.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/inlineComponents.formatted.qml
@@ -3,5 +3,4 @@ Item {
color: "red"
text: "Test Text"
}
-
}
diff --git a/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml b/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml
index 354693d229..70283dade6 100644
--- a/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml
@@ -2,16 +2,14 @@ import QtQml
import QtQuick 2
QtObject {
- small1: 3
- small2: foo
- smallButNeedsBraces: {
- if (foo) {
- bar();
- }
- }
// THIS NEEDS TO BE LAST
largeBinding: {
var x = 300;
console.log(x);
}
+ small1: 3
+ small2: foo
+ smallButNeedsBraces: if (foo) {
+ bar();
+ }
}
diff --git a/tests/auto/qml/qmlformat/data/multilineComment.formatted.qml b/tests/auto/qml/qmlformat/data/multilineComment.formatted.qml
index 830ff32095..45d04c5887 100644
--- a/tests/auto/qml/qmlformat/data/multilineComment.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/multilineComment.formatted.qml
@@ -2,11 +2,10 @@ Item {
Item {
}
- // This is a multiline comment.
- // it should stay attached to Commented instead of getting orphaned.
- //
+ /* This is a multiline comment.
+ it should stay attached to Commented instead of getting orphaned.
+ */
// This should also stick to Commented
Commented {
}
-
}
diff --git a/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml b/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml
index 5a3489e98f..522e844201 100644
--- a/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml
@@ -1,16 +1,10 @@
Item {
function a() {
- function nested() {
- }
-
+ function nested() {}
foo();
}
-
function b() {
- function nested() {
- }
-
+ function nested() {}
bar();
}
-
}
diff --git a/tests/auto/qml/qmlformat/data/nestedIf.formatted.qml b/tests/auto/qml/qmlformat/data/nestedIf.formatted.qml
index 11acf5b568..4ff5a40a23 100644
--- a/tests/auto/qml/qmlformat/data/nestedIf.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/nestedIf.formatted.qml
@@ -6,11 +6,11 @@ Item {
foo();
else
bar();
- } else if (x == 3) {
+ } else if (x == 3)
stuff();
- } else {
+ else
foo_bar();
- }
+
// Same for "for"
if (a) {
for (x in y) {
@@ -18,6 +18,7 @@ Item {
y();
}
}
+
// ...and while
if (b) {
while (y in x) {
diff --git a/tests/auto/qml/qmlformat/data/propertyNames.formatted.qml b/tests/auto/qml/qmlformat/data/propertyNames.formatted.qml
index c7d50abb32..94b5877957 100644
--- a/tests/auto/qml/qmlformat/data/propertyNames.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/propertyNames.formatted.qml
@@ -10,5 +10,4 @@ Item {
"copiedItem": copiedItem
};
}
-
}
diff --git a/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml
index 6e7cc31dcf..3084ab7951 100644
--- a/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml
@@ -2,28 +2,27 @@ import QtQuick 2.0
QtObject {
// Testing UiObjectBinding
- readonly property Item
- item: Item {
+ readonly property Item item: Item {
id: test
-
- signal foo()
+ signal foo
}
+
// End comment
// Testing UiArrayBinding
readonly property list<Item> array: [
Item {
id: test1
-
- signal foo()
+ signal foo
},
Item {
id: test2
-
- signal bar()
+ signal bar
}
]
+
// Testing UiScriptBinding
readonly property int script: Math.sin(Math.PI)
+
property bool normalProperty: true
}
diff --git a/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml b/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml
index bd063ac498..f72e9d8195 100644
--- a/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml
@@ -1,10 +1,5 @@
QtObject {
id: foo
-
- // This needs to be *before* states and transitions after formatting
- Item {
- }
-
states: [
State {
}
@@ -13,4 +8,8 @@ QtObject {
Transition {
}
]
+
+ // This needs to be *before* states and transitions after formatting
+ Item {
+ }
}
diff --git a/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml b/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml
index 84abe38f88..65539b538a 100644
--- a/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml
+++ b/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml
@@ -1,6 +1,8 @@
Item {
property string verbatim1: 'A "verbatim" string!'
+
property string verbatim2: "A 'verbatim' string\u2757"
+
property string verbatim3: `400 + 300 is ${400 + 300}.
mutliline`
diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
index a208b37fff..f9cf4deafb 100644
--- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp
+++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
@@ -32,6 +32,7 @@
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
+#include <QtTest/private/qemulationdetector_p.h>
#include <util.h>
@@ -258,6 +259,8 @@ void TestQmlformat::testFormat()
#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
void TestQmlformat::testExample_data()
{
+ if (QTestPrivate::isRunningArmOnX86())
+ QSKIP("Crashes in QEMU. (timeout)");
QTest::addColumn<QString>("file");
QString examples = QLatin1String(SRCDIR) + "/../../../../examples/";
diff --git a/tools/qmlformat/CMakeLists.txt b/tools/qmlformat/CMakeLists.txt
index e492a3ec56..eeabe1c368 100644
--- a/tools/qmlformat/CMakeLists.txt
+++ b/tools/qmlformat/CMakeLists.txt
@@ -9,12 +9,11 @@ qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "QML Formatter"
TOOLS_TARGET Qml # special case
SOURCES
- commentastvisitor.cpp commentastvisitor.h
- dumpastvisitor.cpp dumpastvisitor.h
- main.cpp
- restructureastvisitor.cpp restructureastvisitor.h
+ qmlformat.cpp
PUBLIC_LIBRARIES
+ Qt::Core
Qt::QmlDevToolsPrivate
+ Qt::QmlDomPrivate
)
#### Keys ignored in scope 1:.:.:qmlformat.pro:<TRUE>:
diff --git a/tools/qmlformat/commentastvisitor.cpp b/tools/qmlformat/commentastvisitor.cpp
deleted file mode 100644
index f07f770b33..0000000000
--- a/tools/qmlformat/commentastvisitor.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "commentastvisitor.h"
-
-using namespace QQmlJS;
-using namespace QQmlJS::AST;
-
-CommentAstVisitor::CommentAstVisitor(QQmlJS::Engine *engine, Node *rootNode) : m_engine(engine)
-{
- rootNode->accept(this);
-
- // Look for complete orphans that have not been attached to *any* node
- QVector<Comment> completeOrphans;
-
- for (const auto &comment : m_engine->comments()) {
- if (isCommentAttached(comment))
- continue;
-
- bool found_orphan = false;
- for (const auto &orphanList : orphanComments().values()) {
- for (const auto &orphan : orphanList) {
- if (orphan.contains(comment)) {
- found_orphan = true;
- break;
- }
- }
-
- if (found_orphan)
- break;
- }
-
- if (found_orphan)
- continue;
-
- completeOrphans.append(Comment(m_engine, Comment::Location::Front, {comment}));
- }
-
- m_orphanComments[nullptr] = completeOrphans;
-}
-
-QList<SourceLocation> CommentAstVisitor::findCommentsInLine(quint32 line, bool includePrevious) const
-{
- QList<SourceLocation> results;
- if (line == 0)
- return results;
-
- for (const auto &location : m_engine->comments()) {
- Comment comment(m_engine, Comment::Location::Front, { location });
- if (line < location.startLine || line > comment.endLine())
- continue;
-
- if (isCommentAttached(location))
- continue;
-
- results.append(location);
-
- if (includePrevious) {
- // See if we can find any more comments above this one
- auto previous = findCommentsInLine(location.startLine - 1, true);
-
- // Iterate it in reverse to restore the correct order
- for (auto it = previous.rbegin(); it != previous.rend(); it++) {
- results.prepend(*it);
- }
- }
-
- break;
- }
-
- return results;
-}
-
-bool CommentAstVisitor::isCommentAttached(const SourceLocation &location) const
-{
- for (const auto &value : m_attachedComments.values()) {
- if (value.contains(location))
- return true;
- }
-
- for (const auto &value : m_listItemComments.values()) {
- if (value.contains(location))
- return true;
- }
-
- // If a comment is already marked as an orphan of a Node that counts as attached too.
- for (const auto &orphanList : m_orphanComments.values()) {
- for (const auto &value : orphanList) {
- if (value.contains(location))
- return true;
- }
- }
-
- return false;
-}
-
-Comment CommentAstVisitor::findComment(SourceLocation first, SourceLocation last,
- int locations) const
-{
- if (locations & Comment::Location::Front) {
- quint32 searchAt = first.startLine - 1;
-
- const auto comments = findCommentsInLine(searchAt, true);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Front, comments);
- }
-
- if (locations & Comment::Location::Front_Inline) {
- quint32 searchAt = first.startLine;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Front_Inline, comments);
- }
-
- if (locations & Comment::Location::Back_Inline) {
- quint32 searchAt = last.startLine;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Back_Inline, comments);
- }
-
- if (locations & Comment::Location::Back) {
- quint32 searchAt = last.startLine + 1;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Back, comments);
- }
-
- return Comment();
-
-}
-
-Comment CommentAstVisitor::findComment(Node *node, int locations) const
-{
- return findComment(node->firstSourceLocation(), node->lastSourceLocation(), locations);
-}
-
-QVector<Comment> CommentAstVisitor::findOrphanComments(Node *node) const
-{
- QVector<Comment> comments;
-
- for (auto &comment : m_engine->comments()) {
- if (isCommentAttached(comment))
- continue;
-
- if (comment.begin() <= node->firstSourceLocation().begin()
- || comment.end() > node->lastSourceLocation().end()) {
- continue;
- }
-
- comments.append(Comment(m_engine, Comment::Location::Front, {comment}));
- }
-
- return comments;
-}
-
-void CommentAstVisitor::attachComment(Node *node, int locations)
-{
- auto comment = findComment(node, locations);
-
- if (comment.isValid())
- m_attachedComments[node] = comment;
-}
-
-bool CommentAstVisitor::visit(UiScriptBinding *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(StatementList *node)
-{
- for (auto *item = node; item != nullptr; item = item->next)
- attachComment(item->statement, Comment::Front | Comment::Back_Inline);
- return true;
-}
-
-void CommentAstVisitor::endVisit(StatementList *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiObjectBinding *node)
-{
- attachComment(node, Comment::Front | Comment::Front_Inline | Comment::Back);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiObjectDefinition *node)
-{
- attachComment(node, Comment::Front | Comment::Front_Inline | Comment::Back);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiObjectDefinition *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiArrayBinding *node)
-{
- attachComment(node);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiArrayBinding *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiEnumDeclaration *node)
-{
- attachComment(node);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiEnumDeclaration *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiEnumMemberList *node)
-{
- for (auto *item = node; item != nullptr; item = item->next) {
- auto comment = findComment(item->memberToken,
- item->valueToken.isValid() ? item->valueToken : item->memberToken,
- Comment::Front | Comment::Back_Inline);
-
- if (comment.isValid())
- m_listItemComments[item->memberToken.begin()] = comment;
- }
-
- m_orphanComments[node] = findOrphanComments(node);
-
- return true;
-}
-
-bool CommentAstVisitor::visit(UiPublicMember *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(FunctionDeclaration *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiImport *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiPragma *node)
-{
- attachComment(node);
- return true;
-}
diff --git a/tools/qmlformat/commentastvisitor.h b/tools/qmlformat/commentastvisitor.h
deleted file mode 100644
index 73a6015db7..0000000000
--- a/tools/qmlformat/commentastvisitor.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef COMMENTASTVISITOR_H
-#define COMMENTASTVISITOR_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-#include <QtQml/private/qqmljsengine_p.h>
-
-#include <QHash>
-#include <QString>
-#include <QVector>
-
-struct Comment
-{
- enum Location : int
- {
- Front = 1,
- Front_Inline = Front << 1,
- Back = Front_Inline << 1,
- Back_Inline = Back << 1,
- DefaultLocations = Front | Back_Inline,
- AllLocations = Front | Back | Front_Inline | Back_Inline
- } m_location = Front;
-
- Comment() = default;
- Comment(const QQmlJS::Engine *engine, Location location, QList<QQmlJS::SourceLocation> srcLocations)
- : m_location(location), m_srcLocations(srcLocations) {
- for (const auto& srcLoc : srcLocations) {
- m_text += engine->code().mid(static_cast<int>(srcLoc.begin()),
- static_cast<int>(srcLoc.end() - srcLoc.begin())) + "\n";
- }
-
- m_text.chop(1);
- }
-
- QList<QQmlJS::SourceLocation> m_srcLocations;
-
- bool hasSheBang() const { return !m_srcLocations.isEmpty() && m_srcLocations.first().begin() == 0; }
- bool isValid() const { return !m_srcLocations.isEmpty(); }
- bool isMultiline() const { return m_text.contains("\n"); }
- bool isSyntheticMultiline() const { return m_srcLocations.size() > 1; }
-
- bool contains(const QQmlJS::SourceLocation& location) const {
- for (const QQmlJS::SourceLocation& srcLoc : m_srcLocations) {
- if (srcLoc.begin() == location.begin() && srcLoc.end() == location.end())
- return true;
- }
-
- return false;
- }
-
- quint32 endLine() const
- {
- if (isSyntheticMultiline() || !isValid())
- return 0;
-
- return m_srcLocations[0].startLine + m_text.count(QLatin1Char('\n'));
- }
-
- QString m_text;
-};
-
-namespace AST = QQmlJS::AST;
-class CommentAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- CommentAstVisitor(QQmlJS::Engine *engine, AST::Node *rootNode);
-
- void throwRecursionDepthError() override {}
-
- const QHash<AST::Node *, Comment> attachedComments() const { return m_attachedComments; }
- const QHash<quint32, Comment> listComments() const { return m_listItemComments; }
- const QHash<AST::Node *, QVector<Comment>> orphanComments() const { return m_orphanComments; }
-
- bool visit(AST::UiScriptBinding *node) override;
- bool visit(AST::UiObjectBinding *node) override;
-
- bool visit(AST::UiArrayBinding *node) override;
- void endVisit(AST::UiArrayBinding *node) override;
-
- bool visit(AST::UiObjectDefinition *node) override;
- void endVisit(AST::UiObjectDefinition *) override;
-
- bool visit(AST::UiEnumDeclaration *node) override;
- void endVisit(AST::UiEnumDeclaration *node) override;
-
- bool visit(AST::UiEnumMemberList *node) override;
-
- bool visit(AST::StatementList *node) override;
- void endVisit(AST::StatementList *node) override;
-
- bool visit(AST::UiImport *node) override;
- bool visit(AST::UiPragma *node) override;
- bool visit(AST::UiPublicMember *node) override;
- bool visit(AST::FunctionDeclaration *node) override;
-private:
- bool isCommentAttached(const QQmlJS::SourceLocation& location) const;
-
- QList<QQmlJS::SourceLocation> findCommentsInLine(quint32 line, bool includePrevious = false) const;
-
- Comment findComment(QQmlJS::SourceLocation first, QQmlJS::SourceLocation last,
- int locations = Comment::DefaultLocations) const;
-
- Comment findComment(AST::Node *node, int locations = Comment::DefaultLocations) const;
- QVector<Comment> findOrphanComments(AST::Node *node) const;
- void attachComment(AST::Node *node, int locations = Comment::DefaultLocations);
-
- QQmlJS::Engine *m_engine;
- QHash<AST::Node *, Comment> m_attachedComments;
- QHash<quint32, Comment> m_listItemComments;
- QHash<AST::Node *, QVector<Comment>> m_orphanComments;
-};
-
-#endif // COMMENTASTVISITOR_H
diff --git a/tools/qmlformat/dumpastvisitor.cpp b/tools/qmlformat/dumpastvisitor.cpp
deleted file mode 100644
index baf6651b20..0000000000
--- a/tools/qmlformat/dumpastvisitor.cpp
+++ /dev/null
@@ -1,1434 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "dumpastvisitor.h"
-#include <QtQml/private/qqmljslexer_p.h>
-
-using namespace QQmlJS::AST;
-
-DumpAstVisitor::DumpAstVisitor(QQmlJS::Engine *engine, Node *rootNode, CommentAstVisitor *comment,
- int indentWidth, DumpAstVisitor::Indentation indentation)
- : m_engine(engine), m_comment(comment), m_indentWidth(indentWidth), m_indentation(indentation)
-{
- // Add all completely orphaned comments
- m_result += getOrphanedComments(nullptr);
-
- m_scope_properties.push(ScopeProperties {});
-
- rootNode->accept(this);
-
- // We need to get rid of one new-line so our output doesn't append an empty line
- m_result.chop(1);
-
- // Remove trailing whitespace
- QStringList lines = m_result.split("\n");
- for (QString& line : lines) {
- while (line.endsWith(" "))
- line.chop(1);
- }
-
- m_result = lines.join("\n");
-}
-
-bool DumpAstVisitor::preVisit(Node *el)
-{
- UiObjectMember *m = el->uiObjectMemberCast();
- if (m != 0)
- Node::accept(m->annotations, this);
- return true;
-}
-
-static QString parseUiQualifiedId(UiQualifiedId *id)
-{
- QString name = id->name.toString();
- for (auto *item = id->next; item != nullptr; item = item->next) {
- name += "." + item->name;
- }
-
- return name;
-}
-
-static QString operatorToString(int op)
-{
- switch (op)
- {
- case QSOperator::Add: return "+";
- case QSOperator::And: return "&&";
- case QSOperator::InplaceAnd: return "&=";
- case QSOperator::Assign: return "=";
- case QSOperator::BitAnd: return "&";
- case QSOperator::BitOr: return "|";
- case QSOperator::BitXor: return "^";
- case QSOperator::InplaceSub: return "-=";
- case QSOperator::Div: return "/";
- case QSOperator::InplaceDiv: return "/=";
- case QSOperator::Equal: return "==";
- case QSOperator::Exp: return "**";
- case QSOperator::InplaceExp: return "**=";
- case QSOperator::Ge: return ">=";
- case QSOperator::Gt: return ">";
- case QSOperator::In: return "in";
- case QSOperator::InplaceAdd: return "+=";
- case QSOperator::InstanceOf: return "instanceof";
- case QSOperator::Le: return "<=";
- case QSOperator::LShift: return "<<";
- case QSOperator::InplaceLeftShift: return "<<=";
- case QSOperator::Lt: return "<";
- case QSOperator::Mod: return "%";
- case QSOperator::InplaceMod: return "%=";
- case QSOperator::Mul: return "*";
- case QSOperator::InplaceMul: return "*=";
- case QSOperator::NotEqual: return "!=";
- case QSOperator::Or: return "||";
- case QSOperator::InplaceOr: return "|=";
- case QSOperator::RShift: return ">>";
- case QSOperator::InplaceRightShift: return ">>=";
- case QSOperator::StrictEqual: return "===";
- case QSOperator::StrictNotEqual: return "!==";
- case QSOperator::Sub: return "-";
- case QSOperator::URShift: return ">>>";
- case QSOperator::InplaceURightShift: return ">>>=";
- case QSOperator::InplaceXor: return "^=";
- case QSOperator::As: return "as";
- case QSOperator::Coalesce: return "??";
- case QSOperator::Invalid:
- default:
- return "INVALID";
- }
-}
-
-QString DumpAstVisitor::formatComment(const Comment &comment) const
-{
- QString result;
-
- bool useMultilineComment = comment.isMultiline() && !comment.isSyntheticMultiline();
-
- if (useMultilineComment)
- result += "/*";
- else if (!comment.hasSheBang())
- result += "//";
-
- result += comment.m_text;
-
- if (comment.isSyntheticMultiline())
- result = result.replace("\n","\n" + formatLine("//", false));
-
- if (comment.m_location == Comment::Location::Back_Inline)
- result.prepend(" ");
-
- if (useMultilineComment)
- result += "*/";
-
- return result;
-}
-
-QString DumpAstVisitor::getComment(Node *node, Comment::Location location) const
-{
- const auto& comments = m_comment->attachedComments();
- if (!comments.contains(node))
- return "";
-
- auto comment = comments[node];
-
- if (comment.m_location != location)
- return "";
-
- return formatComment(comment);
-}
-
-QString DumpAstVisitor::getListItemComment(QQmlJS::SourceLocation srcLocation,
- Comment::Location location) const {
- const auto& comments = m_comment->listComments();
-
- if (!comments.contains(srcLocation.begin()))
- return "";
-
- auto comment = comments[srcLocation.begin()];
-
- if (comment.m_location != location)
- return "";
-
- return formatComment(comment);
-}
-
-QString DumpAstVisitor::getOrphanedComments(Node *node) const {
- const auto& orphans = m_comment->orphanComments()[node];
-
- if (orphans.size() == 0)
- return "";
-
- QString result = "";
-
- for (const Comment& orphan : orphans) {
- result += formatLine(formatComment(orphan));
- }
-
- result += "\n";
-
- return result;
-}
-
-QString DumpAstVisitor::parseArgumentList(ArgumentList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parseExpression(item->expression) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parseUiParameterList(UiParameterList *list) {
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parseUiQualifiedId(item->type) + " " + item->name + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parsePatternElement(PatternElement *element, bool scope)
-{
- switch (element->type)
- {
- case PatternElement::Literal:
- return parseExpression(element->initializer);
- case PatternElement::Binding: {
- QString result = "";
- QString expr = parseExpression(element->initializer);
-
- if (scope) {
- switch (element->scope) {
- case VariableScope::NoScope:
- break;
- case VariableScope::Let:
- result = "let ";
- break;
- case VariableScope::Const:
- result = "const ";
- break;
- case VariableScope::Var:
- result = "var ";
- break;
- }
- }
-
- if (element->bindingIdentifier.isEmpty())
- result += parseExpression(element->bindingTarget);
- else
- result += element->bindingIdentifier.toString();
-
- if (element->typeAnnotation != nullptr)
- result += ": " + parseType(element->typeAnnotation->type);
-
- if (!expr.isEmpty())
- result += " = "+expr;
-
- return result;
- }
- default:
- m_error = true;
- return "pe_unknown";
- }
-}
-
-static QString escapeString(QString string)
-{
- // Handle escape sequences
- string = string.replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t")
- .replace("\b","\\b").replace("\v", "\\v").replace("\f", "\\f");
-
- // Escape backslash
- string = string.replace("\\", "\\\\");
-
- // Escape "
- string = string.replace("\"", "\\\"");
-
- return "\"" + string + "\"";
-}
-
-QString DumpAstVisitor::parsePatternElementList(PatternElementList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parseFormalParameterList(FormalParameterList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parsePatternProperty(PatternProperty *property)
-{
- switch (property->type) {
- case PatternElement::Getter:
- return "get "+parseFunctionExpression(cast<FunctionExpression *>(property->initializer), true);
- case PatternElement::Setter:
- return "set "+parseFunctionExpression(cast<FunctionExpression *>(property->initializer), true);
- default:
- if (property->name->kind == Node::Kind_ComputedPropertyName) {
- return "["+parseExpression(cast<ComputedPropertyName *>(property->name)->expression)+"]: "+parsePatternElement(property, false);
- } else {
- return escapeString(property->name->asString())+": "+parsePatternElement(property, false);
- }
- }
-}
-
-QString DumpAstVisitor::parsePatternPropertyList(PatternPropertyList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += formatLine(parsePatternProperty(item->property) + (item->next != nullptr ? "," : ""));
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseFunctionExpression(FunctionExpression *functExpr, bool omitFunction)
-{
- m_indentLevel++;
- QString result;
- bool hasBraces = true;
-
- if (!functExpr->isArrowFunction) {
- result += omitFunction ? "" : "function";
-
- if (functExpr->isGenerator)
- result += "*";
-
- if (!functExpr->name.isEmpty())
- result += (omitFunction ? "" : " ") + functExpr->name;
-
- result += "("+parseFormalParameterList(functExpr->formals)+")";
-
- if (functExpr->typeAnnotation != nullptr)
- result += " : " + parseType(functExpr->typeAnnotation->type);
-
- result += " {\n" + parseStatementList(functExpr->body);
- } else {
- result += "("+parseFormalParameterList(functExpr->formals)+")";
-
- if (functExpr->typeAnnotation != nullptr)
- result += " : " + parseType(functExpr->typeAnnotation->type);
-
- result += " => ";
-
- if (functExpr->body == nullptr) {
- result += "{}";
- } else if (functExpr->body->next == nullptr && functExpr->body->statement->kind == Node::Kind_ReturnStatement) {
- m_indentLevel--;
- result += parseExpression(cast<ReturnStatement *>(functExpr->body->statement)->expression);
- hasBraces = false;
- } else {
- result += "{\n" + parseStatementList(functExpr->body);
- }
- }
-
- if (hasBraces) {
- m_indentLevel--;
- result += formatLine("}", false);
- }
-
- return result;
-
-}
-
-QString DumpAstVisitor::parseType(Type *type) {
- QString result = parseUiQualifiedId(type->typeId);
-
- if (type->typeArguments != nullptr) {
- TypeArgumentList *list = cast<TypeArgumentList *>(type->typeArguments);
-
- result += "<";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += parseType(item->typeId) + (item->next != nullptr ? ", " : "");
- }
-
- result += ">";
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseExpression(ExpressionNode *expression)
-{
- if (expression == nullptr)
- return "";
-
- switch (expression->kind)
- {
- case Node::Kind_ArrayPattern:
- return "["+parsePatternElementList(cast<ArrayPattern *>(expression)->elements)+"]";
- case Node::Kind_IdentifierExpression:
- return cast<IdentifierExpression*>(expression)->name.toString();
- case Node::Kind_FieldMemberExpression: {
- auto *fieldMemberExpr = cast<FieldMemberExpression *>(expression);
- QString result = parseExpression(fieldMemberExpr->base);
-
- // If we're operating on a numeric literal, always put it in braces
- if (fieldMemberExpr->base->kind == Node::Kind_NumericLiteral)
- result = "(" + result + ")";
-
- result += (fieldMemberExpr->isOptional ? "?." : ".") + fieldMemberExpr->name.toString();
-
- return result;
- }
- case Node::Kind_ArrayMemberExpression: {
- auto *arrayMemberExpr = cast<ArrayMemberExpression *>(expression);
- return parseExpression(arrayMemberExpr->base)
- + (arrayMemberExpr->isOptional ? "?." : "") + "[" + parseExpression(arrayMemberExpr->expression) + "]";
- }
- case Node::Kind_NestedExpression:
- return "("+parseExpression(cast<NestedExpression *>(expression)->expression)+")";
- case Node::Kind_TrueLiteral:
- return "true";
- case Node::Kind_FalseLiteral:
- return "false";
- case Node::Kind_FunctionExpression:
- {
- auto *functExpr = cast<FunctionExpression *>(expression);
- return parseFunctionExpression(functExpr);
- }
- case Node::Kind_NullExpression:
- return "null";
- case Node::Kind_ThisExpression:
- return "this";
- case Node::Kind_PostIncrementExpression:
- return parseExpression(cast<PostIncrementExpression *>(expression)->base)+"++";
- case Node::Kind_PreIncrementExpression:
- return "++"+parseExpression(cast<PreIncrementExpression *>(expression)->expression);
- case Node::Kind_PostDecrementExpression:
- return parseExpression(cast<PostDecrementExpression *>(expression)->base)+"--";
- case Node::Kind_PreDecrementExpression:
- return "--"+parseExpression(cast<PreDecrementExpression *>(expression)->expression);
- case Node::Kind_NumericLiteral:
- return QString::number(cast<NumericLiteral *>(expression)->value);
- case Node::Kind_TemplateLiteral: {
- auto firstSrcLoc = cast<TemplateLiteral *>(expression)->firstSourceLocation();
- auto lastSrcLoc = cast<TemplateLiteral *>(expression)->lastSourceLocation();
- return m_engine->code().mid(static_cast<int>(firstSrcLoc.begin()),
- static_cast<int>(lastSrcLoc.end() - firstSrcLoc.begin()));
- }
- case Node::Kind_StringLiteral: {
- auto srcLoc = cast<StringLiteral *>(expression)->firstSourceLocation();
- return m_engine->code().mid(static_cast<int>(srcLoc.begin()),
- static_cast<int>(srcLoc.end() - srcLoc.begin()));
- }
- case Node::Kind_BinaryExpression: {
- auto *binExpr = expression->binaryExpressionCast();
- return parseExpression(binExpr->left) + " " + operatorToString(binExpr->op)
- + " " + parseExpression(binExpr->right);
- }
- case Node::Kind_CallExpression: {
- auto *callExpr = cast<CallExpression *>(expression);
-
- return parseExpression(callExpr->base) + (callExpr->isOptional ? "?." : "") + "(" + parseArgumentList(callExpr->arguments) + ")";
- }
- case Node::Kind_NewExpression:
- return "new "+parseExpression(cast<NewExpression *>(expression)->expression);
- case Node::Kind_NewMemberExpression: {
- auto *newMemberExpression = cast<NewMemberExpression *>(expression);
- return "new "+parseExpression(newMemberExpression->base)
- + "(" +parseArgumentList(newMemberExpression->arguments)+")";
- }
- case Node::Kind_DeleteExpression:
- return "delete " + parseExpression(cast<DeleteExpression *>(expression)->expression);
- case Node::Kind_VoidExpression:
- return "void " + parseExpression(cast<VoidExpression *>(expression)->expression);
- case Node::Kind_TypeOfExpression:
- return "typeof " + parseExpression(cast<TypeOfExpression *>(expression)->expression);
- case Node::Kind_UnaryPlusExpression:
- return "+" + parseExpression(cast<UnaryPlusExpression *>(expression)->expression);
- case Node::Kind_UnaryMinusExpression:
- return "-" + parseExpression(cast<UnaryMinusExpression *>(expression)->expression);
- case Node::Kind_NotExpression:
- return "!" + parseExpression(cast<NotExpression *>(expression)->expression);
- case Node::Kind_TildeExpression:
- return "~" + parseExpression(cast<TildeExpression *>(expression)->expression);
- case Node::Kind_ConditionalExpression: {
- auto *condExpr = cast<ConditionalExpression *>(expression);
-
- QString result = "";
-
- result += parseExpression(condExpr->expression) + " ? ";
- result += parseExpression(condExpr->ok) + " : ";
- result += parseExpression(condExpr->ko);
-
- return result;
- }
- case Node::Kind_YieldExpression: {
- auto *yieldExpr = cast<YieldExpression*>(expression);
-
- QString result = "yield";
-
- if (yieldExpr->isYieldStar)
- result += "*";
-
- if (yieldExpr->expression)
- result += " " + parseExpression(yieldExpr->expression);
-
- return result;
- }
- case Node::Kind_ObjectPattern: {
- auto *objectPattern = cast<ObjectPattern*>(expression);
-
- if (objectPattern->properties == nullptr)
- return "{}";
-
- QString result = "{\n";
-
- m_indentLevel++;
- result += parsePatternPropertyList(objectPattern->properties);
- m_indentLevel--;
-
- result += formatLine("}", false);
-
- return result;
- }
- case Node::Kind_Expression: {
- auto* expr = cast<Expression*>(expression);
- return parseExpression(expr->left)+", "+parseExpression(expr->right);
- }
- case Node::Kind_TypeExpression: {
- auto* type = cast<TypeExpression*>(expression);
- return parseType(type->m_type);
- }
- case Node::Kind_RegExpLiteral: {
- auto* regexpLiteral = cast<RegExpLiteral*>(expression);
- QString result = "/"+regexpLiteral->pattern+"/";
-
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Unicode)
- result += "u";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Global)
- result += "g";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Multiline)
- result += "m";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Sticky)
- result += "y";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
- result += "i";
-
- return result;
- }
- default:
- m_error = true;
- return "unknown_expression_"+QString::number(expression->kind);
- }
-}
-
-QString DumpAstVisitor::parseVariableDeclarationList(VariableDeclarationList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += parsePatternElement(item->declaration, (item == list))
- + (item->next != nullptr ? ", " : "");
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseCaseBlock(CaseBlock *block)
-{
- QString result = "{\n";
-
- for (auto *item = block->clauses; item != nullptr; item = item->next) {
- result += formatLine("case "+parseExpression(item->clause->expression)+":");
- m_indentLevel++;
- result += parseStatementList(item->clause->statements);
- m_indentLevel--;
- }
-
- if (block->defaultClause) {
- result += formatLine("default:");
- m_indentLevel++;
- result += parseStatementList(block->defaultClause->statements);
- m_indentLevel--;
- }
-
- result += formatLine("}", false);
-
- return result;
-}
-
-QString DumpAstVisitor::parseExportSpecifier(ExportSpecifier *specifier)
-{
- QString result = specifier->identifier.toString();
-
- if (!specifier->exportedIdentifier.isEmpty())
- result += " as " + specifier->exportedIdentifier;
-
- return result;
-}
-
-QString DumpAstVisitor::parseExportsList(ExportsList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += formatLine(parseExportSpecifier(item->exportSpecifier)
- + (item->next != nullptr ? "," : ""));
- }
-
- return result;
-}
-
-static bool needsSemicolon(int kind)
-{
- switch (kind) {
- case Node::Kind_ForStatement:
- case Node::Kind_ForEachStatement:
- case Node::Kind_IfStatement:
- case Node::Kind_SwitchStatement:
- case Node::Kind_WhileStatement:
- case Node::Kind_DoWhileStatement:
- case Node::Kind_TryStatement:
- case Node::Kind_WithStatement:
- return false;
- default:
- return true;
- }
-}
-
-QString DumpAstVisitor::parseBlock(Block *block, bool hasNext, bool allowBraceless)
-{
- bool hasOneLine =
- (block->statements != nullptr && block->statements->next == nullptr) && allowBraceless;
-
- QString result = hasOneLine ? "\n" : "{\n";
- m_indentLevel++;
- result += parseStatementList(block->statements);
- m_indentLevel--;
-
- if (hasNext)
- result += formatLine(hasOneLine ? "" : "} ", false);
-
- if (!hasNext && !hasOneLine)
- result += formatLine("}", false);
-
- if (block->statements) {
- m_blockNeededBraces |= !needsSemicolon(block->statements->statement->kind)
- || (block->statements->next != nullptr);
- } else {
- m_blockNeededBraces = true;
- }
-
- return result;
-}
-
-static bool endsWithSemicolon(const QStringView s)
-{
- return s.trimmed().endsWith(';');
-}
-
-QString DumpAstVisitor::parseStatement(Statement *statement, bool blockHasNext,
- bool blockAllowBraceless)
-{
- if (statement == nullptr)
- return "";
-
- switch (statement->kind)
- {
- case Node::Kind_EmptyStatement:
- return "";
- case Node::Kind_ExpressionStatement:
- return parseExpression(cast<ExpressionStatement *>(statement)->expression);
- case Node::Kind_VariableStatement:
- return parseVariableDeclarationList(cast<VariableStatement *>(statement)->declarations);
- case Node::Kind_ReturnStatement:
- return "return "+parseExpression(cast<ReturnStatement *>(statement)->expression);
- case Node::Kind_ContinueStatement:
- return "continue";
- case Node::Kind_BreakStatement:
- return "break";
- case Node::Kind_SwitchStatement: {
- auto *switchStatement = cast<SwitchStatement *>(statement);
-
- QString result = "switch ("+parseExpression(switchStatement->expression)+") ";
-
- result += parseCaseBlock(switchStatement->block);
-
- return result;
- }
- case Node::Kind_IfStatement: {
- auto *ifStatement = cast<IfStatement *>(statement);
-
- m_blockNeededBraces = !blockAllowBraceless;
-
- QString ifFalse = parseStatement(ifStatement->ko, false, true);
- QString ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), true);
-
- bool ifTrueBlock = ifStatement->ok->kind == Node::Kind_Block;
- bool ifFalseBlock = ifStatement->ko
- ? (ifStatement->ko->kind == Node::Kind_Block || ifStatement->ko->kind == Node::Kind_IfStatement)
- : false;
-
- if (m_blockNeededBraces) {
- ifFalse = parseStatement(ifStatement->ko, false, false);
- ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), false);
- }
-
- if (ifStatement->ok->kind != Node::Kind_Block && !endsWithSemicolon(ifTrue))
- ifTrue += ";";
-
- if (ifStatement->ko && ifStatement->ko->kind != Node::Kind_Block
- && ifStatement->ko->kind != Node::Kind_IfStatement && !endsWithSemicolon(ifFalse))
- ifFalse += ";";
-
- QString result = "if (" + parseExpression(ifStatement->expression) + ")";
-
- if (m_blockNeededBraces) {
- if (ifStatement->ok->kind != Node::Kind_Block) {
- QString result = "{\n";
- m_indentLevel++;
- result += formatLine(ifTrue);
- m_indentLevel--;
- result += formatLine("} ", false);
- ifTrue = result;
- ifTrueBlock = true;
- }
-
- if (ifStatement->ko && ifStatement->ko->kind != Node::Kind_Block && ifStatement->ko->kind != Node::Kind_IfStatement) {
- QString result = "{\n";
- m_indentLevel++;
- result += formatLine(ifFalse);
- m_indentLevel--;
- result += formatLine("} ", false);
- ifFalse = result;
- ifFalseBlock = true;
- }
- }
-
- if (ifTrueBlock) {
- result += " " + ifTrue;
- } else {
- result += "\n";
- m_indentLevel++;
- result += formatPartlyFormatedLines(ifTrue);
- m_indentLevel--;
- }
-
- if (!ifFalse.isEmpty())
- {
- if (ifTrueBlock)
- result += "else";
- else
- result += formatLine("else", false);
-
- if (ifFalseBlock) {
- // Blocks generate an extra newline that we don't want here.
- if (!m_blockNeededBraces && ifFalse.endsWith(QLatin1String("\n")))
- ifFalse.chop(1);
-
- result += " " + ifFalse;
- } else {
- result += "\n";
- m_indentLevel++;
- result += formatPartlyFormatedLines(ifFalse, false);
- m_indentLevel--;
- }
- }
-
- return result;
- }
- case Node::Kind_ForStatement: {
- auto *forStatement = cast<ForStatement *>(statement);
-
- QString expr = parseExpression(forStatement->expression);
- QString result = "for (";
-
- result += parseVariableDeclarationList(forStatement->declarations);
-
- result += "; ";
-
- result += parseExpression(forStatement->condition) + "; ";
- result += parseExpression(forStatement->expression)+")";
-
- const QString statement = parseStatement(forStatement->statement);
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_ForEachStatement: {
- auto *forEachStatement = cast<ForEachStatement *>(statement);
-
- QString result = "for (";
-
- PatternElement *patternElement = cast<PatternElement *>(forEachStatement->lhs);
-
- if (patternElement != nullptr)
- result += parsePatternElement(patternElement);
- else
- result += parseExpression(forEachStatement->lhs->expressionCast());
-
- switch (forEachStatement->type)
- {
- case ForEachType::In:
- result += " in ";
- break;
- case ForEachType::Of:
- result += " of ";
- break;
- }
-
- result += parseExpression(forEachStatement->expression) + ")";
-
- const QString statement = parseStatement(forEachStatement->statement);
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_WhileStatement: {
- auto *whileStatement = cast<WhileStatement *>(statement);
-
- m_blockNeededBraces = false;
-
- auto statement = parseStatement(whileStatement->statement, false, true);
-
- QString result = "while ("+parseExpression(whileStatement->expression) + ")";
-
- if (!statement.isEmpty())
- result += (m_blockNeededBraces ? " " : "") + statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_DoWhileStatement: {
- auto *doWhileStatement = cast<DoWhileStatement *>(statement);
- return "do " + parseBlock(cast<Block *>(doWhileStatement->statement), true, false)
- + "while (" + parseExpression(doWhileStatement->expression) + ")";
- }
- case Node::Kind_TryStatement: {
- auto *tryStatement = cast<TryStatement *>(statement);
-
- Catch *catchExpr = tryStatement->catchExpression;
- Finally *finallyExpr = tryStatement->finallyExpression;
-
- QString result;
-
- result += "try " + parseBlock(cast<Block *>(tryStatement->statement), true, false);
-
- result += "catch (" + parsePatternElement(catchExpr->patternElement, false) + ") "
- + parseBlock(cast<Block *>(catchExpr->statement), finallyExpr, false);
-
- if (finallyExpr) {
- result += "finally " + parseBlock(cast<Block *>(tryStatement->statement), false, false);
- }
-
- return result;
- }
- case Node::Kind_Block: {
- return parseBlock(cast<Block *>(statement), blockHasNext, blockAllowBraceless);
- }
- case Node::Kind_ThrowStatement:
- return "throw "+parseExpression(cast<ThrowStatement *>(statement)->expression);
- case Node::Kind_LabelledStatement: {
- auto *labelledStatement = cast<LabelledStatement *>(statement);
- QString result = labelledStatement->label+":\n";
- result += formatLine(parseStatement(labelledStatement->statement), false);
-
- return result;
- }
- case Node::Kind_WithStatement: {
- auto *withStatement = cast<WithStatement *>(statement);
- return "with (" + parseExpression(withStatement->expression) + ") "
- + parseStatement(withStatement->statement);
- }
- case Node::Kind_DebuggerStatement: {
- return "debugger";
- }
- case Node::Kind_ExportDeclaration:
- m_error = true;
- return "export_decl_unsupported";
- case Node::Kind_ImportDeclaration:
- m_error = true;
- return "import_decl_unsupported";
- default:
- m_error = true;
- return "unknown_statement_"+QString::number(statement->kind);
- }
-}
-
-QString DumpAstVisitor::parseStatementList(StatementList *list)
-{
- QString result = "";
-
- if (list == nullptr)
- return "";
-
- result += getOrphanedComments(list);
-
- for (auto *item = list; item != nullptr; item = item->next) {
- QString statement = parseStatement(item->statement->statementCast(), false, true);
- if (statement.isEmpty())
- continue;
-
- QString commentFront = getComment(item->statement, Comment::Location::Front);
- QString commentBackInline = getComment(item->statement, Comment::Location::Back_Inline);
-
- if (!commentFront.isEmpty())
- result += formatLine(commentFront);
-
- result += formatLine(statement + (needsSemicolon(item->statement->kind) ? ";" : "")
- + commentBackInline);
- }
-
- return result;
-}
-
-bool DumpAstVisitor::visit(UiPublicMember *node) {
-
- QString commentFront = getComment(node, Comment::Location::Front);
- QString commentBackInline = getComment(node, Comment::Location::Back_Inline);
-
- switch (node->type)
- {
- case UiPublicMember::Signal:
- if (scope().m_firstSignal) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstSignal = false;
- }
-
- addLine(commentFront);
- addLine("signal "+node->name.toString()+"("+parseUiParameterList(node->parameters) + ")"
- + commentBackInline);
- break;
- case UiPublicMember::Property: {
- if (scope().m_firstProperty) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstProperty = false;
- }
-
- const bool is_required = node->requiredToken.isValid();
- const bool is_default = node->defaultToken.isValid();
- const bool is_readonly = node->readonlyToken.isValid();
- const bool has_type_modifier = node->typeModifierToken.isValid();
-
- QString prefix = "";
- QString statement = parseStatement(node->statement);
-
- if (!statement.isEmpty())
- statement.prepend(": ");
-
- if (is_required)
- prefix += "required ";
-
- if (is_default)
- prefix += "default ";
-
- if (is_readonly)
- prefix += "readonly ";
-
- QString member_type = parseUiQualifiedId(node->memberType);
-
- if (has_type_modifier)
- member_type = node->typeModifier + "<" + member_type + ">";
-
- addLine(commentFront);
- if (is_readonly && statement.isEmpty()
- && scope().m_bindings.contains(node->name.toString())) {
- m_result += formatLine(prefix + "property " + member_type + " ", false);
-
- scope().m_pendingBinding = true;
- } else {
- addLine(prefix + "property " + member_type + " "
- + node->name+statement + commentBackInline);
- }
- break;
- }
- }
-
- return true;
-}
-
-QString DumpAstVisitor::generateIndent(int indentLevel) const
-{
- return QString(m_indentWidth * indentLevel, m_indentation == Indentation::Tabs ? '\t' : ' ');
-}
-
-QString DumpAstVisitor::formatLine(QString line, bool newline) const
-{
- QString result = generateIndent(m_indentLevel) + line;
- if (newline)
- result += "\n";
-
- return result;
-}
-
-QString DumpAstVisitor::formatPartlyFormatedLines(QString line, bool newline) const
-{
- QString result;
-
- const auto lines = QStringView { line }.split('\n');
- auto it = lines.cbegin();
- const auto endi = lines.cend();
- if (it != endi) {
- result += generateIndent(m_indentLevel) + *it;
- ++it;
- const QString addonIdent = generateIndent(1);
- for (; it != endi; ++it) {
- result += '\n';
- result += addonIdent + *it;
- }
- }
-
- if (newline)
- result += "\n";
-
- return result;
-}
-
-void DumpAstVisitor::addNewLine(bool always) {
- if (!always && m_result.endsWith("\n\n"))
- return;
-
- m_result += "\n";
-}
-
-void DumpAstVisitor::addLine(QString line) {
- // addLine does not support empty lines, use addNewLine(true) for that
- if (line.isEmpty())
- return;
-
- m_result += formatLine(line);
-}
-
-QHash<QString, UiObjectMember*> findBindings(UiObjectMemberList *list) {
- QHash<QString, UiObjectMember*> bindings;
-
- // This relies on RestructureASTVisitor having run beforehand
-
- for (auto *item = list; item != nullptr; item = item->next) {
- switch (item->member->kind) {
- case Node::Kind_UiPublicMember: {
- UiPublicMember *member = cast<UiPublicMember *>(item->member);
-
- if (member->type != UiPublicMember::Property)
- continue;
-
- bindings[member->name.toString()] = nullptr;
-
- break;
- }
- case Node::Kind_UiObjectBinding: {
- UiObjectBinding *binding = cast<UiObjectBinding *>(item->member);
-
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (bindings.contains(name))
- bindings[name] = binding;
-
- break;
- }
- case Node::Kind_UiArrayBinding: {
- UiArrayBinding *binding = cast<UiArrayBinding *>(item->member);
-
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (bindings.contains(name))
- bindings[name] = binding;
-
- break;
- }
- case Node::Kind_UiScriptBinding:
- // We can ignore UiScriptBindings since those are actually properly attached to the property
- break;
- }
- }
-
- return bindings;
-}
-
-bool DumpAstVisitor::visit(UiInlineComponent *node)
-{
- m_component_name = node->name.toString();
- return true;
-}
-
-bool DumpAstVisitor::visit(UiObjectDefinition *node) {
- if (scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
- addLine(getComment(node, Comment::Location::Front_Inline));
-
- QString component = "";
-
- if (!m_component_name.isEmpty()) {
- component = "component "+m_component_name+": ";
- m_component_name = "";
- }
-
- addLine(component + parseUiQualifiedId(node->qualifiedTypeNameId) + " {");
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiObjectDefinition *node) {
- m_indentLevel--;
-
- m_scope_properties.pop();
-
- bool need_comma = scope().m_inArrayBinding && scope().m_lastInArrayBinding != node;
-
- addLine(need_comma ? "}," : "}");
- addLine(getComment(node, Comment::Location::Back));
- if (!scope().m_inArrayBinding)
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiEnumDeclaration *node) {
-
- addNewLine();
-
- addLine(getComment(node, Comment::Location::Front));
- addLine("enum " + node->name + " {");
- m_indentLevel++;
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiEnumDeclaration *) {
- m_indentLevel--;
- addLine("}");
-
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiEnumMemberList *node) {
- for (auto *members = node; members != nullptr; members = members->next) {
-
- addLine(getListItemComment(members->memberToken, Comment::Location::Front));
-
- QString line = members->member.toString();
-
- if (members->valueToken.isValid())
- line += " = "+QString::number(members->value);
-
- if (members->next != nullptr)
- line += ",";
-
- line += getListItemComment(members->memberToken, Comment::Location::Back_Inline);
-
- addLine(line);
- }
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiScriptBinding *node) {
- if (scope().m_firstBinding) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- if (parseUiQualifiedId(node->qualifiedId) != "id")
- scope().m_firstBinding = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
-
- bool multiline = !needsSemicolon(node->statement->kind);
-
- if (multiline) {
- m_indentLevel++;
- }
-
- QString statement = parseStatement(node->statement);
-
- if (multiline) {
- statement = "{\n" + formatLine(statement);
- m_indentLevel--;
- statement += formatLine("}", false);
- }
-
- QString result = parseUiQualifiedId(node->qualifiedId) + ":";
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiArrayBinding *node) {
- if (!scope().m_pendingBinding && scope().m_firstBinding) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstBinding = false;
- }
-
- if (scope().m_pendingBinding) {
- m_result += parseUiQualifiedId(node->qualifiedId)+ ": [\n";
- scope().m_pendingBinding = false;
- } else {
- addLine(getComment(node, Comment::Location::Front));
- addLine(parseUiQualifiedId(node->qualifiedId)+ ": [");
- }
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_inArrayBinding = true;
-
- for (auto *item = node->members; item != nullptr; item = item->next) {
- if (item->next == nullptr)
- props.m_lastInArrayBinding = item->member;
- }
-
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiArrayBinding *) {
- m_indentLevel--;
- m_scope_properties.pop();
- addLine("]");
-}
-
-bool DumpAstVisitor::visit(FunctionDeclaration *node) {
- if (scope().m_firstFunction) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstFunction = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
-
- QString head = "function";
-
- if (node->isGenerator)
- head += "*";
-
- head += " "+node->name+"("+parseFormalParameterList(node->formals)+")";
-
- if (node->typeAnnotation != nullptr)
- head += " : " + parseType(node->typeAnnotation->type);
-
- head += " {";
-
- addLine(head);
- m_indentLevel++;
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(FunctionDeclaration *node)
-{
- m_result += parseStatementList(node->body);
- m_indentLevel--;
- addLine("}");
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiObjectBinding *node) {
- if (!scope().m_pendingBinding && scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- QString name = parseUiQualifiedId(node->qualifiedTypeNameId);
-
- QString result = name;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- if (node->hasOnToken)
- result += " on "+parseUiQualifiedId(node->qualifiedId);
- else
- result.prepend(parseUiQualifiedId(node->qualifiedId) + ": ");
-
- if (scope().m_pendingBinding) {
- m_result += result + " {\n";
-
- scope().m_pendingBinding = false;
- } else {
- addNewLine();
- addLine(getComment(node, Comment::Location::Front));
- addLine(getComment(node, Comment::Location::Front_Inline));
- addLine(result + " {");
- }
-
- m_indentLevel++;
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiObjectBinding *node) {
- m_indentLevel--;
- m_scope_properties.pop();
-
- addLine("}");
- addLine(getComment(node, Comment::Location::Back));
-
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiImport *node) {
- scope().m_firstOfAll = false;
-
- addLine(getComment(node, Comment::Location::Front));
-
- QString result = "import ";
-
- if (!node->fileName.isEmpty())
- result += escapeString(node->fileName.toString());
- else
- result += parseUiQualifiedId(node->importUri);
-
- if (node->version) {
- const auto version = node->version->version;
-
- if (version.hasMajorVersion()) {
- result += " " + QString::number(version.majorVersion());
-
- if (version.hasMinorVersion())
- result += "." + QString::number(version.minorVersion());
- }
- }
-
- if (node->asToken.isValid()) {
- result +=" as " + node->importId;
- }
-
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiPragma *node) {
- scope().m_firstOfAll = false;
-
- addLine(getComment(node, Comment::Location::Front));
- QString result = "pragma "+ node->name;
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiAnnotation *node)
-{
- if (scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
- addLine(QLatin1String("@") + parseUiQualifiedId(node->qualifiedTypeNameId) + " {");
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiAnnotation *node) {
- m_indentLevel--;
-
- m_scope_properties.pop();
-
- addLine("}");
- addLine(getComment(node, Comment::Location::Back));
-}
diff --git a/tools/qmlformat/dumpastvisitor.h b/tools/qmlformat/dumpastvisitor.h
deleted file mode 100644
index 7d37a4b90f..0000000000
--- a/tools/qmlformat/dumpastvisitor.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef DUMPAST_H
-#define DUMPAST_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-
-#include <QHash>
-#include <QStack>
-
-#include "commentastvisitor.h"
-
-class DumpAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- enum Indentation { Tabs, Spaces };
-
- DumpAstVisitor(QQmlJS::Engine *engine, QQmlJS::AST::Node *rootNode, CommentAstVisitor *comment,
- int indentWidth, Indentation indentation);
-
- QString toString() const { return m_result; }
-
- bool preVisit(QQmlJS::AST::Node *) override;
-
- bool visit(QQmlJS::AST::UiScriptBinding *node) override;
-
- bool visit(QQmlJS::AST::UiArrayBinding *node) override;
- void endVisit(QQmlJS::AST::UiArrayBinding *node) override;
-
- bool visit(QQmlJS::AST::UiObjectBinding *node) override;
- void endVisit(QQmlJS::AST::UiObjectBinding *node) override;
-
- bool visit(QQmlJS::AST::FunctionDeclaration *node) override;
- void endVisit(QQmlJS::AST::FunctionDeclaration *node) override;
-
- bool visit(QQmlJS::AST::UiInlineComponent *node) override;
-
- bool visit(QQmlJS::AST::UiObjectDefinition *node) override;
- void endVisit(QQmlJS::AST::UiObjectDefinition *node) override;
-
- bool visit(QQmlJS::AST::UiEnumDeclaration *node) override;
- void endVisit(QQmlJS::AST::UiEnumDeclaration *node) override;
-
- bool visit(QQmlJS::AST::UiEnumMemberList *node) override;
- bool visit(QQmlJS::AST::UiPublicMember *node) override;
- bool visit(QQmlJS::AST::UiImport *node) override;
- bool visit(QQmlJS::AST::UiPragma *node) override;
-
- bool visit(QQmlJS::AST::UiAnnotation *node) override;
- void endVisit(QQmlJS::AST::UiAnnotation *node) override;
-
- void throwRecursionDepthError() override {}
-
- bool error() const { return m_error; }
-private:
- struct ScopeProperties {
- bool m_firstOfAll = true;
- bool m_firstSignal = true;
- bool m_firstProperty = true;
- bool m_firstBinding = true;
- bool m_firstObject = true;
- bool m_firstFunction = true;
- bool m_inArrayBinding = false;
- bool m_pendingBinding = false;
-
- QQmlJS::AST::UiObjectMember* m_lastInArrayBinding = nullptr;
- QHash<QString, QQmlJS::AST::UiObjectMember*> m_bindings;
- };
-
- QString generateIndent(int indentLevel) const;
- QString formatLine(QString line, bool newline = true) const;
- QString formatPartlyFormatedLines(QString line, bool newline = true) const;
-
- QString formatComment(const Comment &comment) const;
-
- QString getComment(QQmlJS::AST::Node *node, Comment::Location location) const;
- QString getListItemComment(QQmlJS::SourceLocation srcLocation, Comment::Location location) const;
-
- void addNewLine(bool always = false);
- void addLine(QString line);
-
- QString getOrphanedComments(QQmlJS::AST::Node *node) const;
-
- QString parseStatement(QQmlJS::AST::Statement *statement, bool blockHasNext = false,
- bool blockAllowBraceless = false);
- QString parseStatementList(QQmlJS::AST::StatementList *list);
-
- QString parseExpression(QQmlJS::AST::ExpressionNode *expression);
-
- QString parsePatternElement(QQmlJS::AST::PatternElement *element, bool scope = true);
- QString parsePatternElementList(QQmlJS::AST::PatternElementList *element);
-
- QString parsePatternProperty(QQmlJS::AST::PatternProperty *property);
- QString parsePatternPropertyList(QQmlJS::AST::PatternPropertyList *list);
-
- QString parseArgumentList(QQmlJS::AST::ArgumentList *list);
-
- QString parseUiParameterList(QQmlJS::AST::UiParameterList *list);
-
- QString parseVariableDeclarationList(QQmlJS::AST::VariableDeclarationList *list);
-
- QString parseCaseBlock(QQmlJS::AST::CaseBlock *block);
- QString parseBlock(QQmlJS::AST::Block *block, bool hasNext, bool allowBraceless);
-
- QString parseExportsList(QQmlJS::AST::ExportsList *list);
- QString parseExportSpecifier(QQmlJS::AST::ExportSpecifier *specifier);
-
- QString parseFormalParameterList(QQmlJS::AST::FormalParameterList *list);
-
- QString parseType(QQmlJS::AST::Type *type);
-
- QString parseFunctionExpression(QQmlJS::AST::FunctionExpression *expression, bool omitFunction = false);
-
- ScopeProperties& scope() { return m_scope_properties.top(); }
-
- int m_indentLevel = 0;
-
- bool m_error = false;
- bool m_blockNeededBraces = false;
-
- QStack<ScopeProperties> m_scope_properties;
-
- QString m_result = "";
- QString m_component_name = "";
- QQmlJS::Engine *m_engine;
- CommentAstVisitor *m_comment;
- int m_indentWidth;
- Indentation m_indentation;
-};
-
-#endif // DUMPAST_H
diff --git a/tools/qmlformat/main.cpp b/tools/qmlformat/qmlformat.cpp
index 3f11ce257a..7f7cdfbb24 100644
--- a/tools/qmlformat/main.cpp
+++ b/tools/qmlformat/qmlformat.cpp
@@ -35,14 +35,16 @@
#include <QtQml/private/qqmljsengine_p.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
#include <QtQml/private/qqmljsast_p.h>
+#include <QtQmlDom/private/qqmldomitem_p.h>
+#include <QtQmlDom/private/qqmldomexternalitems_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+#include <QtQmlDom/private/qqmldomoutwriter_p.h>
#if QT_CONFIG(commandlineparser)
-#include <QCommandLineParser>
+# include <QCommandLineParser>
#endif
-#include "commentastvisitor.h"
-#include "dumpastvisitor.h"
-#include "restructureastvisitor.h"
+using namespace QQmlJS::Dom;
struct Options
{
@@ -51,6 +53,7 @@ struct Options
bool force = false;
bool tabs = false;
bool valid = false;
+ bool normalize = false;
int indentWidth = 4;
bool indentWidthSet = false;
@@ -63,121 +66,94 @@ struct Options
bool parseFile(const QString &filename, const Options &options)
{
- QFile file(filename);
-
- if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
- qWarning().noquote() << "Failed to open" << filename << "for reading.";
- return false;
- }
-
- QString code = QString::fromUtf8(file.readAll());
- file.close();
-
- QQmlJS::Engine engine;
- QQmlJS::Lexer lexer(&engine);
-
- lexer.setCode(code, 1, true);
- QQmlJS::Parser parser(&engine);
-
- bool success = parser.parse();
-
- if (!success) {
- const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
- .arg(filename).arg(m.loc.startLine).arg(m.message);
- }
-
+ DomItem env =
+ DomEnvironment::create(QStringList(),
+ QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
+ | QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
+ DomItem tFile; // place where to store the loaded file
+ env.loadFile(
+ filename, QString(),
+ [&tFile](Path, const DomItem &, const DomItem &newIt) {
+ tFile = newIt; // callback called when everything is loaded that receives the loaded
+ // external file pair (path, oldValue, newValue)
+ },
+ LoadOption::DefaultLoad);
+ env.loadPendingDependencies();
+ DomItem qmlFile = tFile.fileObject();
+ std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>();
+ if (!qmlFilePtr || !qmlFilePtr->isValid()) {
+ qmlFile.iterateErrors(
+ [](DomItem, ErrorMessage msg) {
+ errorToQDebug(msg);
+ return true;
+ },
+ true);
qWarning().noquote() << "Failed to parse" << filename;
return false;
}
- // Try to attach comments to AST nodes
- CommentAstVisitor comment(&engine, parser.rootNode());
-
- if (options.verbose)
- qWarning().noquote() << comment.attachedComments().size() << "comment(s) attached.";
-
- if (options.verbose) {
- int orphaned = 0;
-
- for (const auto& orphanList : comment.orphanComments().values())
- orphaned += orphanList.size();
-
- qWarning().noquote() << orphaned << "comments are orphans.";
- }
-
- // Do the actual restructuring
- RestructureAstVisitor restructure(parser.rootNode());
-
// Turn AST back into source code
if (options.verbose)
qWarning().noquote() << "Dumping" << filename;
- DumpAstVisitor dump(
- &engine, parser.rootNode(), &comment, options.tabs ? 1 : options.indentWidth,
- options.tabs ? DumpAstVisitor::Indentation::Tabs : DumpAstVisitor::Indentation::Spaces);
-
- QString dumpCode = dump.toString();
-
- lexer.setCode(dumpCode, 1, true);
-
- bool dumpSuccess = parser.parse();
-
- if (!dumpSuccess) {
- if (options.verbose) {
- const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning().noquote() << QString::fromLatin1("<formatted>:%2 : %3")
- .arg(m.loc.startLine).arg(m.message);
+ LineWriterOptions lwOptions;
+ lwOptions.formatOptions.indentSize = options.indentWidth;
+ lwOptions.formatOptions.useTabs = options.tabs;
+ lwOptions.updateOptions = LineWriterOptions::Update::None;
+ if (options.newline == "native") {
+ // find out current line endings...
+ QStringView code = qmlFilePtr->code();
+ int newlineIndex = code.indexOf(QChar(u'\n'));
+ int crIndex = code.indexOf(QChar(u'\r'));
+ if (newlineIndex >= 0) {
+ if (crIndex >= 0) {
+ if (crIndex + 1 == newlineIndex)
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Windows;
+ else
+ qWarning().noquote() << "Invalid line ending in file, using default";
+
+ } else {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Unix;
}
+ } else if (crIndex >= 0) {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::OldMacOs;
+ } else {
+ qWarning().noquote() << "Unknown line ending in file, using default";
}
-
- qWarning().noquote() << "Failed to parse formatted code.";
+ } else if (options.newline == "macos") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::OldMacOs;
+ } else if (options.newline == "windows") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Windows;
+ } else if (options.newline == "unix") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Unix;
+ } else {
+ qWarning().noquote() << "Unknown line ending type" << options.newline;
+ return false;
}
- if (dump.error() || !dumpSuccess) {
- if (options.force) {
- qWarning().noquote() << "An error has occurred. The output may not be reliable.";
- } else {
- qWarning().noquote() << "An error has occurred. Aborting.";
- return false;
- }
- }
-
- const bool native = options.newline == "native";
-
- if (!native) {
- if (options.newline == "macos") {
- dumpCode = dumpCode.replace("\n", "\r");
- } else if (options.newline == "windows") {
- dumpCode = dumpCode.replace("\n", "\r\n");
- } else if (options.newline == "unix") {
- // Nothing needs to be done for unix line-endings
- } else {
- qWarning().noquote() << "Unknown line ending type" << options.newline;
- return false;
- }
- }
-
- if (options.inplace) {
- if (options.verbose)
- qWarning().noquote() << "Writing to file" << filename;
-
- if (!file.open(native ? QIODevice::WriteOnly | QIODevice::Text : QIODevice::WriteOnly)) {
- qWarning().noquote() << "Failed to open" << filename << "for writing";
- return false;
- }
-
- file.write(dumpCode.toUtf8());
- file.close();
- } else {
- QFile out;
- out.open(stdout, QIODevice::WriteOnly);
- out.write(dumpCode.toUtf8());
- }
-
- return true;
+ if (options.normalize)
+ lwOptions.attributesSequence = LineWriterOptions::AttributesSequence::Normalize;
+ else
+ lwOptions.attributesSequence = LineWriterOptions::AttributesSequence::Preserve;
+ WriteOutChecks checks = WriteOutCheck::Default;
+ if (options.force || qmlFilePtr->code().size() > 32000)
+ checks = WriteOutCheck::None;
+
+ MutableDomItem res;
+ if (options.inplace) {
+ if (options.verbose)
+ qWarning().noquote() << "Writing to file" << filename;
+ FileWriter fw;
+ res = qmlFile.writeOut(filename, 2, lwOptions, &fw, checks);
+ } else {
+ QFile out;
+ out.open(stdout, QIODevice::WriteOnly);
+ LineWriter lw([&out](QStringView s) { out.write(s.toUtf8()); }, filename, lwOptions);
+ OutWriter ow(lw);
+ res = qmlFile.writeOutForFile(ow, checks);
+ ow.flush();
+ }
+ return bool(res);
}
Options buildCommandLineOptions(const QCoreApplication &app)
@@ -188,14 +164,16 @@ Options buildCommandLineOptions(const QCoreApplication &app)
parser.addHelpOption();
parser.addVersionOption();
- parser.addOption(QCommandLineOption({"V", "verbose"},
- QStringLiteral("Verbose mode. Outputs more detailed information.")));
+ parser.addOption(
+ QCommandLineOption({ "V", "verbose" },
+ QStringLiteral("Verbose mode. Outputs more detailed information.")));
- parser.addOption(QCommandLineOption({"i", "inplace"},
- QStringLiteral("Edit file in-place instead of outputting to stdout.")));
+ parser.addOption(QCommandLineOption(
+ { "i", "inplace" },
+ QStringLiteral("Edit file in-place instead of outputting to stdout.")));
- parser.addOption(QCommandLineOption({"f", "force"},
- QStringLiteral("Continue even if an error has occurred.")));
+ parser.addOption(QCommandLineOption({ "f", "force" },
+ QStringLiteral("Continue even if an error has occurred.")));
parser.addOption(
QCommandLineOption({ "t", "tabs" }, QStringLiteral("Use tabs instead of spaces.")));
@@ -204,12 +182,17 @@ Options buildCommandLineOptions(const QCoreApplication &app)
QStringLiteral("How many spaces are used when indenting."),
"width", "4"));
+ parser.addOption(QCommandLineOption({ "n", "normalize" },
+ QStringLiteral("Reorders the attributes of the objects "
+ "according to the QML Coding Guidelines.")));
+
parser.addOption(QCommandLineOption(
{ "F", "files" }, QStringLiteral("Format all files listed in file, in-place"), "file"));
- parser.addOption(QCommandLineOption({"l", "newline"},
- QStringLiteral("Override the new line format to use (native macos unix windows)."),
- "newline", "native"));
+ parser.addOption(QCommandLineOption(
+ { "l", "newline" },
+ QStringLiteral("Override the new line format to use (native macos unix windows)."),
+ "newline", "native"));
parser.addPositionalArgument("filenames", "files to be processed by qmlformat");
@@ -224,7 +207,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
}
QStringList files;
- if (parser.isSet("files")) {
+ if (!parser.value("files").isEmpty()) {
QFile file(parser.value("files"));
file.open(QIODevice::Text | QIODevice::ReadOnly);
if (file.isOpen()) {
@@ -245,6 +228,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
options.inplace = parser.isSet("inplace");
options.force = parser.isSet("force");
options.tabs = parser.isSet("tabs");
+ options.normalize = parser.isSet("normalize");
options.valid = true;
options.indentWidth = indentWidth;
diff --git a/tools/qmlformat/restructureastvisitor.cpp b/tools/qmlformat/restructureastvisitor.cpp
deleted file mode 100644
index 18021a0a2a..0000000000
--- a/tools/qmlformat/restructureastvisitor.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "restructureastvisitor.h"
-
-#include <QList>
-
-using namespace QQmlJS::AST;
-
-RestructureAstVisitor::RestructureAstVisitor(Node *rootNode)
-{
- rootNode->accept(this);
-}
-
-template<typename T>
-static QList<T *> findKind(UiObjectMemberList *list)
-{
- QList<T *> members;
- for (auto *item = list; item != nullptr; item = item->next) {
- if (cast<T *>(item->member) != nullptr)
- members.append(cast<T *>(item->member));
- }
-
- return members;
-}
-
-template<typename T>
-static QList<T *> findKind(UiHeaderItemList *list)
-{
- QList<T *> members;
- for (auto *item = list; item != nullptr; item = item->next) {
- if (cast<T *>(item->headerItem) != nullptr)
- members.append(cast<T *>(item->headerItem));
- }
-
- return members;
-}
-
-static QString parseUiQualifiedId(UiQualifiedId *id)
-{
- QString name = id->name.toString();
- for (auto *item = id->next; item != nullptr; item = item->next) {
- name += "." + item->name;
- }
-
- return name;
-}
-
-void RestructureAstVisitor::endVisit(UiObjectMemberList *node)
-{
- QList<UiObjectMember*> correctOrder;
-
- QList<UiScriptBinding*> largeScriptBinding;
-
- UiObjectMember *states = nullptr;
- UiObjectMember *transitions = nullptr;
-
- auto enumDeclarations = findKind<UiEnumDeclaration>(node);
- auto scriptBindings = findKind<UiScriptBinding>(node);
- auto arrayBindings = findKind<UiArrayBinding>(node);
- auto publicMembers = findKind<UiPublicMember>(node);
- auto sourceElements = findKind<UiSourceElement>(node);
- auto objectDefinitions = findKind<UiObjectDefinition>(node);
-
- // Look for transitions and states
- for (auto *binding : findKind<UiObjectBinding>(node)) {
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (name == "transitions")
- transitions = binding;
- else if (name == "states")
- states = binding;
- }
-
- for (auto it = arrayBindings.begin(); it != arrayBindings.end();) {
- const QString name = parseUiQualifiedId((*it)->qualifiedId);
-
- if (name == "transitions") {
- transitions = *it;
- it = arrayBindings.erase(it);
- } else if (name == "states") {
- states = *it;
- it = arrayBindings.erase(it);
- } else {
- it++;
- }
- }
-
- // Find large script bindings
- for (auto it = scriptBindings.begin(); it != scriptBindings.end();) {
- // A binding is considered large if it uses a block
- if ((*it)->statement->kind != Node::Kind_Block) {
- it++;
- continue;
- }
-
- largeScriptBinding.push_back(*it);
- it = scriptBindings.erase(it);
- }
-
- // This structure is based on https://doc.qt.io/qt-5/qml-codingconventions.html
-
- // 1st id
- for (auto *binding : scriptBindings) {
- if (parseUiQualifiedId(binding->qualifiedId) == "id") {
- correctOrder.append(binding);
-
- scriptBindings.removeOne(binding);
- break;
- }
- }
-
- // 2nd enums
- for (auto *enumDeclaration : enumDeclarations)
- correctOrder.append(enumDeclaration);
-
- // 3rd property declarations
- for (auto *publicMember : publicMembers) {
- if (publicMember->type != UiPublicMember::Property)
- continue;
-
- correctOrder.append(publicMember);
- }
-
- // 4th signals
- for (auto *publicMember : publicMembers) {
- if (publicMember->type != UiPublicMember::Signal)
- continue;
-
- correctOrder.append(publicMember);
- }
-
- // 5th functions
- for (auto *source : sourceElements)
- correctOrder.append(source);
-
- // 6th properties
- // small script bindings...
- for (auto *binding : scriptBindings)
- correctOrder.append(binding);
-
- // ...then large ones
- for (auto *binding : largeScriptBinding)
- correctOrder.append(binding);
-
- for (auto *binding : arrayBindings)
- correctOrder.append(binding);
-
- // 7th child objects
- for (auto *objectDefinition : objectDefinitions)
- correctOrder.append(objectDefinition);
-
- // 8th all the rest
- for (auto *item = node; item != nullptr; item = item->next) {
- if (!correctOrder.contains(item->member))
- correctOrder.append(item->member);
- }
-
- // 9th states and transitions
- if (states != nullptr)
- correctOrder.append(states);
-
- if (transitions != nullptr)
- correctOrder.append(transitions);
-
- // Rebuild member list from correctOrder
- for (auto *item = node; item != nullptr; item = item->next) {
- item->member = correctOrder.front();
- correctOrder.pop_front();
- }
-}
diff --git a/tools/qmlformat/restructureastvisitor.h b/tools/qmlformat/restructureastvisitor.h
deleted file mode 100644
index 4d1cb7e643..0000000000
--- a/tools/qmlformat/restructureastvisitor.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef RESTRUCTUREASTVISITOR_H
-#define RESTRUCTUREASTVISITOR_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-
-class RestructureAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- RestructureAstVisitor(QQmlJS::AST::Node *rootNode);
-
- void throwRecursionDepthError() override {}
-
- void endVisit(QQmlJS::AST::UiObjectMemberList *node) override;
-};
-
-#endif // RESTRUCTUREASTVISITOR_H