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)';
   }
 }