Set 'enclosingClass' for class members and type parameters.

R=brianwilkerson@google.com

Change-Id: I932f327da2b3eba196150840a60625b5780359e4
Reviewed-on: https://dart-review.googlesource.com/c/86983
Reviewed-by: Brian Wilkerson <brianwilkerson@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 409d7b0..dcc3838 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
@@ -156,6 +156,9 @@
   /// locations are different.
   List<int> enclosingClassNameSignature;
 
+  /// The node of the enclosing class.
+  Node enclosingClass;
+
   _LibraryBuilder(this.uri, this.units);
 
   Library build() {
@@ -181,60 +184,6 @@
     enclosingClassNameSignature =
         (ApiSignature()..addString(enclosingClassName)).toByteList();
 
-    var hasConstConstructor = node.members.any(
-      (m) => m is ConstructorDeclaration && m.constKeyword != null,
-    );
-
-    // TODO(scheglov) do we need type parameters at all?
-    List<Node> classTypeParameters;
-    if (node.typeParameters != null) {
-      classTypeParameters = <Node>[];
-      for (var typeParameter in node.typeParameters.typeParameters) {
-        var api = referenceCollector.collect(
-          _computeNodeTokenSignature(typeParameter),
-          enclosingClassName: enclosingClassName,
-          thisNodeName: typeParameter.name.name,
-          type: typeParameter.bound,
-        );
-        classTypeParameters.add(Node(
-          LibraryQualifiedName(uri, typeParameter.name.name),
-          NodeKind.TYPE_PARAMETER,
-          api,
-          Dependencies.none,
-        ));
-      }
-      classTypeParameters.sort(Node.compare);
-    }
-
-    var classMembers = <Node>[];
-    var hasConstructor = false;
-    for (var member in node.members) {
-      if (member is ConstructorDeclaration) {
-        hasConstructor = true;
-        _addConstructor(classMembers, member);
-      } else if (member is FieldDeclaration) {
-        _addVariables(
-          classMembers,
-          member.metadata,
-          member.fields,
-          hasConstConstructor,
-        );
-      } else if (member is MethodDeclaration) {
-        _addMethod(classMembers, member);
-      } else {
-        throw UnimplementedError('(${member.runtimeType}) $member');
-      }
-    }
-
-    if (!hasConstructor && node is ClassDeclaration) {
-      classMembers.add(Node(
-        LibraryQualifiedName(uri, ''),
-        NodeKind.CONSTRUCTOR,
-        Dependencies.none,
-        Dependencies.none,
-      ));
-    }
-
     var apiTokenSignature = _computeTokenSignature(
       node.beginToken,
       node.leftBracket,
@@ -262,21 +211,78 @@
       throw UnimplementedError('(${node.runtimeType}) $node');
     }
 
-    var classNode = Node(
+    enclosingClass = Node(
       LibraryQualifiedName(uri, enclosingClassName),
       node is MixinDeclaration ? NodeKind.MIXIN : NodeKind.CLASS,
       api,
       Dependencies.none,
-      classTypeParameters: classTypeParameters,
     );
 
-    classMembers.sort(Node.compare);
-    classNode.setClassMembers(classMembers);
+    var hasConstConstructor = node.members.any(
+      (m) => m is ConstructorDeclaration && m.constKeyword != null,
+    );
 
-    declaredNodes.add(classNode);
+    // TODO(scheglov) do we need type parameters at all?
+    List<Node> classTypeParameters;
+    if (node.typeParameters != null) {
+      classTypeParameters = <Node>[];
+      for (var typeParameter in node.typeParameters.typeParameters) {
+        var api = referenceCollector.collect(
+          _computeNodeTokenSignature(typeParameter),
+          enclosingClassName: enclosingClassName,
+          thisNodeName: typeParameter.name.name,
+          type: typeParameter.bound,
+        );
+        classTypeParameters.add(Node(
+          LibraryQualifiedName(uri, typeParameter.name.name),
+          NodeKind.TYPE_PARAMETER,
+          api,
+          Dependencies.none,
+          enclosingClass: enclosingClass,
+        ));
+      }
+      classTypeParameters.sort(Node.compare);
+      enclosingClass.setTypeParameters(classTypeParameters);
+    }
+
+    var classMembers = <Node>[];
+    var hasConstructor = false;
+    for (var member in node.members) {
+      if (member is ConstructorDeclaration) {
+        hasConstructor = true;
+        _addConstructor(classMembers, member);
+      } else if (member is FieldDeclaration) {
+        _addVariables(
+          classMembers,
+          member.metadata,
+          member.fields,
+          hasConstConstructor,
+        );
+      } else if (member is MethodDeclaration) {
+        _addMethod(classMembers, member);
+      } else {
+        throw UnimplementedError('(${member.runtimeType}) $member');
+      }
+    }
+
+    if (node is ClassDeclaration && !hasConstructor) {
+      classMembers.add(Node(
+        LibraryQualifiedName(uri, ''),
+        NodeKind.CONSTRUCTOR,
+        Dependencies.none,
+        Dependencies.none,
+        enclosingClass: enclosingClass,
+      ));
+    }
+
+    classMembers.sort(Node.compare);
+    enclosingClass.setClassMembers(classMembers);
+
+    declaredNodes.add(enclosingClass);
     enclosingClassName = null;
     enclosingClassNameSignature = null;
     enclosingSuperClass = null;
+    enclosingClass = null;
   }
 
   void _addClassTypeAlias(ClassTypeAlias node) {
@@ -325,12 +331,20 @@
       NodeKind.CONSTRUCTOR,
       api,
       impl,
+      enclosingClass: enclosingClass,
     ));
   }
 
   void _addEnum(EnumDeclaration node) {
     var enumTokenSignature = _newApiSignatureBuilder().toByteList();
 
+    var enumNode = Node(
+      LibraryQualifiedName(uri, node.name.name),
+      NodeKind.ENUM,
+      Dependencies(enumTokenSignature, [], [], [], [], []),
+      Dependencies.none,
+    );
+
     Dependencies fieldDependencies;
     {
       var builder = _newApiSignatureBuilder();
@@ -347,6 +361,7 @@
         NodeKind.GETTER,
         fieldDependencies,
         Dependencies.none,
+        enclosingClass: enumNode,
       ));
     }
 
@@ -355,6 +370,7 @@
       NodeKind.GETTER,
       fieldDependencies,
       Dependencies.none,
+      enclosingClass: enumNode,
     ));
 
     members.add(Node(
@@ -362,15 +378,10 @@
       NodeKind.GETTER,
       fieldDependencies,
       Dependencies.none,
+      enclosingClass: enumNode,
     ));
-    members.sort(Node.compare);
 
-    var enumNode = Node(
-      LibraryQualifiedName(uri, node.name.name),
-      NodeKind.ENUM,
-      Dependencies(enumTokenSignature, [], [], [], [], []),
-      Dependencies.none,
-    );
+    members.sort(Node.compare);
     enumNode.setClassMembers(members);
 
     declaredNodes.add(enumNode);
@@ -545,7 +556,9 @@
     );
 
     var name = LibraryQualifiedName(uri, node.name.name);
-    classMembers.add(Node(name, kind, api, impl));
+    classMembers.add(
+      Node(name, kind, api, impl, enclosingClass: enclosingClass),
+    );
   }
 
   void _addUnit(CompilationUnit unit) {
@@ -615,6 +628,7 @@
         NodeKind.GETTER,
         api,
         impl,
+        enclosingClass: enclosingClass,
       ));
 
       if (!variables.isConst && !variables.isFinal) {
@@ -626,6 +640,7 @@
             NodeKind.SETTER,
             api,
             Dependencies.none,
+            enclosingClass: enclosingClass,
           ),
         );
       }
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
index 6fe7d43..ef5022d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/node.dart
@@ -181,7 +181,7 @@
 
   /// If the node is a class, the nodes of its type parameters.
   /// Otherwise `null`.
-  final List<Node> classTypeParameters;
+  List<Node> classTypeParameters;
 
   /// If the node is a class, the sorted list of members in this class.
   /// Otherwise `null`.
@@ -210,6 +210,11 @@
     classMembers = newClassMembers;
   }
 
+  /// Set new class type parameters for this class.
+  void setTypeParameters(List<Node> newTypeParameters) {
+    classTypeParameters = newTypeParameters;
+  }
+
   @override
   String toString() {
     if (enclosingClass != null) {
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 2d6a175..b191634 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
@@ -253,7 +253,9 @@
 
     for (var i = 0; i < initializers.length; i++) {
       var initializer = initializers[i];
-      if (initializer is ConstructorFieldInitializer) {
+      if (initializer is AssertInitializer) {
+        // TODO(scheglov) implement
+      } else if (initializer is ConstructorFieldInitializer) {
         _visitExpression(initializer.expression);
       } else if (initializer is SuperConstructorInvocation) {
         _visitConstructor(superClass, initializer.constructorName);
diff --git a/pkg/analyzer/test/src/dart/analysis/dependency/base.dart b/pkg/analyzer/test/src/dart/analysis/dependency/base.dart
index 9bc3448..b217244 100644
--- a/pkg/analyzer/test/src/dart/analysis/dependency/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/dependency/base.dart
@@ -21,10 +21,8 @@
 
   bool hasDartCore = false;
 
-  void assertNodes(
-    List<Node> actualNodes,
-    List<ExpectedNode> expectedNodes,
-  ) {
+  void assertNodes(List<Node> actualNodes, List<ExpectedNode> expectedNodes,
+      {Node expectedEnclosingClass}) {
     expect(actualNodes, hasLength(expectedNodes.length));
     for (var expectedNode in expectedNodes) {
       var topNode = _getNode(
@@ -33,9 +31,11 @@
         name: expectedNode.name,
         kind: expectedNode.kind,
       );
+      expect(topNode.enclosingClass, expectedEnclosingClass);
 
       if (expectedNode.classMembers != null) {
-        assertNodes(topNode.classMembers, expectedNode.classMembers);
+        assertNodes(topNode.classMembers, expectedNode.classMembers,
+            expectedEnclosingClass: topNode);
       } else {
         expect(topNode.classMembers, isNull);
       }
@@ -44,6 +44,7 @@
         assertNodes(
           topNode.classTypeParameters,
           expectedNode.classTypeParameters,
+          expectedEnclosingClass: topNode,
         );
       } else {
         expect(topNode.classTypeParameters, isNull);