blob: fd50c3f96669379eb533231ea75b0eeaff8f9865 [file] [log] [blame]
// 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.
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";
}
}