[dartdevc] fix NSM with private field overrides and mixin declarations

Analyzer does not put mixin declarations in the `.types` getter, which
broke DDC's assumption that it contained all of the class/interface
types in the compilation unit. Kernel backend was not affected.

Change-Id: I219d814766fb97ef81920d0150cb1dfbbc6087f5
Reviewed-on: https://dart-review.googlesource.com/c/82022
Auto-Submit: Jenny Messerly <jmesserly@google.com>
Commit-Queue: Alan Knight <alanknight@google.com>
Reviewed-by: Alan Knight <alanknight@google.com>
diff --git a/pkg/dev_compiler/lib/src/analyzer/property_model.dart b/pkg/dev_compiler/lib/src/analyzer/property_model.dart
index 1691857..b7dc784 100644
--- a/pkg/dev_compiler/lib/src/analyzer/property_model.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/property_model.dart
@@ -58,22 +58,27 @@
   final _extensiblePrivateClasses = HashSet<ClassElement>();
 
   _LibraryVirtualFieldModel.build(LibraryElement library) {
-    var allTypes = library.units.expand((u) => u.types).toList();
+    var allClasses = Set<ClassElement>();
+    for (var libraryPart in library.units) {
+      allClasses.addAll(libraryPart.types);
+      allClasses.addAll(libraryPart.mixins);
+    }
 
     // The set of public types is our initial extensible type set.
     // From there, visit all immediate private types in this library, and so on
     // from those private types, marking them as extensible.
-    var typesToVisit =
-        Queue<ClassElement>.from(allTypes.where((t) => t.isPublic));
-    while (typesToVisit.isNotEmpty) {
-      var extensibleType = typesToVisit.removeFirst();
+    var classesToVisit =
+        Queue<ClassElement>.from(allClasses.where((t) => t.isPublic));
+    while (classesToVisit.isNotEmpty) {
+      var extensibleClass = classesToVisit.removeFirst();
 
       // For each supertype of a public type in this library,
       // if we encounter a private class, we mark it as being extended, and
       // add it to our work set if this is the first time we've visited it.
-      for (var type in getImmediateSuperclasses(extensibleType)) {
-        if (!type.isPublic && type.library == library) {
-          if (_extensiblePrivateClasses.add(type)) typesToVisit.add(type);
+      for (var superclass in getImmediateSuperclasses(extensibleClass)) {
+        if (!superclass.isPublic && superclass.library == library) {
+          if (_extensiblePrivateClasses.add(superclass))
+            classesToVisit.add(superclass);
         }
       }
     }
@@ -88,43 +93,44 @@
     }
 
     var allFields =
-        HashMap.fromIterables(allTypes, allTypes.map(getInstanceFieldMap));
+        HashMap.fromIterables(allClasses, allClasses.map(getInstanceFieldMap));
 
-    for (var type in allTypes) {
-      Set<ClassElement> supertypes = null;
+    for (var class_ in allClasses) {
+      Set<ClassElement> superclasses;
 
       // Visit accessors in the current class, and see if they override an
       // otherwise private field.
-      for (var accessor in type.accessors) {
+      for (var accessor in class_.accessors) {
         // For getter/setter pairs only process them once.
         if (accessor.correspondingGetter != null) continue;
         // Ignore abstract or static accessors.
         if (accessor.isAbstract || accessor.isStatic) continue;
         // Ignore public accessors in extensible classes.
         if (accessor.isPublic &&
-            (type.isPublic || _extensiblePrivateClasses.contains(type))) {
+            (class_.isPublic || _extensiblePrivateClasses.contains(class_))) {
           continue;
         }
 
-        if (supertypes == null) {
-          supertypes = Set();
-          void collectSupertypes(ClassElement cls) {
-            if (!supertypes.add(cls)) return;
+        if (superclasses == null) {
+          superclasses = Set();
+          void collectSuperclasses(ClassElement cls) {
+            if (!superclasses.add(cls)) return;
             var s = cls.supertype?.element;
-            if (s != null) collectSupertypes(s);
-            cls.mixins.forEach((m) => collectSupertypes(m.element));
+            if (s != null) collectSuperclasses(s);
+            cls.mixins.forEach((m) => collectSuperclasses(m.element));
           }
 
-          collectSupertypes(type);
-          supertypes.remove(type);
-          supertypes.removeWhere((c) => c.library != type.library);
+          collectSuperclasses(class_);
+          superclasses.remove(class_);
+          superclasses.removeWhere((c) => c.library != library);
         }
 
         // Look in all super classes to see if we're overriding a field in our
         // library, if so mark that field as overridden.
         var name = accessor.variable.name;
-        _overriddenPrivateFields.addAll(
-            supertypes.map((c) => allFields[c][name]).where((f) => f != null));
+        _overriddenPrivateFields.addAll(superclasses
+            .map((c) => allFields[c][name])
+            .where((f) => f != null));
       }
     }
   }
diff --git a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
index e004f89..0921e35 100644
--- a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
+++ b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
@@ -186,6 +186,7 @@
     library ??= visitLibraryElement(e.library);
     library.addClass(class_);
 
+    class_.isMixinDeclaration = e.isMixin;
     class_.typeParameters
         .addAll(e.typeParameters.map(visitTypeParameterElement));
 
@@ -504,6 +505,9 @@
       for (var t in u.types) {
         visitClassElement(t, library);
       }
+      for (var t in u.mixins) {
+        visitClassElement(t, library);
+      }
       for (var t in u.functionTypeAliases) {
         visitFunctionTypeAliasElement(t, library);
       }
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index 4242554..df0444b 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -92,7 +92,7 @@
         HashMap.fromIterables(allClasses, allClasses.map(getInstanceFieldMap));
 
     for (var class_ in allClasses) {
-      Set<Class> superclasses = null;
+      Set<Class> superclasses;
 
       // Visit accessors in the current class, and see if they override an
       // otherwise private field.
@@ -124,8 +124,7 @@
 
           collectSupertypes(class_);
           superclasses.remove(class_);
-          superclasses.removeWhere(
-              (s) => s.enclosingLibrary != class_.enclosingLibrary);
+          superclasses.removeWhere((s) => s.enclosingLibrary != library);
         }
 
         // Look in all super classes to see if we're overriding a field in our
diff --git a/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart
index 9bfc38f..aba4640 100644
--- a/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart
+++ b/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart
@@ -402,4 +402,19 @@
   }
 
   Expect.equals(CeOwithM().toString(), CwithM().toString());
+
+  {
+    // Regression test for private fields.
+    var c = PrivateFieldClass();
+    Expect.equals(42, c._foo);
+  }
+}
+
+
+mixin PrivateFieldMixin {
+  int _foo = 40;
+}
+
+class PrivateFieldClass with PrivateFieldMixin {
+  int get _foo => super._foo + 2;
 }