Version 2.18.0-92.0.dev
Merge commit 'b488bd1a75940c43ee236bfe05b562b42c63eb05' into 'dev'
diff --git a/pkg/analyzer/test/src/dart/resolution/comment_test.dart b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
index f3e4408..dba14af 100644
--- a/pkg/analyzer/test/src/dart/resolution/comment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
@@ -31,8 +31,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.named]'), findElement.class_('A'));
- assertElement(findNode.simple('named]'), findElement.constructor('named'));
+ assertResolvedNodeText(findNode.commentReference('A.named]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: named
+ staticElement: self::@class::A::@constructor::named
+ staticType: null
+ staticElement: self::@class::A::@constructor::named
+ staticType: null
+''');
}
test_class_constructor_unnamedViaNew() async {
@@ -45,8 +58,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.new'), findElement.class_('A'));
- assertElement(findNode.simple('new]'), findElement.unnamedConstructor('A'));
+ assertResolvedNodeText(findNode.commentReference('A.new]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: new
+ staticElement: self::@class::A::@constructor::•
+ staticType: null
+ staticElement: self::@class::A::@constructor::•
+ staticType: null
+''');
}
test_class_instanceGetter() async {
@@ -59,8 +85,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+''');
}
test_class_instanceMethod() async {
@@ -73,8 +112,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+''');
}
test_class_instanceSetter() async {
@@ -87,8 +139,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+''');
}
test_class_invalid_ambiguousExtension() async {
@@ -139,8 +204,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+''');
}
test_class_staticMethod() async {
@@ -153,8 +231,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+''');
}
test_class_staticSetter() async {
@@ -167,8 +258,21 @@
void f() {}
''');
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+''');
}
test_extension_instanceGetter() async {
@@ -181,8 +285,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+''');
}
test_extension_instanceMethod() async {
@@ -195,8 +312,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+''');
}
test_extension_instanceSetter() async {
@@ -209,8 +339,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+''');
}
test_extension_staticGetter() async {
@@ -223,8 +366,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+''');
}
test_extension_staticMethod() async {
@@ -237,8 +393,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+''');
}
test_extension_staticSetter() async {
@@ -251,8 +420,21 @@
void f() {}
''');
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+''');
}
}
@@ -270,10 +452,29 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.named'), findElement.prefix('self'));
- assertElement(findNode.simple('A.named]'), findElement.class_('A'));
// TODO(srawlins): Set the type of named, and test it, here and below.
- assertElement(findNode.simple('named]'), findElement.constructor('named'));
+ assertResolvedNodeText(findNode.commentReference('A.named]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: named
+ staticElement: self::@class::A::@constructor::named
+ staticType: null
+ staticType: null
+''');
}
test_class_constructor_unnamedViaNew() async {
@@ -287,9 +488,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.new'), findElement.prefix('self'));
- assertElement(findNode.simple('A.new'), findElement.class_('A'));
- assertElement(findNode.simple('new]'), findElement.unnamedConstructor('A'));
+ assertResolvedNodeText(findNode.commentReference('A.new]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: new
+ staticElement: self::@class::A::@constructor::•
+ staticType: null
+ staticType: null
+''');
}
test_class_instanceGetter() async {
@@ -303,9 +523,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+ staticType: null
+''');
}
test_class_instanceMethod() async {
@@ -319,9 +558,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+ staticType: null
+''');
}
test_class_instanceSetter() async {
@@ -335,9 +593,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+ staticType: null
+''');
}
test_class_staticGetter() async {
@@ -351,9 +628,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@getter::foo
+ staticType: null
+ staticType: null
+''');
}
test_class_staticMethod() async {
@@ -367,9 +663,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+ staticType: null
+''');
}
test_class_staticSetter() async {
@@ -383,9 +698,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.A.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('A.foo'), findElement.class_('A'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('A.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ staticElement: self::@class::A
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@setter::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_instanceGetter() async {
@@ -399,9 +733,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_instanceMethod() async {
@@ -415,9 +768,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_instanceSetter() async {
@@ -431,9 +803,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_staticGetter() async {
@@ -447,9 +838,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.getter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@getter::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_staticMethod() async {
@@ -463,9 +873,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.method('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@method::foo
+ staticType: null
+ staticType: null
+''');
}
test_extension_staticSetter() async {
@@ -479,9 +908,28 @@
void f() {}
''');
- assertElement(findNode.simple('self.E.foo'), findElement.prefix('self'));
- assertElement(findNode.simple('E.foo'), findElement.extension_('E'));
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('E.foo]'), r'''
+CommentReference
+ expression: PropertyAccess
+ target: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: self
+ staticElement: self::@prefix::self
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: E
+ staticElement: self::@extension::E
+ staticType: null
+ staticElement: self::@extension::E
+ staticType: null
+ operator: .
+ propertyName: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E::@setter::foo
+ staticType: null
+ staticType: null
+''');
}
}
@@ -498,7 +946,13 @@
void f() {}
''');
- assertElement(findNode.simple('foo]'), findElement.topGet('foo'));
+ assertResolvedNodeText(findNode.commentReference('foo]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: foo
+ staticElement: self::@getter::foo
+ staticType: null
+''');
}
test_associatedSetterAndGetter_setterInScope() async {
@@ -513,7 +967,13 @@
}
''');
- assertElement(findNode.simple('foo]'), findElement.setter('foo'));
+ assertResolvedNodeText(findNode.commentReference('foo]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: foo
+ staticElement: self::@extension::E2::@setter::foo
+ staticType: null
+''');
}
test_beforeClass() async {
@@ -524,10 +984,13 @@
}
''');
- assertElement(
- findNode.simple('foo]'),
- findElement.method('foo'),
- );
+ assertResolvedNodeText(findNode.commentReference('foo]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+''');
}
test_beforeConstructor() async {
@@ -537,10 +1000,13 @@
A(int p);
}''');
- assertElement(
- findNode.simple('p]'),
- findElement.parameter('p'),
- );
+ assertResolvedNodeText(findNode.commentReference('p]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p
+ staticElement: p@28
+ staticType: null
+''');
}
test_beforeEnum() async {
@@ -553,18 +1019,29 @@
WITHOUT_SWORD
}''');
- assertElement(
- findNode.simple('Samurai]'),
- findElement.enum_('Samurai'),
- );
- assertElement(
- findNode.simple('int]'),
- intElement,
- );
- assertElement(
- findNode.simple('WITH_SWORD]'),
- findElement.getter('WITH_SWORD'),
- );
+ assertResolvedNodeText(findNode.commentReference('Samurai]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: Samurai
+ staticElement: self::@enum::Samurai
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('int]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: int
+ staticElement: dart:core::@class::int
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('WITH_SWORD]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: WITH_SWORD
+ staticElement: self::@enum::Samurai::@getter::WITH_SWORD
+ staticType: null
+''');
}
test_beforeFunction_blockBody() async {
@@ -585,10 +1062,13 @@
foo(int p) => null;
''');
- assertElement(
- findNode.simple('p]'),
- findElement.parameter('p'),
- );
+ assertResolvedNodeText(findNode.commentReference('p]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p
+ staticElement: p@16
+ staticType: null
+''');
}
test_beforeFunctionTypeAlias() async {
@@ -597,10 +1077,13 @@
typedef Foo(int p);
''');
- assertElement(
- findNode.simple('p]'),
- findElement.parameter('p'),
- );
+ assertResolvedNodeText(findNode.commentReference('p]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p
+ staticElement: p@24
+ staticType: null
+''');
}
test_beforeGenericTypeAlias() async {
@@ -609,15 +1092,29 @@
typedef Foo<T> = Function<S>(int p);
''');
- assertElement(
- findNode.simple('T]'),
- findElement.typeParameter('T'),
- );
- assertElement(findNode.simple('S]'), findElement.typeParameter('S'));
- assertElement(
- findNode.simple('p]'),
- findElement.parameter('p'),
- );
+ assertResolvedNodeText(findNode.commentReference('T]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: T
+ staticElement: T@47
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('S]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: S
+ staticElement: S@61
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('p]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p
+ staticElement: p@68
+ staticType: null
+''');
}
test_beforeGetter() async {
@@ -646,11 +1143,45 @@
}
''');
- assertElement(findNode.simple('p1]'), findElement.parameter('p1'));
- assertElement(findNode.simple('p2]'), findElement.parameter('p2'));
- assertElement(findNode.simple('p3]'), findElement.parameter('p3'));
- assertElement(findNode.simple('p4]'), findElement.parameter('p4'));
- assertElement(findNode.simple('p5]'), findElement.parameter('p5'));
+ assertResolvedNodeText(findNode.commentReference('p1]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p1
+ staticElement: p1@39
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('p2]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p2
+ staticElement: p2@65
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('p3]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p3
+ staticElement: p3@100
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('p4]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p4
+ staticElement: self::@class::A::@method::mc::@parameter::p4
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('p5]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: p5
+ staticElement: p5@132
+ staticType: null
+''');
}
test_newKeyword() async {
@@ -667,18 +1198,31 @@
error(HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, 49, 3),
]);
- assertElement(
- findNode.simple('A]'),
- findElement.unnamedConstructor('A'),
- );
- assertElement(
- findNode.simple('A.named]'),
- findElement.class_('A'),
- );
- assertElement(
- findNode.simple('named]'),
- findElement.constructor('named', of: 'A'),
- );
+ assertResolvedNodeText(findNode.commentReference('A]'), r'''
+CommentReference
+ newKeyword: new
+ expression: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A::@constructor::•
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('A.named]'), r'''
+CommentReference
+ newKeyword: new
+ expression: PrefixedIdentifier
+ prefix: SimpleIdentifier
+ token: A
+ staticElement: self::@class::A
+ staticType: null
+ period: .
+ identifier: SimpleIdentifier
+ token: named
+ staticElement: self::@class::A::@constructor::named
+ staticType: null
+ staticElement: self::@class::A::@constructor::named
+ staticType: null
+''');
}
test_parameter_functionTyped() async {
@@ -687,10 +1231,13 @@
foo(int bar()) {}
''');
- assertElement(
- findNode.simple('bar]'),
- findElement.parameter('bar'),
- );
+ assertResolvedNodeText(findNode.commentReference('bar]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: bar
+ staticElement: self::@function::foo::@parameter::bar
+ staticType: null
+''');
}
test_setter() async {
@@ -707,9 +1254,21 @@
}
''');
- var x = findElement.setter('x', of: 'A');
- assertElement(findNode.simple('x] in A'), x);
- assertElement(findNode.simple('x] in B'), x);
+ assertResolvedNodeText(findNode.commentReference('x] in A'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: x
+ staticElement: self::@class::A::@setter::x
+ staticType: null
+''');
+
+ assertResolvedNodeText(findNode.commentReference('x] in B'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: x
+ staticElement: self::@class::A::@setter::x
+ staticType: null
+''');
}
test_unqualifiedReferenceToNonLocalStaticMember() async {
@@ -722,9 +1281,12 @@
class B extends A {}
''');
- assertElement(
- findNode.simple('foo]'),
- findElement.method('foo', of: 'A'),
- );
+ assertResolvedNodeText(findNode.commentReference('foo]'), r'''
+CommentReference
+ expression: SimpleIdentifier
+ token: foo
+ staticElement: self::@class::A::@method::foo
+ staticType: null
+''');
}
}
diff --git a/pkg/compiler/README.md b/pkg/compiler/README.md
index 939a841..a21d663 100644
--- a/pkg/compiler/README.md
+++ b/pkg/compiler/README.md
@@ -4,188 +4,101 @@
## Architecture
-The compiler is currently undergoing a long refactoring process. As you navigate
-this code you may find it helpful to understand how the compiler used to be,
-where it is going, and where it is today.
+The compiler is structured to operate in several phases. By default these phases
+are executed in sequence in a single process, but on some build systems, some of
+these phases are split into separate processes. As such, there is plenty of
+indirection and data representations used mostly for the purpose of serializing
+intermediate results during compilation.
-### The near future architecture
+The current compiler phases are:
-The compiler will operate in these general phases:
+ 1. **common front-end**: Execute traditional front-end compilation phases.
+ Dart2js delegates to the common front-end (also used by DDC and the VM) to
+ do all front-end features, this includes:
+ * parsing Dart source code,
+ * type checking,
+ * inferring implicit user types, like locals with a `var` declaration,
+ * lowering or simplifying Dart features. For example, this is how many
+ syntactic features, like extension methods and list comprehensions, are
+ implemented.
+ * additional web-specific lowering or simplifications. For example,
+ expansion of JS-interop features and web specific implementation of
+ language features like late variables.
- 1. **load kernel**: Load all the code as kernel
- * Collect dart sources transtively
- * Convert to kernel AST
+ The result of this phase is a kernel AST which is serialized as a `.dill`
+ file.
- (this will be handled by invoking the front-end package)
+ 2. **modular analysis**: Using kernel as input, compute data recording
+ properties about each method in the program, especially around dependencies
+ and features they may need. We call this "impact data" (i1).
- Alternatively, the compiler can start compilation directly from kernel files.
+ When the compiler runs as a single process, this is done lazily/on-demand
+ during the tree-shaking phase (below). However, this data can also be
+ computed independently for individual methods, files, or packages in the
+ application. That makes it possible to run this modularly and in parallel.
- 2. **model**: Create a Dart model of the program
- * The kernel ASTs could be used as a model, so this might be a no-op or just
- creating a thin wrapper on top of kernel.
+ The result of this phase can be emitted as files containing impact data in
+ a serialized format.
- 3. **tree-shake and create world**: Build world of reachable code
- * For each reachable piece of code:
- * Compute impact (i1) from kernel AST
- * Build a closed world (w1)
+ 3. **tree-shake and create world**: Create a model to understand what parts of
+ the code are used by an application. This consists of:
+ * creating an intermediate representation called the "K model" that
+ wraps our kernel representation
+ * calculating which classes and methods are considered live in the
+ program. This is done by incrementally combining impact data (i1)
+ starting from `main`, then visiting reachable methods in the program
+ with an Rapid Type Analysis (RTA) algorithm to aggregate impacts
+ together.
- 4. **analyze**: Run a global analysis
- * Assume closed world semantics (from w1)
- * Produce a global result (g)
- * Like today (g) will contain type and nullability information
- * After we adopt strong-mode types, we want to explore simplifying this
- to only contain native + nullability information.
+ The result of this phase is what we call a "closed world" (w1). The closed
+ world is also a datastructure that can answer interesting queries, such as:
+ Is this interface implemented by a single class? Is this method available
+ in any stubtype of some interface? The answers to these questions can help
+ the compiler generate higher quality JavaScript.
- 5. **codegen model**: Create a JS model of the program
- * Model JavaScript specific concepts (like the split of constructor bodies
- as separate elements) and provide a mapping to the Dart model
+ 4. **global analysis**: Run a global analysis that assumes closed world
+ semantics (from w1) and propagates information across method boundaries to
+ further understand what values flow through the program. This phase is
+ very valuable in narrowing down possibilities that are ambiguous based
+ solely on type information written by developers. It often finds
+ oportunities that enable the compiler to devirtualize or inline method
+ calls, generate code specializations, or trigger performance optimizations.
- 6. **codegen and tree-shake**: Generate code, as needed
- * For each reachable piece of code:
- * build ssa graph from kernel ASTs and global results (g)
- * optimize ssa
+ The result of this phase is a "global result" (g).
+
+ 5. **codegen model**: Create a JS or backend model of the program. This is an
+ intermediate representation of the entities in the program we referred to
+ as the "J model". It is very similar to the "K model", but it is tailored
+ to model JavaScript specific concepts (like the split of constructor bodies
+ as separate elements) and provide a mapping to the Dart model.
+
+ 6. **codegen**: Generate code for each method that is deemed necessary. This
+ includes:
+ * build an SSA graph from kernel ASTs and global results (g)
+ * optimize the SSA representation
* compute impact (i2) from optimized code
* emit JS ASTs for the code
- * Build a codegen closed world (w2) from new impacts (i2)
- 7. **emit**: Assemble and minify the program
- * Build program structure from the compiled pieces (w2)
+
+ 7. **link tree-shake**: Using the results of codegen, we perform a second
+ round of tree-shaking. This is important because code that was deemed
+ reachable in (w1) may be found unreachable after optimizations. The process
+ is very similar to the earlier phase: we combine incrementally the codegen
+ impact data (i2) and compute a codegen closed world (w2).
+
+
+ When dart2js runs as a single process the codegen phase is done lazily and
+ on-demand, together with the tree-shaking phase.
+
+ 8. **emit JavaScript files**: The final step is to assemble and minify the
+ final program. This includes:
+ * Build a JavaScript program structure from the compiled pieces (w2)
* Use frequency namer to minify names.
* Emit js and source map files.
-### The old architecture
+## Code organization
-The compiler used to operate as follows:
-
- 1. **load dart**: Load all source files
- * Collect dart sources transtively
- * Scan enough tokens to build import dependencies.
-
- 2. **model**: Create a Dart model (aka. Element Model) of the program
- * Do a diet-parse of the program to create the high-level element model
-
- 3. **resolve and tree-shake**: Resolve and build world of reachable code (the
- resolution enqueuer)
- * For each reachable piece of code:
- * Parse the full body of the function
- * Resolve it and enqueue other pieces that are reachable
- * Type check the body of the function
-
- 4. **analyze**: Run a global analysis
- * Assume closed world semantics (from everything enqueued by the resolver)
- * Produce a global result about type and nullability information of method
- arguments, return values, and receivers of dynamic sends.
-
- 5. **codegen and tree-shake**: Generate code, as needed (via the codegen
- enqueuer)
- * For each reachable piece of code:
- * build ssa graph from resolved source ASTs global results (g)
- * optimize ssa
- * enqueue visible dependencies
- * emit js asts for the code
-
- 6. **emit**: Assemble and minify the program
- * Build program structure from the compiled pieces
- * Use frequency namer to minify names.
- * Emit js and source map files.
-
-### The architecture today (which might be changing while you read this!)
-
-When using the `--use-kernel` flag, you can test the latest state of the
-compiler as we are migrating to the new architecture. Currently it works as
-follows:
-
- 1. **load dart**: (same as old compiler)
-
- 2. **model**: (same element model as old compiler)
-
- 3. **resolve, tree-shake and build world**: Build world of reachable code
- * For each reachable piece of code:
- * Parse full body of the function
- * Resolve it from the parsed source ASTs
- * Type check it (same as old compiler)
- * Compute impact (i1) from resolved source ASTs (no kernel)
- * Build a closed world (w1)
-
- 4. **kernelize**: Create kernel ASTs
- * For all resolved elements in w1, compute their kernel representation using
- the `rasta` visitor.
-
- 5. **analyze**: (almost same as old compiler)
-
- 6. **codegen and tree-shake**: Generate code, as needed
- * For each reachable piece of code:
- * build ssa graph from kernel ASTs (uses global results g)
- * optimize ssa
- * compute impact (i2) from optimized code
- * emit js asts for the code
- * Build a codegen closed world (w2) from new impacts (i2)
-
- 7. **emit**: (same as old compiler)
-
-Some additional details worth highlighting:
-
- * tree-shaking is close to working as we want: the notion of a world and world
- impacts are computed explicitly:
-
- * In the old compiler, the resolver and code generator directly
- enqueued items to be processed, there was no knowledge of what had
- to be done other than in the algorithm itself.
-
- * Now the information is computed explicitly in two ways:
-
- * The dependencies of a single element are computed as an "impact"
- object, these are derived from the structure of the
- code (either the resolved code or the generated code).
-
- * The closed world is now an explicit concept that can be replaced in the
- compiler.
-
- * This allows us to delete the resolver in the future and replace it
- with a kernel loader, an impact builder from kernel, and a kernel world.
-
- * There is an implementation of a kernel impact builder, but it is not yet
- in use in the compiler pipeline (gated on replacing the Dart model)
-
- * We still depend on the Dart model computed by resolution, but progress has
- been made introducing an abstraction common to the new and old models. The
- old model is the "Element model", the generic abstraction is called the
- "Entity model". Some portions of the compiler now refer to the entity model.
-
- * The ssa graph is built from the kernel ASTs, but it still depends on the old
- element model computed from resolution (accessed via a kernel2Ast adapter).
- The graph builder implementation covers a large chunk of the language
- features, but is not complete (89% of langage & corelib tests are passing).
-
- * Global analysis is still working on top of the dart2js ASTs.
-
-## Code organization and history
-
-The compiler package was initially intended to be compiler for multiple targets:
-Javascript, Dart (dart2dart), and dartino bytecodes. It has now evolved to be a
-Javascript only compiler, but some of the abstractions to support multiple
-targets still remain.
-
-### Possibly confusing terminology
-
-Some of the terminology in the compiler is confusing without knowing its
-history. We are cleaning this up as we are rearchitecting the system, but here
-are some of the legacy terminology we have:
-
- * **target**: the output the compiler is producing. Nowdays it just
- JavaScript, but in the past there was also Dart and dartino bytecodes.
-
- * **backend**: pieces of the compiler that were target-specific.
- Note: in the past we've used the term *backend* also for code that is used
- in the frontend of the compiler that happens to be target-specific, as well
- as and code that is used in the emitter or what traditionally is known
- as the backend of the compiler.
-
- * **frontend**: the parser, resolver, and other early stages of the compiler.
- The front-end however makes target-specific choices. For example, to compile
- a program with async-await, the dart2js backend needs to include some helper
- functions that are used by the expanded async-await code, these helpers need
- to be parsed by the frontend and added to the compilation pipeline.
+### Some terminology used in the compiler
* **world**: the compiler exploits closed-world assumptions to do
optimizations. The *world* encapsulates some of our knowledge of the
@@ -201,29 +114,22 @@
* **model**: there are many models in the compiler:
- * **element model**: this is an abstraction describing the elements seen in
- Dart programs, like "libraries", "classes", "methods", etc.
-
- * **entity model**: also describes elements seen in Dart programs, but it is
- meant to be minimalistic and a super-hierarchy above the *element models*.
- This is a newer addition, is an added abstraction to make it possible to
- refactor our code from our old frontend to the kernel frontend.
-
- * **Dart vs JS models**: the compiler in the past had a single model to
- describe elements in the source and elements that were being compiled. In
- the future we plan to have two. Both input model and output models will be
- implementations of the *entity model*. The JS model is intended to have
- concepts specific about generating code in JS (like constructor-bodies as
- a separate entity than the constructor, closure classes, etc).
+ * **entity model**: this is an abstraction describing the elements seen in
+ Dart programs, like "libraries", "classes", "methods", etc. We currently
+ have two entity models, the "K model" (which is frontend centric and
+ usually maps 1:1 with kernel entities) and the "J model" (which is backend
+ centric).
* **emitter model**: this is a model just used for dumping out the structure
of the program in a .js text file. It doesn't have enough semantic meaning
- to be a JS model for compilation at this moment.
+ to be a JS model for compilation, which is why there is a separate "J
+ model".
* **enqueuer**: a work-queue used to achieve tree-shaking (or more precisely
tree-growing): elements are added to the enqueuer as we recognize that they
- are needed in a given application. Note that we even track how elements are
- used, since some ways of using an element require more code than others.
+ are needed in a given application (as described by the impact data). Note
+ that we even track how elements are used, since some ways of using an
+ element require more code than others.
### Code layout
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 7ded407..1d64607 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -1125,7 +1125,7 @@
}
void _writeInfo(js.Node node) {
- sink.writeCached<SourceInformation>(node.sourceInformation,
+ sink.writeCached<SourceInformation /*!*/ >(node.sourceInformation,
(SourceInformation sourceInformation) {
SourceInformation.writeToDataSink(sink, sourceInformation);
});
@@ -2195,7 +2195,7 @@
break;
}
SourceInformation sourceInformation =
- source.readCached<SourceInformation>(() {
+ source.readCachedOrNull<SourceInformation>(() {
return SourceInformation.readFromDataSource(source);
});
if (sourceInformation != null) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 3521af7..184e44e 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -22,6 +22,7 @@
import 'compiler.dart' show Compiler;
import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
import 'deferred_load/output_unit.dart' show OutputUnit, deferredPartFileName;
+import 'dump_info_javascript_monitor.dart';
import 'elements/entities.dart';
import 'inferrer/abstract_value_domain.dart';
import 'inferrer/types.dart'
@@ -1019,7 +1020,8 @@
void reportInlined(FunctionEntity element, MemberEntity inlinedFrom);
}
-class DumpInfoTask extends CompilerTask implements InfoReporter {
+class DumpInfoTask extends CompilerTask
+ implements DumpInfoJavaScriptMonitor, InfoReporter {
final Compiler compiler;
final bool useBinaryFormat;
@@ -1120,6 +1122,7 @@
bool get shouldEmitText => !useBinaryFormat;
// TODO(sigmund): delete the stack once we stop emitting the source text.
final List<_CodeData> _stack = [];
+ @override // DumpInfoJavaScriptMonitor
void enterNode(jsAst.Node node, int start) {
var data = _nodeData[node];
data?.start = start;
@@ -1129,6 +1132,7 @@
}
}
+ @override // DumpInfoJavaScriptMonitor
void emit(String string) {
if (shouldEmitText) {
// Note: historically we emitted the full body of classes and methods, so
@@ -1138,6 +1142,7 @@
}
}
+ @override // DumpInfoJavaScriptMonitor
void exitNode(jsAst.Node node, int start, int end, int closing) {
var data = _nodeData[node];
data?.end = end;
diff --git a/pkg/compiler/lib/src/dump_info_javascript_monitor.dart b/pkg/compiler/lib/src/dump_info_javascript_monitor.dart
new file mode 100644
index 0000000..da46ae1
--- /dev/null
+++ b/pkg/compiler/lib/src/dump_info_javascript_monitor.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2022, 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 file.
+
+library dump_info.javascript_monitor;
+
+import 'package:js_ast/js_ast.dart' as jsAst show Node;
+
+/// Interface implemented by `DumpInfoTask` used to monitor the generated
+/// JavaScript as it is written.
+// TODO(48820): Remove this interface when `DumpInfoTask` is migrated.
+// TODO(sra): Perhaps `DumpInfoTask` should have a member that implements
+// `JavaScriptPrintingContext` instead of this very similar interface.
+abstract class DumpInfoJavaScriptMonitor {
+ void enterNode(jsAst.Node node, int start);
+ void emit(String string);
+ void exitNode(jsAst.Node node, int start, int end, int? closing);
+}
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 869cfa7..58812cd 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.10
-
library dart2js.code_output;
import '../../compiler_api.dart' as api show OutputSink;
@@ -28,8 +26,9 @@
///
/// The inlining call-site was made from [pushLocation] and calls
/// [inlinedMethodName].
+ // TODO(48820): We might have a [pushPosition].
void addPush(
- int targetOffset, SourceLocation pushPosition, String inlinedMethodName);
+ int targetOffset, SourceLocation? pushPosition, String inlinedMethodName);
/// Record a return of an inlining call at the [targetOffset].
///
@@ -63,7 +62,7 @@
}
@override
- void addPush(int targetOffset, SourceLocation sourceLocation,
+ void addPush(int targetOffset, SourceLocation? sourceLocation,
String inlinedMethodName) {
assert(targetOffset <= codeOutput.length);
List<FrameEntry> frames = frameMarkers[targetOffset] ??= [];
@@ -137,12 +136,11 @@
}
abstract class AbstractCodeOutput extends CodeOutput {
- final List<CodeOutputListener> _listeners;
+ final List<CodeOutputListener>? _listeners;
AbstractCodeOutput([this._listeners]);
- Map<String, _SourceLocationsImpl> sourceLocationsMap =
- <String, _SourceLocationsImpl>{};
+ Map<String, _SourceLocationsImpl> sourceLocationsMap = {};
@override
bool isClosed = false;
@@ -198,7 +196,7 @@
class CodeBuffer extends AbstractCodeOutput implements BufferedCodeOutput {
StringBuffer buffer = StringBuffer();
- CodeBuffer([List<CodeOutputListener> listeners]) : super(listeners);
+ CodeBuffer([List<CodeOutputListener>? listeners]) : super(listeners);
@override
void _addInternal(String text) {
@@ -225,7 +223,7 @@
int length = 0;
final api.OutputSink output;
- StreamCodeOutput(this.output, [List<CodeOutputListener> listeners])
+ StreamCodeOutput(this.output, [List<CodeOutputListener>? listeners])
: super(listeners);
@override
diff --git a/pkg/compiler/lib/src/io/kernel_source_information.dart b/pkg/compiler/lib/src/io/kernel_source_information.dart
index 1634405..e8982b1 100644
--- a/pkg/compiler/lib/src/io/kernel_source_information.dart
+++ b/pkg/compiler/lib/src/io/kernel_source_information.dart
@@ -252,7 +252,7 @@
if (node is ir.LocalFunction) {
return _buildBody(node, node.function.body);
} else if (node is ir.Member && node.function != null) {
- return _buildBody(node, node.function.body);
+ return _buildBody(node, node.function /*!*/ .body);
}
break;
default:
@@ -501,9 +501,4 @@
KernelSourceLocation(ir.Location location, this.offset, this.sourceName)
: sourceUri = location.file,
super.fromLocation(location);
-
- KernelSourceLocation.fromOther(KernelSourceLocation other, this.sourceName)
- : sourceUri = other.sourceUri,
- offset = other.offset,
- super.fromOther(other);
}
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index ee6cfd7..08b07ae 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.10
-
/// Source information system mapping that attempts a semantic mapping between
/// offsets of JavaScript code points to offsets of Dart code points.
@@ -27,22 +25,24 @@
final SourceLocation startPosition;
@override
- final SourceLocation innerPosition;
+ final SourceLocation? innerPosition;
@override
- final List<FrameContext> inliningContext;
+ final List<FrameContext>? inliningContext;
PositionSourceInformation(
- this.startPosition, this.innerPosition, this.inliningContext);
+ this.startPosition, this.innerPosition, this.inliningContext) {
+ assert((startPosition as dynamic) != null);
+ }
factory PositionSourceInformation.readFromDataSource(
DataSourceReader source) {
source.begin(tag);
SourceLocation startPosition = source.readCached<SourceLocation>(
() => SourceLocation.readFromDataSource(source));
- SourceLocation innerPosition = source.readCached<SourceLocation>(
+ SourceLocation? innerPosition = source.readCachedOrNull<SourceLocation>(
() => SourceLocation.readFromDataSource(source));
- List<FrameContext> inliningContext =
+ List<FrameContext>? inliningContext =
source.readListOrNull(() => FrameContext.readFromDataSource(source));
source.end(tag);
return PositionSourceInformation(
@@ -68,19 +68,17 @@
@override
List<SourceLocation> get sourceLocations {
List<SourceLocation> list = [];
- if (startPosition != null) {
- list.add(startPosition);
- }
+ list.add(startPosition);
if (innerPosition != null) {
- list.add(innerPosition);
+ list.add(innerPosition!);
}
return list;
}
@override
SourceSpan get sourceSpan {
- SourceLocation location = startPosition ?? innerPosition;
- Uri uri = location.sourceUri;
+ SourceLocation location = startPosition;
+ Uri uri = location.sourceUri!;
int offset = location.offset;
return SourceSpan(uri, offset, offset);
}
@@ -106,33 +104,23 @@
StringBuffer sb = StringBuffer();
sb.write('$uriText:');
// Use 1-based line/column info to match usual dart tool output.
- if (startPosition != null) {
- sb.write('[${startPosition.line},'
- '${startPosition.column}]');
- }
+ sb.write('[${startPosition.line},'
+ '${startPosition.column}]');
if (innerPosition != null) {
- sb.write('-[${innerPosition.line},'
- '${innerPosition.column}]');
+ sb.write('-[${innerPosition!.line},'
+ '${innerPosition!.column}]');
}
return sb.toString();
}
@override
String get shortText {
- if (startPosition != null) {
- return _computeText(startPosition.sourceUri.pathSegments.last);
- } else {
- return _computeText(innerPosition.sourceUri.pathSegments.last);
- }
+ return _computeText(startPosition.sourceUri!.pathSegments.last);
}
@override
String toString() {
- if (startPosition != null) {
- return _computeText('${startPosition.sourceUri}');
- } else {
- return _computeText('${innerPosition.sourceUri}');
- }
+ return _computeText('${startPosition.sourceUri}');
}
}
@@ -170,19 +158,19 @@
List<SourceLocation> get sourceLocations => const [];
@override
- SourceSpan get sourceSpan => SourceSpan(null, null, null);
+ SourceSpan get sourceSpan => SourceSpan.unknown();
}
/// The start, end and closing offsets for a [js.Node].
class CodePosition {
final int startPosition;
final int endPosition;
- final int closingPosition;
+ final int? closingPosition;
CodePosition(this.startPosition, this.endPosition, this.closingPosition);
// ignore: MISSING_RETURN
- int getPosition(CodePositionKind kind) {
+ int? getPosition(CodePositionKind kind) {
switch (kind) {
case CodePositionKind.START:
return startPosition;
@@ -202,7 +190,7 @@
/// A map from a [js.Node] to its [CodePosition].
abstract class CodePositionMap {
- CodePosition operator [](js.Node node);
+ CodePosition? operator [](js.Node node);
}
/// Registry for mapping [js.Node]s to their [CodePosition].
@@ -211,7 +199,7 @@
Map<js.Node, CodePosition>.identity();
void registerPositions(
- js.Node node, int startPosition, int endPosition, int closingPosition) {
+ js.Node node, int startPosition, int endPosition, int? closingPosition) {
registerCodePosition(
node, CodePosition(startPosition, endPosition, closingPosition));
}
@@ -221,7 +209,7 @@
}
@override
- CodePosition operator [](js.Node node) => _codePositionMap[node];
+ CodePosition? operator [](js.Node node) => _codePositionMap[node];
}
/// Enum values for the part of a Dart node used for the source location offset.
@@ -259,9 +247,9 @@
}
// ignore: MISSING_RETURN
-SourceLocation getSourceLocation(SourceInformation sourceInformation,
+SourceLocation? getSourceLocation(SourceInformation sourceInformation,
[SourcePositionKind sourcePositionKind = SourcePositionKind.START]) {
- if (sourceInformation == null) return null;
+ assert((sourceInformation as dynamic) != null);
switch (sourcePositionKind) {
case SourcePositionKind.START:
return sourceInformation.startPosition;
@@ -319,12 +307,12 @@
final CodePositionRecorder codePositionRecorder = CodePositionRecorder();
final SourceInformationReader reader;
- CodePositionMap codePositionMap;
- List<TraceListener> traceListeners;
- InliningTraceListener inliningListener;
+ late final CodePositionMap codePositionMap;
+ late final List<TraceListener> traceListeners;
+ late final InliningTraceListener inliningListener;
PositionSourceInformationProcessor(SourceMapperProvider provider, this.reader,
- [Coverage coverage]) {
+ [Coverage? coverage]) {
codePositionMap = coverage != null
? CodePositionCoverage(codePositionRecorder, coverage)
: codePositionRecorder;
@@ -341,12 +329,12 @@
@override
void process(js.Node node, BufferedCodeOutput code) {
JavaScriptTracer(codePositionMap, reader, traceListeners).apply(node);
- inliningListener?.finish();
+ inliningListener.finish();
}
@override
void onPositions(
- js.Node node, int startPosition, int endPosition, int closingPosition) {
+ js.Node node, int startPosition, int endPosition, int? closingPosition) {
codePositionRecorder.registerPositions(
node, startPosition, endPosition, closingPosition);
}
@@ -354,23 +342,23 @@
/// Visitor that computes [SourceInformation] for a [js.Node] using information
/// attached to the node itself or alternatively from child nodes.
-class NodeSourceInformation extends js.BaseVisitor<SourceInformation> {
+class NodeSourceInformation extends js.BaseVisitor<SourceInformation?> {
final SourceInformationReader reader;
const NodeSourceInformation(this.reader);
- SourceInformation visit(js.Node node) => node?.accept(this);
+ SourceInformation? visit(js.Node? node) => node?.accept(this);
@override
- SourceInformation visitNode(js.Node node) =>
+ SourceInformation? visitNode(js.Node node) =>
reader.getSourceInformation(node);
@override
- SourceInformation visitComment(js.Comment node) => null;
+ SourceInformation? visitComment(js.Comment node) => null;
@override
- SourceInformation visitExpressionStatement(js.ExpressionStatement node) {
- SourceInformation sourceInformation = reader.getSourceInformation(node);
+ SourceInformation? visitExpressionStatement(js.ExpressionStatement node) {
+ SourceInformation? sourceInformation = reader.getSourceInformation(node);
if (sourceInformation != null) {
return sourceInformation;
}
@@ -378,14 +366,14 @@
}
@override
- SourceInformation visitVariableDeclarationList(
+ SourceInformation? visitVariableDeclarationList(
js.VariableDeclarationList node) {
- SourceInformation sourceInformation = reader.getSourceInformation(node);
+ SourceInformation? sourceInformation = reader.getSourceInformation(node);
if (sourceInformation != null) {
return sourceInformation;
}
for (js.Node declaration in node.declarations) {
- SourceInformation sourceInformation = visit(declaration);
+ SourceInformation? sourceInformation = visit(declaration);
if (sourceInformation != null) {
return sourceInformation;
}
@@ -394,9 +382,9 @@
}
@override
- SourceInformation visitVariableInitialization(
+ SourceInformation? visitVariableInitialization(
js.VariableInitialization node) {
- SourceInformation sourceInformation = reader.getSourceInformation(node);
+ SourceInformation? sourceInformation = reader.getSourceInformation(node);
if (sourceInformation != null) {
return sourceInformation;
}
@@ -404,8 +392,8 @@
}
@override
- SourceInformation visitAssignment(js.Assignment node) {
- SourceInformation sourceInformation = reader.getSourceInformation(node);
+ SourceInformation? visitAssignment(js.Assignment node) {
+ SourceInformation? sourceInformation = reader.getSourceInformation(node);
if (sourceInformation != null) {
return sourceInformation;
}
@@ -417,7 +405,7 @@
abstract class NodeToSourceInformationMixin {
SourceInformationReader get reader;
- SourceInformation computeSourceInformation(js.Node node) {
+ SourceInformation? computeSourceInformation(js.Node node) {
return NodeSourceInformation(reader).visit(node);
}
}
@@ -428,37 +416,38 @@
final SourceMapper sourceMapper;
@override
final SourceInformationReader reader;
- final Map<int, List<FrameContext>> _frames = {};
+ final Map<int, List<FrameContext>?> _frames = {};
InliningTraceListener(this.sourceMapper, this.reader);
@override
void onStep(js.Node node, Offset offset, StepKind kind) {
- SourceInformation sourceInformation = computeSourceInformation(node);
+ SourceInformation? sourceInformation = computeSourceInformation(node);
if (sourceInformation == null) return;
// TODO(sigmund): enable this assertion.
// assert(offset.value != null, "Expected a valid offset: $node $offset");
- if (offset.value == null) return;
+ final offsetValue = offset.value;
+ if (offsetValue == null) return;
// TODO(sigmund): enable this assertion
//assert(_frames[offset.value] == null,
// "Expect a single entry per offset: $offset $node");
- if (_frames[offset.value] != null) return;
+ if (_frames[offsetValue] != null) return;
// During tracing we only collect information per offset because the tracer
// visits nodes in tree order. We'll later sort the data by offset before
// registering the frame data with [SourceMapper].
if (kind == StepKind.FUN_EXIT) {
- _frames[offset.value] = null;
+ _frames[offsetValue] = null;
} else {
- _frames[offset.value] = sourceInformation.inliningContext;
+ _frames[offsetValue] = sourceInformation.inliningContext;
}
}
/// Converts the inlining context data collected during tracing into push/pop
/// stack operations that will be emitted with the source-map files.
void finish() {
- List<FrameContext> lastInliningContext;
+ List<FrameContext>? lastInliningContext;
for (var offset in _frames.keys.toList()..sort()) {
var newInliningContext = _frames[offset];
@@ -471,7 +460,7 @@
int popCount = 0;
List<FrameContext> pushes = const [];
if (newInliningContext == null) {
- popCount = lastInliningContext.length;
+ popCount = lastInliningContext!.length;
isEmpty = true;
} else if (lastInliningContext == null) {
pushes = newInliningContext;
@@ -563,7 +552,7 @@
/// ^
@override
void onStep(js.Node node, Offset offset, StepKind kind) {
- int codeLocation = offset.value;
+ int? codeLocation = offset.value;
if (codeLocation == null) return;
if (kind == StepKind.NO_INFO) {
@@ -571,11 +560,11 @@
return;
}
- SourceInformation sourceInformation = computeSourceInformation(node);
+ SourceInformation? sourceInformation = computeSourceInformation(node);
if (sourceInformation == null) return;
void registerPosition(SourcePositionKind sourcePositionKind) {
- SourceLocation sourceLocation =
+ SourceLocation? sourceLocation =
getSourceLocation(sourceInformation, sourcePositionKind);
if (sourceLocation != null) {
sourceMapper.register(node, codeLocation, sourceLocation);
@@ -595,7 +584,7 @@
break;
case StepKind.CALL:
CallPosition callPosition =
- CallPosition.getSemanticPositionForCall(node);
+ CallPosition.getSemanticPositionForCall(node as js.Call);
registerPosition(callPosition.sourcePositionKind);
break;
case StepKind.ACCESS:
@@ -686,7 +675,7 @@
/// (@ marks the current JavaScript position and ^ point to the mapped Dart
/// code position.)
static CallPosition getSemanticPositionForCall(js.Call node) {
- js.Expression access = js.undefer(node.target);
+ js.Expression access = js.undefer(node.target) as js.Expression;
if (access is js.PropertyAccess) {
js.Node target = access;
bool pureAccess = false;
@@ -758,6 +747,10 @@
///
/// Currently [subexpressionOffset] is used since it corresponds the most to the
/// offset used by most browsers.
+///
+// TODO(sra): Any or all of the values can be `null`. Investigate why this
+// happens. Since we are writing a JavaScript AST to an output, we should be
+// able to have non-null values.
class Offset {
/// The offset of the enclosing statement relative to the beginning of the
/// file.
@@ -769,7 +762,7 @@
/// ^ // the statement offset of the `*.bar()` call
/// ^ // the statement offset of the `baz()` call
///
- final int statementOffset;
+ final int? statementOffset;
/// The `subexpression` offset of the step. This is the (mostly) unique
/// offset relative to the beginning of the file, that identifies the
@@ -786,7 +779,7 @@
/// the `foo()` its execution is identified by the `bar` identifier more than
/// the foo identifier.
///
- final int subexpressionOffset;
+ final int? subexpressionOffset;
/// The `left-to-right` offset of the step. This is like [subexpressionOffset]
/// but restricted so that the offset of each subexpression in execution
@@ -802,12 +795,12 @@
/// Here, `baz()` is executed before `foo()` so we need to use 'f' as its best
/// position under the restriction.
///
- final int leftToRightOffset;
+ final int? leftToRightOffset;
Offset(
this.statementOffset, this.leftToRightOffset, this.subexpressionOffset);
- int get value => subexpressionOffset;
+ int? get value => subexpressionOffset;
@override
String toString() {
@@ -878,13 +871,13 @@
List steps = [];
/// The offset of the current statement.
- int statementOffset;
+ int? statementOffset;
/// The current offset in left-to-right progression.
- int leftToRightOffset;
+ int? leftToRightOffset;
/// The offset of the surrounding statement, used for the first subexpression.
- int offsetPosition;
+ int? offsetPosition;
bool active;
@@ -921,7 +914,7 @@
void apply(js.Node node) {
notifyStart(node);
- int startPosition = getSyntaxOffset(node, kind: CodePositionKind.START);
+ int? startPosition = getSyntaxOffset(node, kind: CodePositionKind.START);
Offset startOffset = getOffsetForNode(node, startPosition);
notifyStep(node, startOffset, StepKind.NO_INFO, force: true);
@@ -930,11 +923,11 @@
}
@override
- visitNode(js.Node node) {
+ void visitNode(js.Node node) {
node.visitChildren(this);
}
- visit(js.Node node, [BranchKind branch, value]) {
+ visit(js.Node? node, [BranchKind? branch, value]) {
if (node != null) {
if (branch != null) {
notifyPushBranch(branch, value);
@@ -946,11 +939,9 @@
}
}
- visitList(List<js.Node> nodeList) {
- if (nodeList != null) {
- for (js.Node node in nodeList) {
- visit(node);
- }
+ void visitList(List<js.Node> nodeList) {
+ for (js.Node node in nodeList) {
+ visit(node);
}
}
@@ -971,7 +962,7 @@
Offset exitOffset = getOffsetForNode(node, statementOffset);
notifyStep(node, exitOffset, StepKind.FUN_EXIT);
if (active && !activeBefore) {
- int endPosition = getSyntaxOffset(node, kind: CodePositionKind.END);
+ int? endPosition = getSyntaxOffset(node, kind: CodePositionKind.END);
Offset endOffset = getOffsetForNode(node, endPosition);
notifyStep(node, endOffset, StepKind.NO_INFO);
}
@@ -995,9 +986,9 @@
}
}
- int getSyntaxOffset(js.Node node,
+ int? getSyntaxOffset(js.Node node,
{CodePositionKind kind = CodePositionKind.START}) {
- CodePosition codePosition = codePositions[node];
+ CodePosition? codePosition = codePositions[node];
if (codePosition != null) {
return codePosition.getPosition(kind);
}
@@ -1005,7 +996,7 @@
}
visitSubexpression(
- js.Node parent, js.Expression child, int codeOffset, StepKind kind) {
+ js.Node parent, js.Expression child, int? codeOffset, StepKind kind) {
var oldSteps = steps;
steps = [];
offsetPosition = codeOffset;
@@ -1033,13 +1024,13 @@
@override
visitCall(js.Call node) {
visit(node.target);
- int oldPosition = offsetPosition;
+ int? oldPosition = offsetPosition;
offsetPosition = null;
visitList(node.arguments);
offsetPosition = oldPosition;
CallPosition callPosition = CallPosition.getSemanticPositionForCall(node);
js.Node positionNode = callPosition.node;
- int callOffset =
+ int? callOffset =
getSyntaxOffset(positionNode, kind: callPosition.codePositionKind);
if (offsetPosition == null) {
// Use the call offset if this is not the first subexpression.
@@ -1054,7 +1045,7 @@
@override
visitNew(js.New node) {
visit(node.target);
- int oldPosition = offsetPosition;
+ int? oldPosition = offsetPosition;
offsetPosition = null;
visitList(node.arguments);
offsetPosition = oldPosition;
@@ -1135,26 +1126,29 @@
@override
visitFor(js.For node) {
- int offset = statementOffset = getSyntaxOffset(node);
+ int? offset = statementOffset = getSyntaxOffset(node);
statementOffset = offset;
leftToRightOffset = null;
- if (node.init != null) {
+ final init = node.init;
+ if (init != null) {
visitSubexpression(
- node, node.init, getSyntaxOffset(node), StepKind.FOR_INITIALIZER);
+ node, init, getSyntaxOffset(node), StepKind.FOR_INITIALIZER);
}
- if (node.condition != null) {
- visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
- StepKind.FOR_CONDITION);
+ final condition = node.condition;
+ if (condition != null) {
+ visitSubexpression(
+ node, condition, getSyntaxOffset(condition), StepKind.FOR_CONDITION);
}
notifyPushBranch(BranchKind.LOOP);
visit(node.body);
statementOffset = offset;
- if (node.update != null) {
+ final update = node.update;
+ if (update != null) {
visitSubexpression(
- node, node.update, getSyntaxOffset(node.update), StepKind.FOR_UPDATE);
+ node, update, getSyntaxOffset(update), StepKind.FOR_UPDATE);
}
notifyPopBranch();
@@ -1163,10 +1157,8 @@
@override
visitWhile(js.While node) {
statementOffset = getSyntaxOffset(node);
- if (node.condition != null) {
- visitSubexpression(node, node.condition, getSyntaxOffset(node),
- StepKind.WHILE_CONDITION);
- }
+ visitSubexpression(
+ node, node.condition, getSyntaxOffset(node), StepKind.WHILE_CONDITION);
statementOffset = null;
leftToRightOffset = null;
@@ -1177,10 +1169,9 @@
visitDo(js.Do node) {
statementOffset = getSyntaxOffset(node);
visit(node.body);
- if (node.condition != null) {
- visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
- StepKind.DO_CONDITION);
- }
+ final condition = node.condition;
+ visitSubexpression(
+ node, condition, getSyntaxOffset(condition), StepKind.DO_CONDITION);
statementOffset = null;
leftToRightOffset = null;
}
@@ -1323,16 +1314,16 @@
visit(node.value);
}
- Offset getOffsetForNode(js.Node node, int codeOffset) {
+ Offset getOffsetForNode(js.Node node, int? codeOffset) {
if (codeOffset == null) {
- CodePosition codePosition = codePositions[node];
+ CodePosition? codePosition = codePositions[node];
if (codePosition != null) {
codeOffset = codePosition.startPosition;
}
}
if (leftToRightOffset != null &&
codeOffset != null &&
- leftToRightOffset < codeOffset) {
+ leftToRightOffset! < codeOffset) {
leftToRightOffset = codeOffset;
}
if (leftToRightOffset == null) {
@@ -1370,15 +1361,16 @@
_nodesWithoutOffset.clear();
_nodesWithoutInfoCount += _nodesWithoutInfo.length;
+
for (js.Node node in _nodesWithoutInfo) {
+ Type type;
if (node is js.ExpressionStatement) {
- _nodesWithoutInfoCountByType.putIfAbsent(
- node.expression.runtimeType, () => 0);
- _nodesWithoutInfoCountByType[node.expression.runtimeType]++;
+ type = node.expression.runtimeType;
} else {
- _nodesWithoutInfoCountByType.putIfAbsent(node.runtimeType, () => 0);
- _nodesWithoutInfoCountByType[node.runtimeType]++;
+ type = node.runtimeType;
}
+ _nodesWithoutInfoCountByType.update(type, (count) => count + 1,
+ ifAbsent: () => 1);
}
_nodesWithoutInfo.clear();
}
@@ -1412,12 +1404,12 @@
sb.write(') by runtime type:');
List<Type> types = _nodesWithoutInfoCountByType.keys.toList();
types.sort((a, b) {
- return -_nodesWithoutInfoCountByType[a]
- .compareTo(_nodesWithoutInfoCountByType[b]);
+ return -_nodesWithoutInfoCountByType[a]!
+ .compareTo(_nodesWithoutInfoCountByType[b]!);
});
types.forEach((Type type) {
- int count = _nodesWithoutInfoCountByType[type];
+ int count = _nodesWithoutInfoCountByType[type]!;
sb.write('\n ');
sb.write(count);
sb.write(' ');
@@ -1446,7 +1438,7 @@
@override
void onStep(js.Node node, Offset offset, StepKind kind) {
- SourceInformation sourceInformation = computeSourceInformation(node);
+ SourceInformation? sourceInformation = computeSourceInformation(node);
if (sourceInformation != null) {
coverage.registerNodeWithInfo(node);
} else {
@@ -1468,8 +1460,8 @@
CodePositionCoverage(this.codePositions, this.coverage);
@override
- CodePosition operator [](js.Node node) {
- CodePosition codePosition = codePositions[node];
+ CodePosition? operator [](js.Node node) {
+ CodePosition? codePosition = codePositions[node];
if (codePosition == null) {
coverage.registerNodesWithoutOffset(node);
}
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 0171346..bbf7969 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.10
-
library dart2js.source_information;
import 'package:kernel/ast.dart' as ir;
@@ -22,9 +20,7 @@
static SourceInformation readFromDataSource(DataSourceReader source) {
int hasSourceInformation = source.readInt();
- if (hasSourceInformation == 0) {
- return null;
- } else if (hasSourceInformation == 1) {
+ if (hasSourceInformation == 1) {
return const SourceMappedMarker();
} else {
assert(hasSourceInformation == 2);
@@ -34,13 +30,12 @@
static void writeToDataSink(
DataSinkWriter sink, SourceInformation sourceInformation) {
- if (sourceInformation == null) {
- sink.writeInt(0);
- } else if (sourceInformation is SourceMappedMarker) {
+ if (sourceInformation is SourceMappedMarker) {
sink.writeInt(1);
} else {
sink.writeInt(2);
- PositionSourceInformation positionSourceInformation = sourceInformation;
+ PositionSourceInformation positionSourceInformation =
+ sourceInformation as PositionSourceInformation;
positionSourceInformation.writeToDataSinkInternal(sink);
}
}
@@ -48,21 +43,21 @@
SourceSpan get sourceSpan;
/// The source location associated with the start of the JS node.
- SourceLocation get startPosition => null;
+ SourceLocation? get startPosition => null;
/// The source location associated with an inner of the JS node.
///
/// The inner position is for instance `foo()` in `o.foo()`.
- SourceLocation get innerPosition => null;
+ SourceLocation? get innerPosition => null;
/// The source location associated with the end of the JS node.
- SourceLocation get endPosition => null;
+ SourceLocation? get endPosition => null;
/// A list containing start, inner, and end positions.
List<SourceLocation> get sourceLocations;
/// A list of inlining context locations.
- List<FrameContext> get inliningContext => null;
+ List<FrameContext>? get inliningContext => null;
/// Return a short textual representation of the source location.
String get shortText;
@@ -118,7 +113,7 @@
}
/// Generate [SourceInformation] marker for non-preamble code.
- SourceInformation buildSourceMappedMarker() => null;
+ SourceInformation? buildSourceMappedMarker() => null;
/// Called when compilation has completed.
void onComplete() {}
@@ -135,123 +130,124 @@
this;
/// Generate [SourceInformation] for the declaration of the [member].
- SourceInformation buildDeclaration(covariant MemberEntity member) => null;
+ SourceInformation? buildDeclaration(covariant MemberEntity member) => null;
/// Generate [SourceInformation] for the stub of [callStructure] for [member].
- SourceInformation buildStub(
+ SourceInformation? buildStub(
covariant FunctionEntity function, CallStructure callStructure) =>
null;
/// Generate [SourceInformation] for the generic [node].
@deprecated
- SourceInformation buildGeneric(ir.Node node) => null;
+ SourceInformation? buildGeneric(ir.Node node) => null;
/// Generate [SourceInformation] for an instantiation of a class using [node]
/// for the source position.
- SourceInformation buildCreate(ir.Node node) => null;
+ SourceInformation? buildCreate(ir.Node node) => null;
/// Generate [SourceInformation] for the return [node].
- SourceInformation buildReturn(ir.Node node) => null;
+ SourceInformation? buildReturn(ir.Node node) => null;
/// Generate [SourceInformation] for an implicit return in [element].
- SourceInformation buildImplicitReturn(covariant MemberEntity element) => null;
+ SourceInformation? buildImplicitReturn(covariant MemberEntity element) =>
+ null;
/// Generate [SourceInformation] for the loop [node].
- SourceInformation buildLoop(ir.Node node) => null;
+ SourceInformation? buildLoop(ir.Node node) => null;
/// Generate [SourceInformation] for a read access like `a.b`.
- SourceInformation buildGet(ir.Node node) => null;
+ SourceInformation? buildGet(ir.Node node) => null;
/// Generate [SourceInformation] for a write access like `a.b = 3`.
- SourceInformation buildSet(ir.Node node) => null;
+ SourceInformation? buildSet(ir.Node node) => null;
/// Generate [SourceInformation] for a call in [node].
- SourceInformation buildCall(ir.Node receiver, ir.Node call) => null;
+ SourceInformation? buildCall(ir.Node receiver, ir.Node call) => null;
/// Generate [SourceInformation] for the if statement in [node].
- SourceInformation buildIf(ir.Node node) => null;
+ SourceInformation? buildIf(ir.Node node) => null;
/// Generate [SourceInformation] for the constructor invocation in [node].
- SourceInformation buildNew(ir.Node node) => null;
+ SourceInformation? buildNew(ir.Node node) => null;
/// Generate [SourceInformation] for the throw in [node].
- SourceInformation buildThrow(ir.Node node) => null;
+ SourceInformation? buildThrow(ir.Node node) => null;
/// Generate [SourceInformation] for the assert in [node].
- SourceInformation buildAssert(ir.Node node) => null;
+ SourceInformation? buildAssert(ir.Node node) => null;
/// Generate [SourceInformation] for the assignment in [node].
- SourceInformation buildAssignment(ir.Node node) => null;
+ SourceInformation? buildAssignment(ir.Node node) => null;
/// Generate [SourceInformation] for the variable declaration inserted as
/// first statement of a function.
- SourceInformation buildVariableDeclaration() => null;
+ SourceInformation? buildVariableDeclaration() => null;
/// Generate [SourceInformation] for the await [node].
- SourceInformation buildAwait(ir.Node node) => null;
+ SourceInformation? buildAwait(ir.Node node) => null;
/// Generate [SourceInformation] for the yield or yield* [node].
- SourceInformation buildYield(ir.Node node) => null;
+ SourceInformation? buildYield(ir.Node node) => null;
/// Generate [SourceInformation] for async/await boiler plate code.
- SourceInformation buildAsyncBody() => null;
+ SourceInformation? buildAsyncBody() => null;
/// Generate [SourceInformation] for exiting async/await code.
- SourceInformation buildAsyncExit() => null;
+ SourceInformation? buildAsyncExit() => null;
/// Generate [SourceInformation] for an invocation of a foreign method.
- SourceInformation buildForeignCode(ir.Node node) => null;
+ SourceInformation? buildForeignCode(ir.Node node) => null;
/// Generate [SourceInformation] for a string interpolation of [node].
- SourceInformation buildStringInterpolation(ir.Node node) => null;
+ SourceInformation? buildStringInterpolation(ir.Node node) => null;
/// Generate [SourceInformation] for the for-in `iterator` access in [node].
- SourceInformation buildForInIterator(ir.Node node) => null;
+ SourceInformation? buildForInIterator(ir.Node node) => null;
/// Generate [SourceInformation] for the for-in `moveNext` call in [node].
- SourceInformation buildForInMoveNext(ir.Node node) => null;
+ SourceInformation? buildForInMoveNext(ir.Node node) => null;
/// Generate [SourceInformation] for the for-in `current` access in [node].
- SourceInformation buildForInCurrent(ir.Node node) => null;
+ SourceInformation? buildForInCurrent(ir.Node node) => null;
/// Generate [SourceInformation] for the for-in variable assignment in [node].
- SourceInformation buildForInSet(ir.Node node) => null;
+ SourceInformation? buildForInSet(ir.Node node) => null;
/// Generate [SourceInformation] for the operator `[]` access in [node].
- SourceInformation buildIndex(ir.Node node) => null;
+ SourceInformation? buildIndex(ir.Node node) => null;
/// Generate [SourceInformation] for the operator `[]=` assignment in [node].
- SourceInformation buildIndexSet(ir.Node node) => null;
+ SourceInformation? buildIndexSet(ir.Node node) => null;
/// Generate [SourceInformation] for the binary operation in [node].
- SourceInformation buildBinary(ir.Node node) => null;
+ SourceInformation? buildBinary(ir.Node node) => null;
/// Generate [SourceInformation] for the unary operation in [node].
- SourceInformation buildUnary(ir.Node node) => null;
+ SourceInformation? buildUnary(ir.Node node) => null;
/// Generate [SourceInformation] for the try statement in [node].
- SourceInformation buildTry(ir.Node node) => null;
+ SourceInformation? buildTry(ir.Node node) => null;
/// Generate [SourceInformation] for the unary operator in [node].
- SourceInformation buildCatch(ir.Node node) => null;
+ SourceInformation? buildCatch(ir.Node node) => null;
/// Generate [SourceInformation] for the is-test in [node].
- SourceInformation buildIs(ir.Node node) => null;
+ SourceInformation? buildIs(ir.Node node) => null;
/// Generate [SourceInformation] for the as-cast in [node].
- SourceInformation buildAs(ir.Node node) => null;
+ SourceInformation? buildAs(ir.Node node) => null;
/// Generate [SourceInformation] for the switch statement [node].
- SourceInformation buildSwitch(ir.Node node) => null;
+ SourceInformation? buildSwitch(ir.Node node) => null;
/// Generate [SourceInformation] for the switch case in [node].
- SourceInformation buildSwitchCase(ir.Node node) => null;
+ SourceInformation? buildSwitchCase(ir.Node node) => null;
/// Generate [SourceInformation] for the list literal in [node].
- SourceInformation buildListLiteral(ir.Node node) => null;
+ SourceInformation? buildListLiteral(ir.Node node) => null;
/// Generate [SourceInformation] for the break/continue in [node].
- SourceInformation buildGoto(ir.Node node) => null;
+ SourceInformation? buildGoto(ir.Node node) => null;
}
/// A location in a source file.
@@ -261,7 +257,13 @@
const SourceLocation();
/// The absolute URI of the source file of this source location.
- Uri get sourceUri;
+
+ // TODO(48820): [sourceUri] is nullable due to `NoSourceLocationMarker`. We
+ // would not need nullability of we could replace all
+ // `NoSourceLocationMarker`s with `null`, or rearranged the `SourceLocation`
+ // class hierarchy. `NoSourceLocationMarker` and `null` have different effects
+ // on the generated source-map files.
+ Uri? get sourceUri;
/// The character offset of the this source location into the source file.
int get offset;
@@ -273,41 +275,38 @@
int get column;
/// The name associated with this source location, if any.
- String get sourceName;
+ String? get sourceName;
static SourceLocation readFromDataSource(DataSourceReader source) {
int hasSourceLocation = source.readInt();
- if (hasSourceLocation == 0) {
- return null;
- } else if (hasSourceLocation == 1) {
+ if (hasSourceLocation == 1) {
return const NoSourceLocationMarker();
- } else {
- assert(hasSourceLocation == 2);
+ } else if (hasSourceLocation == 2) {
source.begin(tag);
Uri sourceUri = source.readUri();
int offset = source.readInt();
int line = source.readInt();
int column = source.readInt();
- String sourceName = source.readString();
+ String? sourceName = source.readStringOrNull();
source.end(tag);
return DirectSourceLocation(sourceUri, offset, line, column, sourceName);
+ } else {
+ throw StateError('Unknown hasSourceLocation value: $hasSourceLocation');
}
}
static void writeToDataSink(
DataSinkWriter sink, SourceLocation sourceLocation) {
- if (sourceLocation == null) {
- sink.writeInt(0);
- } else if (sourceLocation is NoSourceLocationMarker) {
+ if (sourceLocation is NoSourceLocationMarker) {
sink.writeInt(1);
} else {
sink.writeInt(2);
sink.begin(tag);
- sink.writeUri(sourceLocation.sourceUri);
+ sink.writeUri(sourceLocation.sourceUri!);
sink.writeInt(sourceLocation.offset);
sink.writeInt(sourceLocation.line);
sink.writeInt(sourceLocation.column);
- sink.writeString(sourceLocation.sourceName);
+ sink.writeStringOrNull(sourceLocation.sourceName);
sink.end(tag);
}
}
@@ -328,7 +327,7 @@
sourceName == other.sourceName;
}
- String get shortText => '${sourceUri?.pathSegments?.last}:[$line,$column]';
+ String get shortText => '${sourceUri?.pathSegments.last}:[$line,$column]';
@override
String toString() => '${sourceUri}:[${line},${column}]';
@@ -348,7 +347,7 @@
final int column;
@override
- final String sourceName;
+ final String? sourceName;
DirectSourceLocation(
this.sourceUri, this.offset, this.line, this.column, this.sourceName);
@@ -356,37 +355,36 @@
/// A location in a source file.
abstract class AbstractSourceLocation extends SourceLocation {
- final SourceFile _sourceFile;
- ir.Location _location;
+ final SourceFile? _sourceFile;
+ ir.Location? _location;
- AbstractSourceLocation(this._sourceFile) {
+ AbstractSourceLocation(SourceFile this._sourceFile) {
assert(
- offset < _sourceFile.length,
+ offset < _sourceFile!.length,
failedAt(
SourceSpan(sourceUri, 0, 0),
"Invalid source location in ${sourceUri}: "
- "offset=$offset, length=${_sourceFile.length}."));
+ "offset=$offset, length=${_sourceFile!.length}."));
}
- AbstractSourceLocation.fromLocation(this._location) : _sourceFile = null;
-
- AbstractSourceLocation.fromOther(AbstractSourceLocation location)
- : this.fromLocation(location._location);
+ AbstractSourceLocation.fromLocation(ir.Location location)
+ : _location = location,
+ _sourceFile = null;
@override
- Uri get sourceUri => _sourceFile.uri;
+ Uri get sourceUri => _sourceFile!.uri;
@override
int get offset;
@override
- int get line => (_location ??= _sourceFile.getLocation(offset)).line;
+ int get line => (_location ??= _sourceFile!.getLocation(offset)).line;
@override
- int get column => (_location ??= _sourceFile.getLocation(offset)).column;
+ int get column => (_location ??= _sourceFile!.getLocation(offset)).column;
@override
- String get sourceName;
+ String? get sourceName;
@override
String get shortText => '${sourceUri.pathSegments.last}:[$line,$column]';
@@ -415,34 +413,35 @@
/// it is used to name the parameter stub for [element].
// TODO(johnniwinther): Merge this with `computeKernelElementNameForSourceMaps`
// when the old frontend is removed.
-String computeElementNameForSourceMaps(Entity element,
- [CallStructure callStructure]) {
+String? computeElementNameForSourceMaps(Entity element,
+ [CallStructure? callStructure]) {
if (element is ClassEntity) {
return element.name;
- } else if (element is MemberEntity) {
+ }
+ if (element is MemberEntity) {
+ final enclosingClass = element.enclosingClass;
String suffix = computeStubSuffix(callStructure);
if (element is ConstructorEntity || element is ConstructorBodyEntity) {
- String className = element.enclosingClass.name;
+ String className = enclosingClass!.name;
if (element.name == '') {
return className;
}
return '$className.${element.name}$suffix';
- } else if (element.enclosingClass != null) {
- if (element.enclosingClass.isClosure) {
- return computeElementNameForSourceMaps(
- element.enclosingClass, callStructure);
- }
- return '${element.enclosingClass.name}.${element.name}$suffix';
- } else {
- return '${element.name}$suffix';
}
+ if (enclosingClass != null) {
+ if (enclosingClass.isClosure) {
+ return computeElementNameForSourceMaps(enclosingClass, callStructure);
+ }
+ return '${enclosingClass.name}.${element.name}$suffix';
+ }
+ return '${element.name}$suffix';
}
// TODO(redemption): Create element names from kernel locals and closures.
return element.name;
}
/// Compute the suffix used for a parameter stub for [callStructure].
-String computeStubSuffix(CallStructure callStructure) {
+String computeStubSuffix(CallStructure? callStructure) {
if (callStructure == null) return '';
StringBuffer sb = StringBuffer();
sb.write(r'[function-entry$');
@@ -459,19 +458,19 @@
const NoSourceLocationMarker();
@override
- Uri get sourceUri => null;
+ Uri? get sourceUri => null;
@override
- String get sourceName => null;
+ int get column => 0;
@override
- int get column => null;
+ int get line => 0;
@override
- int get line => null;
+ int get offset => 0;
@override
- int get offset => null;
+ String? get sourceName => null;
String get shortName => '<no-location>';
@@ -486,10 +485,10 @@
/// deobfuscate production stack traces.
class FrameEntry {
/// For push operations, the location of the inlining call, otherwise null.
- final SourceLocation pushLocation;
+ final SourceLocation? pushLocation;
/// For push operations, the inlined method name, otherwise null.
- final String inlinedMethodName;
+ final String? inlinedMethodName;
/// Whether a pop is the last pop that makes the inlining stack empty.
final bool isEmptyPop;
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 7e48ef3..349d065 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -2,15 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.10
-
library js;
import 'package:js_ast/js_ast.dart';
import '../common.dart';
import '../options.dart';
-import '../dump_info.dart' show DumpInfoTask;
+import '../dump_info_javascript_monitor.dart' show DumpInfoJavaScriptMonitor;
import '../io/code_output.dart' show CodeBuffer, CodeOutputListener;
import 'js_source_mapping.dart';
@@ -35,7 +33,7 @@
CodeBuffer createCodeBuffer(Node node, CompilerOptions compilerOptions,
JavaScriptSourceInformationStrategy sourceInformationStrategy,
- {DumpInfoTask monitor,
+ {DumpInfoJavaScriptMonitor? monitor,
bool allowVariableMinification = true,
List<CodeOutputListener> listeners = const []}) {
JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
@@ -55,7 +53,7 @@
}
class Dart2JSJavaScriptPrintingContext implements JavaScriptPrintingContext {
- final DumpInfoTask monitor;
+ final DumpInfoJavaScriptMonitor? monitor;
final CodeBuffer outBuffer;
final CodePositionListener codePositionListener;
@@ -81,7 +79,7 @@
@override
void exitNode(
- Node node, int startPosition, int endPosition, int closingPosition) {
+ Node node, int startPosition, int endPosition, int? closingPosition) {
monitor?.exitNode(node, startPosition, endPosition, closingPosition);
codePositionListener.onPositions(
node, startPosition, endPosition, closingPosition);
@@ -135,7 +133,8 @@
final Node tree;
final bool _enableMinification;
final bool _protectForEval;
- LiteralString _cachedLiteral;
+ // TODO(48820): Can be `late final` with initializer.
+ LiteralString? _cachedLiteral;
@override
Iterable<Node> get containedNodes => [tree];
@@ -147,22 +146,20 @@
/// parenthesis. The result is also escaped.
UnparsedNode(this.tree, this._enableMinification, this._protectForEval);
- LiteralString get _literal {
- if (_cachedLiteral == null) {
- String text = prettyPrint(tree, enableMinification: _enableMinification);
- if (_protectForEval) {
- if (tree is Fun) text = '($text)';
- if (tree is LiteralExpression) {
- LiteralExpression literalExpression = tree;
- String template = literalExpression.template;
- if (template.startsWith("function ") || template.startsWith("{")) {
- text = '($text)';
- }
+ LiteralString get _literal => _cachedLiteral ??= _create(tree);
+
+ LiteralString _create(Node node) {
+ String text = prettyPrint(node, enableMinification: _enableMinification);
+ if (_protectForEval) {
+ if (node is Fun) text = '($text)';
+ if (node is LiteralExpression) {
+ String template = node.template;
+ if (template.startsWith("function ") || template.startsWith("{")) {
+ text = '($text)';
}
}
- _cachedLiteral = js.string(text);
}
- return _cachedLiteral;
+ return js.string(text);
}
@override
@@ -189,10 +186,9 @@
node = call.target;
}
if (node is PropertyAccess) {
- PropertyAccess access = node;
- if (access.receiver is InterpolatedExpression) {
- InterpolatedExpression hole = access.receiver;
- return hole.isPositional && hole.nameOrPosition == 0;
+ final receiver = node.receiver;
+ if (receiver is InterpolatedExpression) {
+ return receiver.isPositional && receiver.nameOrPosition == 0;
}
}
return false;
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index fc932c3..1dbd7b2 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.10
-
library js.source_mapping;
import '../io/code_output.dart'
@@ -33,7 +31,8 @@
class SourceInformationReader {
const SourceInformationReader();
- SourceInformation getSourceInformation(Node node) => node.sourceInformation;
+ SourceInformation? getSourceInformation(Node node) =>
+ node.sourceInformation as SourceInformation?;
}
/// An observer of code positions of printed JavaScript [Node]s.
@@ -50,7 +49,7 @@
///
/// The nodes are seen in post-traversal order.
void onPositions(
- Node node, int startPosition, int endPosition, int closingPosition) {}
+ Node node, int startPosition, int endPosition, int? closingPosition) {}
}
/// Interface for creating [SourceMapper]s for multiple source information
@@ -79,7 +78,7 @@
/// Associate [codeOffset] with an inlining call at [sourceLocation].
void registerPush(
- int codeOffset, SourceLocation sourceLocation, String inlinedMethodName);
+ int codeOffset, SourceLocation? sourceLocation, String inlinedMethodName);
/// Associate [codeOffset] with an inlining return.
///
@@ -101,8 +100,8 @@
}
@override
- void registerPush(
- int codeOffset, SourceLocation sourceLocation, String inlinedMethodName) {
+ void registerPush(int codeOffset, SourceLocation? sourceLocation,
+ String inlinedMethodName) {
sourceLocations.addPush(codeOffset, sourceLocation, inlinedMethodName);
}
diff --git a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
index 22e8329..2e24fe1 100644
--- a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
+++ b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
@@ -110,7 +110,7 @@
@override
js.Expression get value {
assert(isFinalized, '$this is unassigned');
- return _value;
+ return _value /*!*/;
}
@override
@@ -175,7 +175,7 @@
}
@override
- Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
+ Iterable<js.Node> get containedNodes => isFinalized ? [value] : const [];
}
/// A [DeferredHolderParameter] is a deferred JavaScript expression determined
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 3c4f5fa..f49b6ce 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -514,7 +514,7 @@
}
Map<String, String> createMinifiedGlobalNameMap() {
- var map = <String, String>{};
+ var map = <String, String /*!*/ >{};
userGlobals.forEach((entity, jsName) {
_registerName(map, jsName, entity.name);
});
@@ -817,11 +817,11 @@
}
@override
- jsAst.Name globalPropertyNameForMember(MemberEntity element) =>
+ jsAst.Name globalPropertyNameForMember(MemberEntity /*!*/ element) =>
_disambiguateGlobalMember(element);
@override
- jsAst.Name globalPropertyNameForClass(ClassEntity element) =>
+ jsAst.Name globalPropertyNameForClass(ClassEntity /*!*/ element) =>
_disambiguateGlobalType(element);
@override
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index b5bf78d..a9db00c 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -408,7 +408,7 @@
void writeMainFragment(MainFragment fragment, js.Statement code,
{bool isSplit}) {
LocationCollector locationCollector;
- List<CodeOutputListener> codeOutputListeners;
+ List<CodeOutputListener /*!*/ > codeOutputListeners;
if (_shouldGenerateSourceMap) {
_task.measureSubtask('source-maps', () {
locationCollector = LocationCollector();
@@ -478,7 +478,7 @@
FinalizedFragment fragment,
List<EmittedCodeFragment> fragmentCode,
Map<CodeFragment, String> fragmentHashes) {
- List<CodeOutputListener> outputListeners = [];
+ List<CodeOutputListener /*!*/ > outputListeners = [];
LocationCollector locationCollector;
if (_shouldGenerateSourceMap) {
_task.measureSubtask('source-maps', () {
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
index efa9bb1..ccb047e 100644
--- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -76,9 +76,9 @@
void writeTreeNodeMapInContext<V>(Map<ir.TreeNode, V>? map, void f(V value),
{bool allowNull = false});
- void writeCached<E extends Object>(E value, void f(E value));
+ void writeCached<E extends Object>(E? value, void f(E value));
- void writeList<E extends Object>(Iterable<E> values, void f(E value),
+ void writeList<E extends Object>(Iterable<E>? values, void f(E value),
{bool allowNull = false});
}
@@ -117,6 +117,7 @@
Map<K, V>? readTreeNodeMapInContextOrNull<K extends ir.TreeNode, V>(V f());
E readCached<E extends Object>(E f());
+ E? readCachedOrNull<E extends Object>(E f());
List<E> readList<E extends Object>(E f());
List<E>? readListOrNull<E extends Object>(E f());
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
index 214b6e9..8c5e1ba 100644
--- a/pkg/compiler/lib/src/serialization/sink.dart
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -113,7 +113,7 @@
/// Writes a reference to [value] to this data sink. If [value] has not yet
/// been serialized, [f] is called to serialize the value itself.
@override
- void writeCached<E>(E value, void f(E value)) {
+ void writeCached<E>(E /*?*/ value, void f(E value)) {
IndexedSink sink = _generalCaches[E] ??= _createSink<E>();
sink.write(value, (v) => f(v));
}
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index 2d0855c..efe6512 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -173,6 +173,15 @@
/// not yet been deserialized, [f] is called to deserialize the value itself.
@override
E readCached<E>(E f()) {
+ E /*?*/ value = readCachedOrNull(f);
+ if (value == null) throw StateError("Unexpected 'null' for $E");
+ return value;
+ }
+
+ /// Reads a reference to an [E] value from this data source. If the value has
+ /// not yet been deserialized, [f] is called to deserialize the value itself.
+ @override
+ E /*?*/ readCachedOrNull<E>(E f()) {
IndexedSource source = _generalCaches[E] ??= _createSource<E>();
return source.read(f);
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 3755c74..b44fc3c 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -981,7 +981,8 @@
if (ignoreAllocatorAnalysis ||
!_fieldAnalysis.getFieldData(field).isInitializedInAllocator) {
- if (node.initializer == null) {
+ final initializer = node.initializer;
+ if (initializer == null) {
constructorData.fieldValues[field] =
graph.addConstantNull(closedWorld);
} else {
@@ -989,9 +990,10 @@
// class type parameters are accessed as values.
// TODO(sra): It would be sufficient to know the context was a field
// initializer.
- _inlinedFrom(field,
- _sourceInformationBuilder.buildAssignment(node.initializer), () {
- node.initializer.accept(this);
+ _inlinedFrom(
+ field, _sourceInformationBuilder.buildAssignment(initializer),
+ () {
+ initializer.accept(this);
constructorData.fieldValues[field] = pop();
});
}
@@ -1183,7 +1185,7 @@
}
/// Constructs a special signature function for a closure.
- void _buildMethodSignatureNewRti(ir.FunctionNode originalClosureNode) {
+ void _buildMethodSignatureNewRti(ir.FunctionNode /*!*/ originalClosureNode) {
// The signature function has no corresponding ir.Node, so we just use the
// targetElement to set up the type environment.
_openFunction(targetElement, checks: TargetChecks.none);
@@ -1586,7 +1588,7 @@
void _openFunction(MemberEntity member,
{ir.FunctionNode functionNode,
ParameterStructure parameterStructure,
- TargetChecks checks}) {
+ /*required*/ TargetChecks checks}) {
assert(checks != null);
Map<Local, AbstractValue> parameterMap = {};
@@ -1640,6 +1642,8 @@
// check. The null check is added before the argument type checks since in
// strong mode, the parameter type might be non-nullable.
if (member.name == '==') {
+ if (functionNode == null)
+ throw StateError("'==' should have functionNode");
if (!_commonElements.operatorEqHandlesNullArgument(member)) {
_handleIf(
visitCondition: () {
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 10d97e2..5dc3ae7 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -74,6 +74,12 @@
help: 'The path to the package resolution configuration file, which '
'supplies a mapping of package names\ninto paths.',
hide: !verbose,
+ )
+ ..addOption(
+ 'sdk-path',
+ valueHelp: 'path',
+ help: 'The path to the Dart SDK.',
+ hide: !verbose,
);
}
@@ -110,9 +116,30 @@
var progress =
machineFormat ? null : log.progress('Analyzing $targetsNames');
+ io.Directory sdkPath;
+ if (args.wasParsed('sdk-path')) {
+ sdkPath = io.Directory(args['sdk-path'] as String);
+ if (!sdkPath.existsSync()) {
+ usageException('Invalid Dart SDK path: $sdkPath');
+ }
+ final snapshotPath = path.join(
+ sdkPath.path,
+ 'bin',
+ 'snapshots',
+ 'analysis_server.dart.snapshot',
+ );
+ if (!io.File(snapshotPath).existsSync()) {
+ usageException(
+ 'Invalid Dart SDK path has no analysis_server.dart.snapshot file: '
+ '$sdkPath');
+ }
+ } else {
+ sdkPath = io.Directory(sdk.sdkPath);
+ }
+
final AnalysisServer server = AnalysisServer(
_packagesFile(),
- io.Directory(sdk.sdkPath),
+ sdkPath,
targets,
cacheDirectoryPath: args['cache'],
commandName: 'analyze',
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 2ca1456..0513849 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -5,6 +5,7 @@
import 'package:cli_util/cli_logging.dart';
import 'package:dartdev/src/analysis_server.dart';
import 'package:dartdev/src/commands/analyze.dart';
+import 'package:dartdev/src/sdk.dart';
import 'package:test/test.dart';
import '../utils.dart';
@@ -355,6 +356,25 @@
expect(result.stdout, contains('1 issue found.'));
});
+ test('--sdk-path value does not exist', () async {
+ p = project();
+ var result = await p.run(['analyze', '--sdk-path=bad']);
+
+ expect(result.exitCode, 64);
+ expect(result.stderr, contains('Invalid Dart SDK path: bad'));
+ expect(result.stderr, contains(_analyzeUsageText));
+ });
+
+ test('--sdk-path', () async {
+ var sdkPath = sdk.sdkPath;
+ p = project();
+ var result = await p.run(['analyze', '--sdk-path=$sdkPath']);
+
+ expect(result.exitCode, 0);
+ expect(result.stdout, contains('No issues found!'));
+ expect(result.stderr, isEmpty);
+ });
+
test('--verbose', () async {
p = project(mainSrc: '''
int f() {
diff --git a/tools/VERSION b/tools/VERSION
index 33d92f0..525543e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 91
+PRERELEASE 92
PRERELEASE_PATCH 0
\ No newline at end of file