Record references in expressions.
This probably covers all expressions.
But I will run over larger codebase later to be sure.
R=brianwilkerson@google.com
Change-Id: I1c8e7ff4c717507e83637b91e9664a12aaa97d43
Reviewed-on: https://dart-review.googlesource.com/c/86506
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
index 26cb1fa..308b816 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
@@ -274,7 +274,8 @@
var builder = _newApiSignatureBuilder();
builder.addString(node.name.name);
_appendTokens(builder, node.leftBracket, node.rightBracket);
- fieldDependencies = Dependencies(builder.toByteList(), [], [], [], []);
+ var tokenSignature = builder.toByteList();
+ fieldDependencies = Dependencies(tokenSignature, [], [], [], [], []);
}
var members = <Node>[];
@@ -305,7 +306,7 @@
var enumNode = Node(
LibraryQualifiedName(uri, node.name.name),
NodeKind.ENUM,
- Dependencies(enumTokenSignature, [], [], [], []),
+ Dependencies(enumTokenSignature, [], [], [], [], []),
Dependencies.none,
);
enumNode.setClassMembers(members);
@@ -640,6 +641,7 @@
importPrefixes,
importPrefixedReferencedNames,
const [],
+ const [],
);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
index 71791d6..6fe7d43 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
@@ -16,46 +16,38 @@
/// will notice added overrides in the target class, or anywhere in between.
final LibraryQualifiedName target;
- /// Whether the explicit `super` was used as the target.
- /// The [target] is the enclosing class.
- final bool targetSuper;
-
/// The name referenced in the [target].
final String name;
@override
final int hashCode;
- ClassMemberReference(this.target, this.targetSuper, this.name)
+ ClassMemberReference(this.target, this.name)
: hashCode = JenkinsSmiHash.hash2(target.hashCode, name.hashCode);
@override
bool operator ==(other) {
return other is ClassMemberReference &&
other.target == target &&
- other.targetSuper == targetSuper &&
other.name == name;
}
@override
String toString() {
- return '($target, $name, super: $targetSuper)';
+ return '($target, $name)';
}
static int compare(ClassMemberReference first, ClassMemberReference second) {
var result = LibraryQualifiedName.compare(first.target, second.target);
if (result != 0) return result;
- if (first.targetSuper && !second.targetSuper) return -1;
- if (!first.targetSuper && second.targetSuper) return 1;
-
return first.name.compareTo(second.name);
}
}
/// The dependencies of the API or implementation portion of a node.
class Dependencies {
- static final none = Dependencies([], [], [], [], []);
+ static final none = Dependencies([], [], [], [], [], []);
/// The token signature of this portion of the node. It depends on all
/// tokens that might affect the node API or implementation resolution.
@@ -79,6 +71,11 @@
/// This list is sorted.
final List<List<String>> importPrefixedReferencedNames;
+ /// The names that appear prefixed with `super` in this portion of the node.
+ ///
+ /// This list is sorted.
+ final List<String> superReferencedNames;
+
/// The class members referenced in this portion of the node.
///
/// This list is sorted.
@@ -98,6 +95,7 @@
this.unprefixedReferencedNames,
this.importPrefixes,
this.importPrefixedReferencedNames,
+ this.superReferencedNames,
this.classMemberReferences);
String get tokenSignatureHex => hex.encode(tokenSignature);
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
index 2ad3cb6..7bd603d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/dependency/node.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
/// Collector of information about external nodes referenced by a node.
///
@@ -28,6 +30,9 @@
/// It is filled by [addImportPrefix] and shared across all nodes.
List<_ReferencedImportPrefixedNames> _importPrefixedReferences = [];
+ /// The list of names that are referenced with `super`.
+ _NameSet _superReferences = _NameSet();
+
/// The set of referenced class members.
_ClassMemberReferenceSet _memberReferences = new _ClassMemberReferenceSet();
@@ -59,7 +64,7 @@
_visitExpression(expression);
}
if (formalParameters != null) {
- _visitFormalParameters(formalParameters);
+ _visitFormalParameterList(formalParameters);
}
if (functionBody != null) {
_visitFunctionBody(functionBody);
@@ -85,6 +90,9 @@
import.clear();
}
+ var superReferencedNames = _superReferences.toList();
+ _superReferences = _NameSet();
+
var classMemberReferences = _memberReferences.toList();
_memberReferences = _ClassMemberReferenceSet();
@@ -93,6 +101,7 @@
unprefixedReferencedNames,
importPrefixes,
importPrefixedReferencedNames,
+ superReferencedNames,
classMemberReferences,
);
}
@@ -109,10 +118,9 @@
return null;
}
- void _recordClassMemberReference(
- DartType targetType, bool withSuper, String name) {
+ void _recordClassMemberReference(DartType targetType, String name) {
if (targetType is InterfaceType) {
- _memberReferences.add(targetType, withSuper, name);
+ _memberReferences.add(targetType, name);
}
}
@@ -122,53 +130,121 @@
_unprefixedReferences.add(name);
}
+ void _visitAdjacentStrings(AdjacentStrings node) {
+ var strings = node.strings;
+ for (var i = 0; i < strings.length; i++) {
+ var string = strings[i];
+ _visitExpression(string);
+ }
+ }
+
+ void _visitArgumentList(ArgumentList argumentList) {
+ var arguments = argumentList.arguments;
+ for (var i = 0; i < arguments.length; i++) {
+ var argument = arguments[i];
+ _visitExpression(argument);
+ }
+ }
+
+ void _visitCascadeExpression(CascadeExpression node) {
+ _visitExpression(node.target);
+ var sections = node.cascadeSections;
+ for (var i = 0; i < sections.length; i++) {
+ var section = sections[i];
+ _visitExpression(section);
+ }
+ }
+
void _visitExpression(Expression node) {
if (node == null) return;
- if (node is AssignmentExpression) {
+ if (node is AdjacentStrings) {
+ _visitAdjacentStrings(node);
+ } else if (node is AsExpression) {
+ _visitExpression(node.expression);
+ _visitTypeAnnotation(node.type);
+ } else if (node is AssignmentExpression) {
_visitExpression(node.leftHandSide);
_visitExpression(node.rightHandSide);
- // TODO(scheglov) operator
+ var assignmentType = node.operator.type;
+ if (assignmentType != TokenType.EQ &&
+ assignmentType != TokenType.QUESTION_QUESTION_EQ) {
+ var operatorType = operatorFromCompoundAssignment(assignmentType);
+ _recordClassMemberReference(
+ node.leftHandSide.staticType,
+ operatorType.lexeme,
+ );
+ }
+ } else if (node is AwaitExpression) {
+ _visitExpression(node.expression);
} else if (node is BinaryExpression) {
_visitExpression(node.leftOperand);
_visitExpression(node.rightOperand);
_recordClassMemberReference(
node.leftOperand.staticType,
- false,
node.operator.lexeme,
);
} else if (node is BooleanLiteral) {
// no dependencies
+ } else if (node is CascadeExpression) {
+ _visitCascadeExpression(node);
} else if (node is ConditionalExpression) {
- // TODO(scheglov) test
_visitExpression(node.condition);
_visitExpression(node.thenExpression);
_visitExpression(node.elseExpression);
} else if (node is DoubleLiteral) {
// no dependencies
+ } else if (node is FunctionExpression) {
+ _visitFunctionExpression(node);
+ } else if (node is FunctionExpressionInvocation) {
+ _visitExpression(node.function);
+ _visitTypeArguments(node.typeArguments);
+ _visitArgumentList(node.argumentList);
} else if (node is IndexExpression) {
_visitExpression(node.target);
_visitExpression(node.index);
+ } else if (node is InstanceCreationExpression) {
+ _visitInstanceCreationExpression(node);
} else if (node is IntegerLiteral) {
// no dependencies
+ } else if (node is IsExpression) {
+ _visitExpression(node.expression);
+ _visitTypeAnnotation(node.type);
} else if (node is ListLiteral) {
_visitListLiteral(node);
} else if (node is MapLiteral) {
_visitMapLiteral(node);
} else if (node is MethodInvocation) {
_visitMethodInvocation(node);
+ } else if (node is NamedExpression) {
+ _visitExpression(node.expression);
+ } else if (node is NullLiteral) {
+ // no dependencies
} else if (node is ParenthesizedExpression) {
_visitExpression(node.expression);
+ } else if (node is PostfixExpression) {
+ _visitPostfixExpression(node);
} else if (node is PrefixExpression) {
_visitPrefixExpression(node);
} else if (node is PrefixedIdentifier) {
_visitPrefixedIdentifier(node);
+ } else if (node is PropertyAccess) {
+ _visitPropertyAccess(node);
} else if (node is SetLiteral) {
_visitSetLiteral(node);
} else if (node is SimpleIdentifier) {
_visitSimpleIdentifier(node);
+ } else if (node is SimpleStringLiteral) {
+ // no dependencies
+ } else if (node is StringInterpolation) {
+ _visitStringInterpolation(node);
+ } else if (node is ThisExpression) {
+ // no dependencies
+ // TODO(scheglov) not really, because "this" type depends on the hierarchy
+ } else if (node is ThrowExpression) {
+ _visitExpression(node.expression);
} else {
-// throw UnimplementedError('(${node.runtimeType}) $node');
+ throw UnimplementedError('(${node.runtimeType}) $node');
}
}
@@ -195,7 +271,7 @@
_localScopes.exit();
}
- void _visitFormalParameters(FormalParameterList node) {
+ void _visitFormalParameterList(FormalParameterList node) {
if (node == null) return;
var parameters = node.parameters;
@@ -211,7 +287,7 @@
}
if (parameter is FunctionTypedFormalParameter) {
_visitTypeAnnotation(parameter.returnType);
- _visitFormalParameters(parameter.parameters);
+ _visitFormalParameterList(parameter.parameters);
} else if (parameter is SimpleFormalParameter) {
_visitTypeAnnotation(parameter.type);
} else {
@@ -255,14 +331,33 @@
void _visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
var function = node.functionDeclaration;
_visitTypeAnnotation(function.returnType);
+ _visitFunctionExpression(function.functionExpression);
+ }
+ void _visitFunctionExpression(FunctionExpression node) {
_localScopes.enter();
- var functionExpression = function.functionExpression;
- _visitFormalParameters(functionExpression.parameters);
- _visitFunctionBody(functionExpression.body);
+ _visitTypeParameterList(node.typeParameters);
+ _visitFormalParameterList(node.parameters);
+ _visitFunctionBody(node.body);
_localScopes.exit();
}
+ void _visitInstanceCreationExpression(InstanceCreationExpression node) {
+ var constructor = node.constructorName;
+
+ _visitTypeAnnotation(constructor.type);
+
+ var instantiatedType = constructor.type.type;
+ var name = constructor.name;
+ if (name != null) {
+ _recordClassMemberReference(instantiatedType, name.name);
+ } else {
+ _recordClassMemberReference(instantiatedType, '');
+ }
+
+ _visitArgumentList(node.argumentList);
+ }
+
void _visitListLiteral(ListLiteral node) {
_visitTypeArguments(node.typeArguments);
var elements = node.elements;
@@ -283,25 +378,32 @@
}
void _visitMethodInvocation(MethodInvocation node) {
- _visitExpression(node.target);
var realTarget = node.realTarget;
if (realTarget == null) {
_visitExpression(node.methodName);
} else if (realTarget is SuperExpression) {
- // TODO(scheglov) implement
- // throw UnimplementedError('$node');
+ _superReferences.add(node.methodName.name);
} else {
+ _visitExpression(node.target);
_recordClassMemberReference(
realTarget.staticType,
- false,
node.methodName.name,
);
}
- // TODO(scheglov) tests
- var arguments = node.argumentList.arguments;
- for (var i = 0; i < arguments.length; i++) {
- var argument = arguments[i];
- _visitExpression(argument);
+ _visitTypeArguments(node.typeArguments);
+ _visitArgumentList(node.argumentList);
+ }
+
+ void _visitPostfixExpression(PostfixExpression node) {
+ _visitExpression(node.operand);
+
+ var operator = node.operator.type;
+ if (operator == TokenType.MINUS_MINUS) {
+ _recordClassMemberReference(node.operand.staticType, '-');
+ } else if (operator == TokenType.PLUS_PLUS) {
+ _recordClassMemberReference(node.operand.staticType, '+');
+ } else {
+ throw UnimplementedError('$operator');
}
}
@@ -310,18 +412,11 @@
var prefixElement = prefix.staticElement;
if (prefixElement is PrefixElement) {
var prefixName = prefix.name;
- // TODO(scheglov) remove this null check work around
var importPrefix = _importPrefix(prefixName);
- if (importPrefix != null) {
- importPrefix.add(node.identifier.name);
- }
+ importPrefix.add(node.identifier.name);
} else {
_visitExpression(prefix);
- _recordClassMemberReference(
- prefix.staticType,
- false,
- node.identifier.name,
- );
+ _recordClassMemberReference(prefix.staticType, node.identifier.name);
}
}
@@ -331,11 +426,20 @@
var operatorName = node.operator.lexeme;
if (operatorName == '-') operatorName = 'unary-';
- _recordClassMemberReference(
- node.operand.staticType,
- false,
- operatorName,
- );
+ _recordClassMemberReference(node.operand.staticType, operatorName);
+ }
+
+ void _visitPropertyAccess(PropertyAccess node) {
+ var realTarget = node.realTarget;
+ if (realTarget is SuperExpression) {
+ _superReferences.add(node.propertyName.name);
+ } else {
+ _visitExpression(node.target);
+ _recordClassMemberReference(
+ realTarget.staticType,
+ node.propertyName.name,
+ );
+ }
}
void _visitSetLiteral(SetLiteral node) {
@@ -352,6 +456,7 @@
var name = node.name;
if (!_localScopes.contains(name) && name != 'void' && name != 'dynamic') {
+ // TODO(scheglov) use `name=` if assignment context, or both
_recordUnprefixedReference(name);
}
}
@@ -428,6 +533,16 @@
_localScopes.exit();
}
+ void _visitStringInterpolation(StringInterpolation node) {
+ var elements = node.elements;
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ if (element is InterpolationExpression) {
+ _visitExpression(element.expression);
+ }
+ }
+ }
+
void _visitSwitchStatement(SwitchStatement node) {
_visitExpression(node.expression);
var members = node.members;
@@ -465,7 +580,7 @@
}
_visitTypeAnnotation(node.returnType);
- _visitFormalParameters(node.parameters);
+ _visitFormalParameterList(node.parameters);
_localScopes.exit();
} else if (node is TypeName) {
@@ -487,6 +602,17 @@
}
}
+ void _visitTypeParameterList(TypeParameterList node) {
+ if (node == null) return;
+
+ var typeParameters = node.typeParameters;
+ for (var i = 0; i < typeParameters.length; i++) {
+ var typeParameter = typeParameters[i];
+ _localScopes.add(typeParameter.name.name);
+ _visitTypeAnnotation(typeParameter.bound);
+ }
+ }
+
void _visitVariableList(VariableDeclarationList node) {
if (node == null) return;
@@ -505,10 +631,10 @@
class _ClassMemberReferenceSet {
final List<ClassMemberReference> references = [];
- void add(InterfaceType type, bool withSuper, String name) {
+ void add(InterfaceType type, String name) {
var class_ = type.element;
var target = LibraryQualifiedName(class_.library.source.uri, class_.name);
- var reference = ClassMemberReference(target, withSuper, name);
+ var reference = ClassMemberReference(target, name);
if (!references.contains(reference)) {
references.add(reference);
}
diff --git a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
index cd73479..587a193 100644
--- a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
@@ -22,6 +22,70 @@
@reflectiveTest
class ExpressionReferenceCollectorTest extends _Base {
+ test_adjacentStrings() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ 'foo' '$x' 'bar';
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x']);
+ }
+
+ test_asExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x as Y;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['Y', 'x']);
+ }
+
+ test_assignmentExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x = y;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
+ }
+
+ test_assignmentExpression_compound() async {
+ var library = await buildTestLibrary(a, r'''
+class A {
+ operator+(_) {}
+}
+
+class B extends A {}
+
+B x, y;
+
+test() {
+ x += y;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['x', 'y'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'B', '+')]);
+ }
+
+ test_assignmentExpression_nullAware() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x ??= y;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
+ }
+
+ test_awaitExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() async {
+ await x;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x']);
+ }
+
test_binaryExpression() async {
var library = await buildTestLibrary(a, r'''
class A {
@@ -140,6 +204,39 @@
_assertImpl(library, 'test', NodeKind.FUNCTION);
}
+ test_cascadeExpression() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+A x;
+
+test() {
+ x
+ ..foo(y)
+ ..bar = z;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: [
+ 'x',
+ 'y',
+ 'z'
+ ], expectedMembers: [
+ _ExpectedClassMember(aUri, 'A', 'bar'),
+ _ExpectedClassMember(aUri, 'A', 'foo'),
+ ]);
+ // TODO(scheglov) should be `bar=`
+ }
+
+ test_conditionalExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x ? y : z;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['x', 'y', 'z']);
+ }
+
test_doubleLiteral() async {
var library = await buildTestLibrary(a, r'''
test() {
@@ -149,6 +246,111 @@
_assertImpl(library, 'test', NodeKind.FUNCTION);
}
+ test_functionExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ <T extends A, U extends T>(B b, C c, T t, U u) {
+ T;
+ U;
+ x;
+ }
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'B', 'C', 'x']);
+ }
+
+ test_functionExpressionInvocation() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ (x)<T>(y, z);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['T', 'x', 'y', 'z']);
+ }
+
+ test_indexExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x[y];
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
+ }
+
+ test_instanceCreationExpression_explicitNew_named() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+test() {
+ new A<T>.named(x, b: y);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x', 'y'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', 'named')]);
+ }
+
+ test_instanceCreationExpression_explicitNew_unnamed() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+test() {
+ new A<T>(x, b: y);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x', 'y'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', '')]);
+ }
+
+ test_instanceCreationExpression_explicitNew_unresolvedClass() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ new A<T>.named(x);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x']);
+ }
+
+ test_instanceCreationExpression_implicitNew_named() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+test() {
+ A<T>.named(x, b: y);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x', 'y'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', 'named')]);
+ }
+
+ test_instanceCreationExpression_implicitNew_unnamed() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+test() {
+ A<T>(x, b: y);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x', 'y'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', '')]);
+ }
+
+ test_instanceCreationExpression_implicitNew_unresolvedClass_named() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ A<T>.named(x, b: y);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x', 'y']);
+ }
+
test_integerLiteral() async {
var library = await buildTestLibrary(a, r'''
test() {
@@ -158,6 +360,15 @@
_assertImpl(library, 'test', NodeKind.FUNCTION);
}
+ test_isExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x is Y;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['Y', 'x']);
+ }
+
test_listLiteral() async {
var library = await buildTestLibrary(a, r'''
test() {
@@ -178,23 +389,83 @@
unprefixed: ['A', 'B', 'v', 'w', 'x', 'y']);
}
- test_methodInvocation() async {
+ test_methodInvocation_instance_withoutTarget_function() async {
var library = await buildTestLibrary(a, r'''
-class A {
- void foo() {}
-}
-
-class B extends A {}
-
-B x;
+void foo(a, {b}) {}
test() {
- x.foo();
+ foo(x, b: y);
}
''');
_assertImpl(library, 'test', NodeKind.FUNCTION,
- unprefixed: ['x'],
- expectedMembers: [_ExpectedClassMember(aUri, 'B', 'foo')]);
+ unprefixed: ['foo', 'x', 'y']);
+ }
+
+ test_methodInvocation_instance_withoutTarget_method() async {
+ var library = await buildTestLibrary(a, r'''
+class C {
+ void foo(a, {b}) {}
+
+ test() {
+ foo(x, b: y);
+ }
+}
+''');
+ _assertImpl(library, 'test', NodeKind.METHOD,
+ memberOf: 'C', unprefixed: ['foo', 'x', 'y']);
+ }
+
+ test_methodInvocation_instance_withTarget() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+A x;
+
+test() {
+ x.foo<T>(y, b: z);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['T', 'x', 'y', 'z'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', 'foo')]);
+ }
+
+ test_methodInvocation_instance_withTarget_super() async {
+ var library = await buildTestLibrary(a, r'''
+class A {
+ void foo(a, b) {}
+}
+
+class B extends A {
+ test() {
+ super.foo(x, y);
+ }
+}
+''');
+ _assertImpl(library, 'test', NodeKind.METHOD,
+ memberOf: 'B', unprefixed: ['x', 'y'], superPrefixed: ['foo']);
+ }
+
+ test_methodInvocation_static_withTarget() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+test() {
+ A.foo<T>(x);
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['A', 'T', 'x'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'A', 'foo')]);
+ }
+
+ test_nullLiteral() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ null;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION);
}
test_parenthesizedExpression() async {
@@ -206,6 +477,37 @@
_assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x']);
}
+ test_postfixExpression() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+class B extend A {}
+
+B x, y;
+
+test() {
+ x++;
+ y--;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: [
+ 'x',
+ 'y'
+ ], expectedMembers: [
+ _ExpectedClassMember(aUri, 'B', '+'),
+ _ExpectedClassMember(aUri, 'B', '-')
+ ]);
+ }
+
+ test_postfixExpression_unresolvedTarget() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ x++;
+ y--;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
+ }
+
test_prefixedIdentifier_importPrefix() async {
newFile(b, content: 'var b = 0;');
var library = await buildTestLibrary(a, r'''
@@ -252,6 +554,21 @@
expectedMembers: [_ExpectedClassMember(aUri, 'B', 'y')]);
}
+ test_prefixedIdentifier_static() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+class B extends A {}
+
+test() {
+ B.x;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['B'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'B', 'x')]);
+ }
+
test_prefixedIdentifier_unresolvedPrefix() async {
var library = await buildTestLibrary(a, r'''
test() {
@@ -304,6 +621,35 @@
_assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x']);
}
+ test_propertyAccess() async {
+ var library = await buildTestLibrary(a, r'''
+class A {}
+
+class B extends A {}
+
+B x;
+
+test() {
+ (x).foo;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION,
+ unprefixed: ['x'],
+ expectedMembers: [_ExpectedClassMember(aUri, 'B', 'foo')]);
+ }
+
+ test_propertyAccess_super() async {
+ var library = await buildTestLibrary(a, r'''
+class C {
+ test() {
+ super.foo;
+ }
+}
+''');
+ _assertImpl(library, 'test', NodeKind.METHOD,
+ memberOf: 'C', superPrefixed: ['foo']);
+ }
+
test_setLiteral() async {
var library = await buildTestLibrary(a, r'''
test() {
@@ -350,6 +696,46 @@
''');
_assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
}
+
+ test_simpleStringLiteral() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ '';
+ """""";
+ r"""""";
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION);
+ }
+
+ test_stringInterpolation() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ '$x ${y}';
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x', 'y']);
+ }
+
+ test_thisExpression() async {
+ var library = await buildTestLibrary(a, r'''
+class C {
+ test() {
+ this;
+ }
+}
+''');
+ _assertImpl(library, 'test', NodeKind.METHOD, memberOf: 'C');
+ }
+
+ test_throwExpression() async {
+ var library = await buildTestLibrary(a, r'''
+test() {
+ throw x;
+}
+''');
+ _assertImpl(library, 'test', NodeKind.FUNCTION, unprefixed: ['x']);
+ }
}
@reflectiveTest
@@ -766,12 +1152,14 @@
void _assertApi(Library library, String name, NodeKind kind,
{List<String> unprefixed: const [],
Map<String, List<String>> prefixed: const {},
+ List<String> superPrefixed: const [],
List<_ExpectedClassMember> expectedMembers: const []}) {
var node = getNode(library, name: name, kind: kind);
_assertDependencies(
node.api,
unprefixed: unprefixed,
prefixed: prefixed,
+ superPrefixed: superPrefixed,
expectedMembers: expectedMembers,
);
}
@@ -779,10 +1167,12 @@
void _assertDependencies(Dependencies dependencies,
{List<String> unprefixed: const [],
Map<String, List<String>> prefixed: const {},
+ List<String> superPrefixed: const [],
List<_ExpectedClassMember> expectedMembers: const []}) {
expect(dependencies.unprefixedReferencedNames, unprefixed);
expect(dependencies.importPrefixes, prefixed.keys);
expect(dependencies.importPrefixedReferencedNames, prefixed.values);
+ expect(dependencies.superReferencedNames, superPrefixed);
var actualMembers = dependencies.classMemberReferences;
if (actualMembers.length != expectedMembers.length) {
@@ -794,22 +1184,24 @@
var expectedMember = expectedMembers[i];
if (actualMember.target.libraryUri != expectedMember.targetUri ||
actualMember.target.name != expectedMember.targetName ||
- actualMember.name != expectedMember.name ||
- actualMember.targetSuper != expectedMember.withSuper) {
+ actualMember.name != expectedMember.name) {
fail('Expected: $expectedMember\nActual: $actualMember');
}
}
}
void _assertImpl(Library library, String name, NodeKind kind,
- {List<String> unprefixed: const [],
+ {String memberOf,
+ List<String> unprefixed: const [],
Map<String, List<String>> prefixed: const {},
+ List<String> superPrefixed: const [],
List<_ExpectedClassMember> expectedMembers: const []}) {
- var node = getNode(library, name: name, kind: kind);
+ var node = getNode(library, name: name, kind: kind, memberOf: memberOf);
_assertDependencies(
node.impl,
unprefixed: unprefixed,
prefixed: prefixed,
+ superPrefixed: superPrefixed,
expectedMembers: expectedMembers,
);
}
@@ -818,14 +1210,16 @@
class _ExpectedClassMember {
final Uri targetUri;
final String targetName;
- final bool withSuper;
final String name;
- _ExpectedClassMember(this.targetUri, this.targetName, this.name,
- {this.withSuper: false});
+ _ExpectedClassMember(
+ this.targetUri,
+ this.targetName,
+ this.name,
+ );
@override
String toString() {
- return '($targetUri, $targetName, $name, withSuper: $withSuper)';
+ return '($targetUri, $targetName, $name)';
}
}