Support references to static getters in the summary linker.
R=scheglov@google.com
Review URL: https://codereview.chromium.org/1944733002 .
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 18960c0..e68b5df 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -271,6 +271,9 @@
hasBeenInferred = !enclosingElement.isInBuildUnit;
@override
+ List<PropertyAccessorElementForLink> get accessors;
+
+ @override
ConstructorElementForLink get asConstructor => unnamedConstructor;
@override
@@ -323,6 +326,12 @@
_containedNames[field.name] = field;
}
}
+ for (PropertyAccessorElementForLink accessor in accessors) {
+ if (accessor.isStatic && !accessor.isSynthetic) {
+ // TODO(paulberry): add synthetic elements too?
+ _containedNames[accessor.name] = accessor;
+ }
+ }
// TODO(paulberry): add methods.
}
return _containedNames.putIfAbsent(
@@ -3461,7 +3470,7 @@
* linking.
*/
abstract class PropertyAccessorElementForLink
- implements PropertyAccessorElementImpl {
+ implements PropertyAccessorElementImpl, ReferenceableElementForLink {
void link(CompilationUnitElementInBuildUnit compilationUnit);
}
@@ -3482,6 +3491,18 @@
unlinkedExecutable);
@override
+ ConstructorElementForLink get asConstructor => null;
+
+ @override
+ ConstVariableNode get asConstVariable => null;
+
+ @override
+ DartType get asStaticType => returnType;
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode => null;
+
+ @override
PropertyAccessorElementForLink_Executable get correspondingGetter =>
variable.getter;
@@ -3498,6 +3519,15 @@
UnlinkedExecutableKind.getter ? ElementKind.GETTER : ElementKind.SETTER;
@override
+ DartType buildType(DartType getTypeArgument(int i),
+ List<int> implicitFunctionTypeIndices) =>
+ DynamicTypeImpl.instance;
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) =>
+ UndefinedElementForLink.instance;
+
+ @override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
diff --git a/pkg/analyzer/lib/src/summary/prelink.dart b/pkg/analyzer/lib/src/summary/prelink.dart
index e98b64b..ec947f0 100644
--- a/pkg/analyzer/lib/src/summary/prelink.dart
+++ b/pkg/analyzer/lib/src/summary/prelink.dart
@@ -274,6 +274,9 @@
UnlinkedExecutableKind.functionOrMethod &&
executable.isStatic) {
kind = ReferenceKind.method;
+ } else if (executable.kind == UnlinkedExecutableKind.getter &&
+ executable.isStatic) {
+ kind = ReferenceKind.propertyAccessor;
}
if (kind != null && executable.name.isNotEmpty) {
namespace[executable.name] = new _Meaning(
diff --git a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
index 5cb6e8e5..684113e 100644
--- a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
+++ b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
@@ -83,14 +83,15 @@
}
if (member is MethodDeclaration &&
member.isStatic &&
- !member.isGetter &&
!member.isSetter &&
!member.isOperator) {
String name = member.name.name;
if (isPublic(name)) {
cls.members.add(new UnlinkedPublicNameBuilder(
name: name,
- kind: ReferenceKind.method,
+ kind: member.isGetter
+ ? ReferenceKind.propertyAccessor
+ : ReferenceKind.method,
numTypeParameters:
member.typeParameters?.typeParameters?.length ?? 0));
}
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index e0e5c95..b8828ec 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -609,6 +609,7 @@
List<UnlinkedPublicNameBuilder> bs = <UnlinkedPublicNameBuilder>[];
for (FieldElement field in cls.fields) {
if (field.isStatic && field.isConst && field.isPublic) {
+ // TODO(paulberry): include non-consts
// TODO(paulberry): should numTypeParameters include class params?
bs.add(new UnlinkedPublicNameBuilder(
name: field.name,
@@ -625,6 +626,17 @@
numTypeParameters: method.typeParameters.length));
}
}
+ for (PropertyAccessorElement accessor in cls.accessors) {
+ if (accessor.isStatic &&
+ accessor.isGetter &&
+ accessor.isPublic &&
+ !accessor.isSynthetic) {
+ // TODO(paulberry): combine with field code above.
+ // TODO(paulberry): should numTypeParameters include class params?
+ bs.add(new UnlinkedPublicNameBuilder(
+ name: accessor.name, kind: ReferenceKind.propertyAccessor));
+ }
+ }
for (ConstructorElement constructor in cls.constructors) {
if (constructor.isPublic && constructor.name.isNotEmpty) {
// TODO(paulberry): should numTypeParameters include class params?
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 23dbd71..c3ae04d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -647,7 +647,7 @@
return;
}
expect(original, isNotNull);
- expect(resynthesized, isNotNull);
+ expect(resynthesized, isNotNull, reason: desc);
expect(rImpl.runtimeType, oImpl.runtimeType);
expect(resynthesized.kind, original.kind);
expect(resynthesized.location, original.location, reason: desc);
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index cf86321..7e25284 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -2819,6 +2819,73 @@
]);
}
+ test_constExpr_pushReference_staticGetter() {
+ UnlinkedVariable variable = serializeVariableText('''
+class C {
+ static int get x => null;
+}
+const v = C.x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'x',
+ expectedKind: ReferenceKind.propertyAccessor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_staticGetter_imported() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static int get x => null;
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = C.x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'x',
+ expectedKind: ReferenceKind.propertyAccessor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+ absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+ ])
+ ]);
+ }
+
+ test_constExpr_pushReference_staticGetter_imported_withPrefix() {
+ addNamedSource(
+ '/a.dart',
+ '''
+class C {
+ static int get x => null;
+}
+''');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.C.x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'x',
+ expectedKind: ReferenceKind.propertyAccessor,
+ prefixExpectations: [
+ new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+ absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+ new _PrefixExpectation(ReferenceKind.prefix, 'p')
+ ])
+ ]);
+ }
+
test_constExpr_pushReference_staticMethod() {
UnlinkedVariable variable = serializeVariableText('''
class C {
@@ -2956,6 +3023,48 @@
]);
}
+ test_constExpr_pushReference_topLevelGetter() {
+ UnlinkedVariable variable = serializeVariableText('''
+int get x => null;
+const v = x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, null, null, 'x',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor)
+ ]);
+ }
+
+ test_constExpr_pushReference_topLevelGetter_imported() {
+ addNamedSource('/a.dart', 'int get x => null;');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'x',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor)
+ ]);
+ }
+
+ test_constExpr_pushReference_topLevelGetter_imported_withPrefix() {
+ addNamedSource('/a.dart', 'int get x => null;');
+ UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.x;
+''');
+ _assertUnlinkedConst(variable.constExpr, operators: [
+ UnlinkedConstOperation.pushReference
+ ], referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'x',
+ expectedKind: ReferenceKind.topLevelPropertyAccessor,
+ expectedPrefix: 'p')
+ ]);
+ }
+
test_constExpr_pushReference_topLevelVariable() {
UnlinkedVariable variable = serializeVariableText('''
const int a = 1;
@@ -5282,9 +5391,13 @@
expect(executable.isAsynchronous, isFalse);
expect(executable.isExternal, isFalse);
expect(executable.isGenerator, isFalse);
+ expect(executable.isStatic, isFalse);
_assertCodeRange(executable.codeRange, 10, 15);
expect(findVariable('f', variables: cls.fields), isNull);
expect(findExecutable('f=', executables: cls.executables), isNull);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members, isEmpty);
}
test_executable_member_getter_external() {
@@ -5294,6 +5407,25 @@
expect(executable.isExternal, isTrue);
}
+ test_executable_member_getter_static() {
+ UnlinkedClass cls =
+ serializeClassText('class C { static int get f => 1; }');
+ UnlinkedExecutable executable =
+ findExecutable('f', executables: cls.executables, failIfAbsent: true);
+ expect(executable.isStatic, isTrue);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'f');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
+ ReferenceKind.propertyAccessor);
+ expect(
+ unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
+ 0);
+ expect(
+ unlinkedUnits[0].publicNamespace.names[0].members[0].members, isEmpty);
+ }
+
test_executable_member_setter() {
UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
UnlinkedExecutable executable =
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 3f7c009..d1ebb09 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1246,6 +1246,17 @@
''');
}
+ void test_fieldRefersToStaticGetter() {
+ var mainUnit = checkFile('''
+class C {
+ final x = _x;
+ static int get _x => null;
+}
+''');
+ var x = mainUnit.types[0].fields[0];
+ expect(x.type.toString(), 'int');
+ }
+
void test_genericMethods_basicDownwardInference() {
checkFile(r'''
/*=T*/ f/*<S, T>*/(/*=S*/ s) => null;