|  | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE.md file. | 
|  |  | 
|  | // @dart = 2.9 | 
|  |  | 
|  | import "dart:convert"; | 
|  |  | 
|  | import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart' | 
|  | show ScannerConfiguration; | 
|  |  | 
|  | import "package:front_end/src/fasta/util/textual_outline.dart" | 
|  | show textualOutline; | 
|  |  | 
|  | const ScannerConfiguration scannerConfiguration = | 
|  | const ScannerConfiguration(enableExtensionMethods: true); | 
|  |  | 
|  | void main() { | 
|  | // Doesn't sort if not asked to perform modelling. | 
|  | String result = textualOutline(utf8.encode(""" | 
|  | b() { print("hello"); } | 
|  | a() { print("hello"); } | 
|  | """), scannerConfiguration, throwOnUnexpected: true, performModelling: false); | 
|  | if (result != | 
|  | """ | 
|  | b() {} | 
|  |  | 
|  | a() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Sort if asked to perform modelling. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | b() { print("hello"); } | 
|  | a() { print("hello"); } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | a() {} | 
|  |  | 
|  | b() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Content between braces or not doesn't make any difference. | 
|  | // Procedure without content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | a() {} | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | a() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Procedure with content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | a() { | 
|  | // Whatever | 
|  | } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | a() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Class without content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | class B {} | 
|  | class A {} | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | class A {} | 
|  |  | 
|  | class B {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Class without real content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | class A { | 
|  | // Whatever | 
|  | } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | class A {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Has space between entries. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | @a | 
|  | @A(2) | 
|  | typedef void F1(); | 
|  |  | 
|  | @a | 
|  | @A(3) | 
|  | int f1, f2; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | @a | 
|  | @A(3) | 
|  | int f1, f2; | 
|  |  | 
|  | @a | 
|  | @A(2) | 
|  | typedef void F1();""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Has space between entries. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | @a | 
|  | @A(2) | 
|  | typedef void F1(); | 
|  | @a | 
|  | @A(3) | 
|  | int f1, f2; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | @a | 
|  | @A(3) | 
|  | int f1, f2; | 
|  |  | 
|  | @a | 
|  | @A(2) | 
|  | typedef void F1();""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Knows about and can sort named mixin applications. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | class C<T> = Object with A<Function(T)>; | 
|  | class B<T> = Object with A<Function(T)>; | 
|  | class A<T> {} | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | class A<T> {} | 
|  |  | 
|  | class B<T> = Object with A<Function(T)>; | 
|  |  | 
|  | class C<T> = Object with A<Function(T)>;""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Knows about and can sort imports, but doesn't mix them with the other | 
|  | // content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | import "foo.dart" show B, | 
|  | A, | 
|  | C; | 
|  | import "bar.dart"; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | import "baz.dart"; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | import "bar.dart"; | 
|  | import "foo.dart" show A, B, C; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | import "baz.dart";""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Knows about and can sort exports, but doesn't mix them with the other | 
|  | // content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | export "foo.dart" show B, | 
|  | A, | 
|  | C; | 
|  | export "bar.dart"; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | export "baz.dart"; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | export "bar.dart"; | 
|  | export "foo.dart" show A, B, C; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | export "baz.dart";""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Knows about and can sort imports and exports, | 
|  | // but doesn't mix them with the other content. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | export "foo.dart" show B, | 
|  | A, | 
|  | C; | 
|  | import "foo.dart" show B, | 
|  | A, | 
|  | C; | 
|  | export "bar.dart"; | 
|  | import "bar.dart"; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | export "baz.dart"; | 
|  | import "baz.dart"; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | export "bar.dart"; | 
|  | export "foo.dart" show A, B, C; | 
|  | import "bar.dart"; | 
|  | import "foo.dart" show A, B, C; | 
|  |  | 
|  | main() {} | 
|  |  | 
|  | export "baz.dart"; | 
|  | import "baz.dart";""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Knows about library, part and part of but they cannot be sorted. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | part "foo.dart"; | 
|  | part of "foo.dart"; | 
|  | library foo; | 
|  |  | 
|  | bar() { | 
|  | // whatever | 
|  | } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | part "foo.dart"; | 
|  |  | 
|  | part of "foo.dart"; | 
|  |  | 
|  | library foo; | 
|  |  | 
|  | bar() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Ending metadata (not associated with anything) is still present. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | @Object2() | 
|  | foo() { | 
|  | // hello | 
|  | } | 
|  |  | 
|  | @Object1() | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | @Object2() | 
|  | foo() {} | 
|  |  | 
|  | @Object1()""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Sorting of question mark types. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | class Class1 { | 
|  | Class1? get nullable1 => property1; | 
|  | Class2? get property => null; | 
|  | Class1 get nonNullable1 => property1; | 
|  | Class2 get property1 => new Class1(); | 
|  | } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | class Class1 { | 
|  | Class1? get nullable1 => property1; | 
|  | Class1 get nonNullable1 => property1; | 
|  | Class2? get property => null; | 
|  | Class2 get property1 => new Class1(); | 
|  | }""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Sorting of various classes with numbers and less than. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | class C2<V> = Super<V> with Mixin<V>; | 
|  | class C<V> extends Super<V> with Mixin<V> {} | 
|  | class D extends Super with Mixin {} | 
|  | class D2 = Super with Mixin; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | class C<V> extends Super<V> with Mixin<V> {} | 
|  |  | 
|  | class C2<V> = Super<V> with Mixin<V>; | 
|  |  | 
|  | class D extends Super with Mixin {} | 
|  |  | 
|  | class D2 = Super with Mixin;""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Metadata on imports / exports. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | @Object1 | 
|  | export "a3.dart"; | 
|  | @Object2 | 
|  | import "a2.dart"; | 
|  | @Object3 | 
|  | export "a1.dart"; | 
|  | @Object4 | 
|  | import "a0.dart"; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | @Object3 | 
|  | export "a1.dart"; | 
|  |  | 
|  | @Object1 | 
|  | export "a3.dart"; | 
|  |  | 
|  | @Object4 | 
|  | import "a0.dart"; | 
|  |  | 
|  | @Object2 | 
|  | import "a2.dart";""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Doesn't crash on illegal import/export. | 
|  | // Note that for now a bad import becomes unknown as it has | 
|  | // 'advanced recovery' via "handleRecoverImport" whereas exports enforce the | 
|  | // structure more. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | // bad line. | 
|  | import "a0.dart" show | 
|  | // ok line | 
|  | import "a1.dart" show foo; | 
|  | // bad line. | 
|  | export "a2.dart" show | 
|  | // ok line | 
|  | export "a3.dart" show foo; | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true, | 
|  | returnNullOnError: false); | 
|  | if (result != | 
|  | """ | 
|  | ---- unknown chunk starts ---- | 
|  | import "a0.dart" show ; | 
|  | ---- unknown chunk ends ---- | 
|  |  | 
|  | export "a2.dart" show ; | 
|  | export "a3.dart" show foo; | 
|  | import "a1.dart" show foo;""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  |  | 
|  | // Enums. | 
|  | result = textualOutline(utf8.encode(""" | 
|  | library test; | 
|  |  | 
|  | enum E { v1 } | 
|  | final x = E.v1; | 
|  |  | 
|  | main() { | 
|  | x; | 
|  | } | 
|  | """), scannerConfiguration, | 
|  | throwOnUnexpected: true, | 
|  | performModelling: true, | 
|  | addMarkerForUnknownForTest: true); | 
|  | if (result != | 
|  | """ | 
|  | library test; | 
|  |  | 
|  | enum E { v1 } | 
|  |  | 
|  | final x = E.v1; | 
|  |  | 
|  | main() {}""") { | 
|  | throw "Unexpected result: $result"; | 
|  | } | 
|  | } |