Version 2.12.0-231.0.dev

Merge commit '989e42f18972918422c1b24ede86a6b2ae08ebf2' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
index 946989a..524cdaa 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
@@ -6,14 +6,11 @@
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
-import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_matcher.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_manager.dart';
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart' show LibraryElement;
-import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:meta/meta.dart';
@@ -36,16 +33,11 @@
         importedUris.add(Uri.parse(uri));
       }
     }
-    var components = _computeComponents();
-    if (components == null) {
-      // If we couldn't compute the components it's because the node doesn't
-      // represent an element that can be transformed.
+    var matcher = ElementMatcher.forNode(node);
+    if (matcher == null) {
+      // The node doesn't represent an element that can be transformed.
       return;
     }
-    var matcher = ElementMatcher(
-        importedUris: importedUris,
-        components: components,
-        kinds: _kindsForNode(node));
     for (var set in _availableTransformSetsForLibrary(library)) {
       for (var transform
           in set.transformsFor(matcher, applyingBulkFixes: applyingBulkFixes)) {
@@ -63,174 +55,6 @@
     return TransformSetManager.instance.forLibrary(library);
   }
 
-  /// Return the components for the element associated with the given [node] by
-  /// looking at the parent of the [node].
-  List<String> _componentsFromParent(AstNode node) {
-    var parent = node.parent;
-    if (parent is ArgumentList) {
-      parent = parent.parent;
-    }
-    if (parent is Annotation) {
-      return [parent.constructorName?.name ?? '', parent.name.name];
-    } else if (parent is ExtensionOverride) {
-      return [parent.extensionName.name];
-    } else if (parent is InstanceCreationExpression) {
-      var constructorName = parent.constructorName;
-      return [constructorName.name?.name ?? '', constructorName.type.name.name];
-    } else if (parent is MethodInvocation) {
-      var target = _nameOfTarget(parent.realTarget);
-      if (target != null) {
-        return [parent.methodName.name, target];
-      }
-      var ancestor = parent.parent;
-      while (ancestor != null) {
-        if (ancestor is ClassOrMixinDeclaration) {
-          return [parent.methodName.name, ancestor.name.name];
-        } else if (ancestor is ExtensionDeclaration) {
-          return [parent.methodName.name, ancestor.name.name];
-        }
-        ancestor = ancestor.parent;
-      }
-      return [parent.methodName.name];
-    } else if (parent is RedirectingConstructorInvocation) {
-      var ancestor = parent.parent;
-      if (ancestor is ConstructorDeclaration) {
-        return [parent.constructorName?.name ?? '', ancestor.returnType.name];
-      }
-    } else if (parent is SuperConstructorInvocation) {
-      var ancestor = parent.parent;
-      if (ancestor is ConstructorDeclaration) {
-        return [parent.constructorName?.name ?? '', ancestor.returnType.name];
-      }
-    }
-    return null;
-  }
-
-  /// Return the components of the path of the element associated with the
-  /// diagnostic. The components are ordered from the most local to the most
-  /// global. For example, for a constructor this would be the name of the
-  /// constructor followed by the name of the class in which the constructor is
-  /// declared (with an empty string for the unnamed constructor).
-  List<String> _computeComponents() {
-    var node = this.node;
-    if (node is SimpleIdentifier) {
-      var parent = node.parent;
-      if (parent is Label && parent.parent is NamedExpression) {
-        // The parent of the named expression is an argument list. Because we
-        // don't represent parameters as elements, the element we need to match
-        // against is the invocation containing those arguments.
-        return _componentsFromParent(parent.parent.parent);
-      } else if (parent is TypeName && parent.parent is ConstructorName) {
-        return ['', node.name];
-      } else if (parent is MethodInvocation) {
-        return _componentsFromParent(node);
-      }
-      return [node.name];
-    } else if (node is PrefixedIdentifier) {
-      var parent = node.parent;
-      if (parent is TypeName && parent.parent is ConstructorName) {
-        return ['', node.identifier.name];
-      }
-      return [node.identifier.name];
-    } else if (node is ConstructorName) {
-      return [node.name.name];
-    } else if (node is NamedType) {
-      return [node.name.name];
-    } else if (node is TypeArgumentList) {
-      return _componentsFromParent(node);
-    } else if (node is ArgumentList) {
-      return _componentsFromParent(node);
-    } else if (node?.parent is ArgumentList) {
-      return _componentsFromParent(node.parent);
-    }
-    return null;
-  }
-
-  List<ElementKind> _kindsForNode(AstNode node, {AstNode child}) {
-    if (node is ConstructorName) {
-      return const [ElementKind.constructorKind];
-    } else if (node is ExtensionOverride) {
-      return const [ElementKind.extensionKind];
-    } else if (node is InstanceCreationExpression) {
-      return const [ElementKind.constructorKind];
-    } else if (node is Label) {
-      var argumentList = node.parent.parent;
-      return _kindsForNode(argumentList.parent, child: argumentList);
-    } else if (node is MethodInvocation) {
-      assert(child != null);
-      if (node.target == child) {
-        return const [
-          ElementKind.classKind,
-          ElementKind.enumKind,
-          ElementKind.mixinKind
-        ];
-      } else if (node.realTarget != null) {
-        return const [ElementKind.constructorKind, ElementKind.methodKind];
-      }
-      return const [
-        ElementKind.classKind,
-        ElementKind.extensionKind,
-        ElementKind.functionKind,
-        ElementKind.methodKind
-      ];
-    } else if (node is NamedType) {
-      var parent = node.parent;
-      if (parent is ConstructorName && parent.name == null) {
-        return const [ElementKind.classKind, ElementKind.constructorKind];
-      }
-      return const [
-        ElementKind.classKind,
-        ElementKind.enumKind,
-        ElementKind.mixinKind,
-        ElementKind.typedefKind
-      ];
-    } else if (node is PrefixedIdentifier) {
-      if (node.prefix == child) {
-        return const [
-          ElementKind.classKind,
-          ElementKind.enumKind,
-          ElementKind.extensionKind,
-          ElementKind.mixinKind,
-          ElementKind.typedefKind
-        ];
-      }
-      return const [
-        ElementKind.fieldKind,
-        ElementKind.getterKind,
-        ElementKind.setterKind
-      ];
-    } else if (node is PropertyAccess) {
-      return const [ElementKind.getterKind, ElementKind.setterKind];
-    } else if (node is SimpleIdentifier) {
-      return _kindsForNode(node.parent, child: node);
-    }
-    return null;
-  }
-
-  /// Return the name of the class associated with the given [target].
-  String _nameOfTarget(Expression target) {
-    if (target is SimpleIdentifier) {
-      var type = target.staticType;
-      if (type != null) {
-        if (type is InterfaceType) {
-          return type.element.name;
-        } else if (type.isDynamic) {
-          // The name is likely to be undefined.
-          return target.name;
-        }
-        return null;
-      }
-      return target.name;
-    } else if (target != null) {
-      var type = target.staticType;
-      if (type is InterfaceType) {
-        return type.element.name;
-      }
-      return null;
-    }
-    return null;
-  }
-
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
   static DataDriven newInstance() => DataDriven();
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
index a938d2c..d07b075 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
@@ -4,6 +4,10 @@
 
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart'
+    show ClassElement, ExtensionElement;
+import 'package:analyzer/dart/element/type.dart';
 import 'package:meta/meta.dart';
 
 /// An object that can be used to determine whether an element is appropriate
@@ -89,4 +93,246 @@
     }
     return false;
   }
+
+  /// Return an element matcher that will match the element that is, or should
+  /// be, associated with the given [node], or `null` if there is no appropriate
+  /// matcher for the node.
+  static ElementMatcher forNode(AstNode node) {
+    if (node == null) {
+      return null;
+    }
+    var importedUris = _importElementsForNode(node);
+    if (importedUris == null) {
+      return null;
+    }
+    var components = _componentsForNode(node);
+    if (components == null) {
+      return null;
+    }
+    return ElementMatcher(
+        importedUris: importedUris,
+        components: components,
+        kinds: _kindsForNode(node));
+  }
+
+  /// Return the components of the path of the element associated with the given
+  /// [node]. The components are ordered from the most local to the most global.
+  /// For example, for a constructor this would be the name of the constructor
+  /// followed by the name of the class in which the constructor is declared
+  /// (with an empty string for the unnamed constructor).
+  static List<String> _componentsForNode(AstNode node) {
+    if (node is SimpleIdentifier) {
+      var parent = node.parent;
+      if (parent is Label && parent.parent is NamedExpression) {
+        // The parent of the named expression is an argument list. Because we
+        // don't represent parameters as elements, the element we need to match
+        // against is the invocation containing those arguments.
+        return _componentsFromParent(parent.parent.parent);
+      } else if (parent is TypeName && parent.parent is ConstructorName) {
+        return ['', node.name];
+      } else if (parent is MethodDeclaration && node == parent.name) {
+        return [node.name];
+      } else if ((parent is MethodInvocation && node == parent.methodName) ||
+          (parent is PrefixedIdentifier && node == parent.identifier) ||
+          (parent is PropertyAccess && node == parent.propertyName)) {
+        return _componentsFromParent(node);
+      }
+      return _componentsFromIdentifier(node);
+    } else if (node is PrefixedIdentifier) {
+      var parent = node.parent;
+      if (parent is TypeName && parent.parent is ConstructorName) {
+        return ['', node.identifier.name];
+      }
+      return [node.identifier.name];
+    } else if (node is ConstructorName) {
+      return [node.name.name];
+    } else if (node is NamedType) {
+      return [node.name.name];
+    } else if (node is TypeArgumentList) {
+      return _componentsFromParent(node);
+    } else if (node is ArgumentList) {
+      return _componentsFromParent(node);
+    } else if (node?.parent is ArgumentList) {
+      return _componentsFromParent(node.parent);
+    }
+    return null;
+  }
+
+  /// Return the components associated with the [identifier] when there is no
+  /// contextual information.
+  static List<String> _componentsFromIdentifier(SimpleIdentifier identifier) {
+    var element = identifier.staticElement;
+    if (element == null) {
+      var parent = identifier.parent;
+      if (parent is AssignmentExpression && identifier == parent.leftHandSide) {
+        element = parent.writeElement;
+      }
+    }
+    if (element != null) {
+      var enclosingElement = element.enclosingElement;
+      if (enclosingElement is ClassElement ||
+          enclosingElement is ExtensionElement) {
+        return [identifier.name, enclosingElement.name];
+      }
+    }
+    return [identifier.name];
+  }
+
+  /// Return the components for the element associated with the given [node] by
+  /// looking at the parent of the [node].
+  static List<String> _componentsFromParent(AstNode node) {
+    var parent = node.parent;
+    if (parent is ArgumentList) {
+      parent = parent.parent;
+    }
+    if (parent is Annotation) {
+      return [parent.constructorName?.name ?? '', parent.name.name];
+    } else if (parent is ExtensionOverride) {
+      return [parent.extensionName.name];
+    } else if (parent is InstanceCreationExpression) {
+      var constructorName = parent.constructorName;
+      return [constructorName.name?.name ?? '', constructorName.type.name.name];
+    } else if (parent is MethodInvocation) {
+      var methodName = parent.methodName;
+      var targetName = _nameOfTarget(parent.realTarget);
+      if (targetName != null) {
+        return [methodName.name, targetName];
+      }
+      return _componentsFromIdentifier(methodName);
+    } else if (parent is PrefixedIdentifier) {
+      var identifier = parent.identifier;
+      var targetName = _nameOfTarget(parent.prefix);
+      if (targetName != null) {
+        return [identifier.name, targetName];
+      }
+      return _componentsFromIdentifier(identifier);
+    } else if (parent is PropertyAccess) {
+      var propertyName = parent.propertyName;
+      var targetName = _nameOfTarget(parent.realTarget);
+      if (targetName != null) {
+        return [propertyName.name, targetName];
+      }
+      return _componentsFromIdentifier(propertyName);
+    } else if (parent is RedirectingConstructorInvocation) {
+      var ancestor = parent.parent;
+      if (ancestor is ConstructorDeclaration) {
+        return [parent.constructorName?.name ?? '', ancestor.returnType.name];
+      }
+    } else if (parent is SuperConstructorInvocation) {
+      var ancestor = parent.parent;
+      if (ancestor is ConstructorDeclaration) {
+        return [parent.constructorName?.name ?? '', ancestor.returnType.name];
+      }
+    }
+    return null;
+  }
+
+  /// Return the URIs of the imports in the library containing the [node], or
+  /// `null` if the imports can't be determined.
+  static List<Uri> _importElementsForNode(AstNode node) {
+    var root = node.root;
+    if (root is! CompilationUnit) {
+      return null;
+    }
+    var importedUris = <Uri>[];
+    var library = (root as CompilationUnit).declaredElement.library;
+    for (var importElement in library.imports) {
+      // TODO(brianwilkerson) Filter based on combinators to help avoid making
+      //  invalid suggestions.
+      var uri = importElement.importedLibrary?.source?.uri;
+      if (uri != null) {
+        // The [uri] is `null` if the literal string is not a valid URI.
+        importedUris.add(uri);
+      }
+    }
+    return importedUris;
+  }
+
+  /// Return the kinds of elements that could reasonably be referenced at the
+  /// location of the [node]. If [child] is no `null` then the [node] is a
+  /// parent of the original node.
+  static List<ElementKind> _kindsForNode(AstNode node, {AstNode child}) {
+    if (node is ConstructorName) {
+      return const [ElementKind.constructorKind];
+    } else if (node is ExtensionOverride) {
+      return const [ElementKind.extensionKind];
+    } else if (node is InstanceCreationExpression) {
+      return const [ElementKind.constructorKind];
+    } else if (node is Label) {
+      var argumentList = node.parent.parent;
+      return _kindsForNode(argumentList.parent, child: argumentList);
+    } else if (node is MethodInvocation) {
+      assert(child != null);
+      if (node.target == child) {
+        return const [
+          ElementKind.classKind,
+          ElementKind.enumKind,
+          ElementKind.mixinKind
+        ];
+      } else if (node.realTarget != null) {
+        return const [ElementKind.constructorKind, ElementKind.methodKind];
+      }
+      return const [
+        ElementKind.classKind,
+        ElementKind.extensionKind,
+        ElementKind.functionKind,
+        ElementKind.methodKind
+      ];
+    } else if (node is NamedType) {
+      var parent = node.parent;
+      if (parent is ConstructorName && parent.name == null) {
+        return const [ElementKind.classKind, ElementKind.constructorKind];
+      }
+      return const [
+        ElementKind.classKind,
+        ElementKind.enumKind,
+        ElementKind.mixinKind,
+        ElementKind.typedefKind
+      ];
+    } else if (node is PrefixedIdentifier) {
+      if (node.prefix == child) {
+        return const [
+          ElementKind.classKind,
+          ElementKind.enumKind,
+          ElementKind.extensionKind,
+          ElementKind.mixinKind,
+          ElementKind.typedefKind
+        ];
+      }
+      return const [
+        ElementKind.fieldKind,
+        ElementKind.getterKind,
+        ElementKind.setterKind
+      ];
+    } else if (node is PropertyAccess) {
+      return const [ElementKind.getterKind, ElementKind.setterKind];
+    } else if (node is SimpleIdentifier) {
+      return _kindsForNode(node.parent, child: node);
+    }
+    return null;
+  }
+
+  /// Return the name of the class associated with the given [target].
+  static String _nameOfTarget(Expression target) {
+    if (target is SimpleIdentifier) {
+      var type = target.staticType;
+      if (type != null) {
+        if (type is InterfaceType) {
+          return type.element.name;
+        } else if (type.isDynamic) {
+          // The name is likely to be undefined.
+          return target.name;
+        }
+        return null;
+      }
+      return target.name;
+    } else if (target != null) {
+      var type = target.staticType;
+      if (type is InterfaceType) {
+        return type.element.name;
+      }
+      return null;
+    }
+    return null;
+  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/element_matcher_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/element_matcher_test.dart
new file mode 100644
index 0000000..89ec9da
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/element_matcher_test.dart
@@ -0,0 +1,404 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/element_matcher.dart';
+import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'data_driven_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ElementMatcherComponentAndKindTest);
+    defineReflectiveTests(ElementMatcherImportsTest);
+  });
+}
+
+abstract class AbstractElementMatcherTest extends DataDrivenFixProcessorTest {
+  void _assertMatcher(String search,
+      {List<String> expectedComponents,
+      List<ElementKind> expectedKinds,
+      List<String> expectedUris}) {
+    var node = findNodeAtString(search);
+    var matcher = ElementMatcher.forNode(node);
+    if (expectedUris != null) {
+      expect(matcher.importedUris,
+          unorderedEquals(expectedUris.map((uri) => Uri.parse(uri))));
+    }
+    if (expectedComponents != null) {
+      expect(matcher.components, expectedComponents);
+    }
+    if (expectedKinds != null) {
+      expect(matcher.validKinds, expectedKinds);
+    }
+  }
+}
+
+@reflectiveTest
+class ElementMatcherComponentAndKindTest extends AbstractElementMatcherTest {
+  /// The kinds that are expected where a getter or setter is allowed.
+  static List<ElementKind> accessorKinds = [
+    ElementKind.fieldKind,
+    ElementKind.getterKind,
+    ElementKind.setterKind,
+  ];
+
+  /// The kinds that are expected where an invocation is allowed.
+  static List<ElementKind> invocationKinds = [
+    ElementKind.classKind,
+    ElementKind.extensionKind,
+    ElementKind.functionKind,
+    ElementKind.methodKind,
+  ];
+
+  /// The kinds that are expected where a method or constructor is allowed.
+  static List<ElementKind> methodKinds = [
+    ElementKind.constructorKind,
+    ElementKind.methodKind
+  ];
+
+  /// The kinds that are expected where a type is allowed.
+  static List<ElementKind> typeKinds = [
+    ElementKind.classKind,
+    ElementKind.enumKind,
+    ElementKind.mixinKind,
+    ElementKind.typedefKind,
+  ];
+
+  @failingTest
+  Future<void> test_binaryExpression_resolved() async {
+    // This test fails because we don't yet support operators.
+    await resolveTestCode('''
+void f(int x, int y) {
+  x + y;
+}
+''');
+    _assertMatcher('+',
+        expectedComponents: ['+', 'int'],
+        expectedKinds: [ElementKind.methodKind]);
+  }
+
+  @failingTest
+  Future<void> test_binaryExpression_unresolved() async {
+    // This test fails because we don't yet support operators.
+    await resolveTestCode('''
+void f(C c1, C c2) {
+  c1 + c2;
+}
+class C {}
+''');
+    _assertMatcher('+',
+        expectedComponents: ['+', 'C'],
+        expectedKinds: [ElementKind.methodKind]);
+  }
+
+  Future<void> test_getter_withoutTarget_resolved() async {
+    await resolveTestCode('''
+class C {
+  String get g => '';
+  void m() {
+    g;
+  }
+}
+''');
+    _assertMatcher('g;', expectedComponents: ['g', 'C']);
+  }
+
+  Future<void> test_getter_withoutTarget_unresolved() async {
+    await resolveTestCode('''
+class C {
+  void m() {
+    foo;
+  }
+}
+''');
+    _assertMatcher('foo', expectedComponents: ['foo']);
+  }
+
+  Future<void> test_getter_withTarget_resolved() async {
+    await resolveTestCode('''
+void f(String s) {
+  s.length;
+}
+''');
+    _assertMatcher('length',
+        expectedComponents: ['length', 'String'], expectedKinds: accessorKinds);
+  }
+
+  Future<void> test_getter_withTarget_unresolved() async {
+    await resolveTestCode('''
+void f(String s) {
+  s.foo;
+}
+''');
+    _assertMatcher('foo',
+        expectedComponents: ['foo', 'String'], expectedKinds: accessorKinds);
+  }
+
+  Future<void> test_identifier_propertyAccess() async {
+    await resolveTestCode('''
+void f() {
+  s.length;
+}
+''');
+    // TODO(brianwilkerson) Several of these kinds don't seem to be appropriate,
+    //  so we might want to narrow down the list.
+    _assertMatcher('s', expectedComponents: [
+      's'
+    ], expectedKinds: [
+      ElementKind.classKind,
+      ElementKind.enumKind,
+      ElementKind.extensionKind,
+      ElementKind.mixinKind,
+      ElementKind.typedefKind,
+    ]);
+  }
+
+  Future<void> test_method_withoutTarget_resolved() async {
+    await resolveTestCode('''
+class C {
+  void m(int i) {}
+  void m2() {
+    m(0);
+  }
+}
+''');
+    _assertMatcher('m(0)',
+        expectedComponents: ['m', 'C'], expectedKinds: invocationKinds);
+  }
+
+  Future<void> test_method_withoutTarget_unresolved() async {
+    await resolveTestCode('''
+class C {
+  void m() {
+    foo();
+  }
+}
+''');
+    _assertMatcher('foo',
+        expectedComponents: ['foo'], expectedKinds: invocationKinds);
+  }
+
+  Future<void> test_method_withTarget_resolved() async {
+    await resolveTestCode('''
+void f(String s) {
+  s.substring(2);
+}
+''');
+    _assertMatcher('substring',
+        expectedComponents: ['substring', 'String'],
+        expectedKinds: methodKinds);
+  }
+
+  Future<void> test_method_withTarget_unresolved() async {
+    await resolveTestCode('''
+void f(String s) {
+  s.foo(2);
+}
+''');
+    _assertMatcher('foo',
+        expectedComponents: ['foo', 'String'], expectedKinds: methodKinds);
+  }
+
+  Future<void> test_setter_withoutTarget_resolved() async {
+    await resolveTestCode('''
+class C {
+  set s(String s) {}
+  void m() {
+    s = '';
+  }
+}
+''');
+    _assertMatcher('s =', expectedComponents: ['s', 'C']);
+  }
+
+  Future<void> test_setter_withoutTarget_unresolved() async {
+    await resolveTestCode('''
+class C {
+  void m() {
+    foo = '';
+  }
+}
+''');
+    _assertMatcher('foo', expectedComponents: ['foo']);
+  }
+
+  Future<void> test_setter_withTarget_resolved() async {
+    await resolveTestCode('''
+void f(C c) {
+  c.s = '';
+}
+class C {
+  set s(String s) {}
+}
+''');
+    _assertMatcher('s =',
+        expectedComponents: ['s', 'C'], expectedKinds: accessorKinds);
+  }
+
+  Future<void> test_setter_withTarget_unresolved() async {
+    await resolveTestCode('''
+void f(String s) {
+  s.foo = '';
+}
+''');
+    _assertMatcher('foo',
+        expectedComponents: ['foo', 'String'], expectedKinds: accessorKinds);
+  }
+
+  Future<void> test_type_field_resolved() async {
+    await resolveTestCode('''
+class C {
+  String s = '';
+}
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_field_unresolved() async {
+    await resolveTestCode('''
+class C {
+  Foo s = '';
+}
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_localVariable_resolved() async {
+    await resolveTestCode('''
+void f() {
+  String s = '';
+}
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_localVariable_unresolved() async {
+    await resolveTestCode('''
+void f() {
+  Foo s = '';
+}
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_method_resolved() async {
+    await resolveTestCode('''
+class C {
+  String m() => '';
+}
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_method_unresolved() async {
+    await resolveTestCode('''
+class C {
+  Foo m() => '';
+}
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_parameter_resolved() async {
+    await resolveTestCode('''
+void f(String s) {}
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_parameter_unresolved() async {
+    await resolveTestCode('''
+void f(Foo s) {}
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_topLevelFunction_resolved() async {
+    await resolveTestCode('''
+String f() => '';
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_topLevelFunction_unresolved() async {
+    await resolveTestCode('''
+Foo f() => '';
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_topLevelVariable_resolved() async {
+    await resolveTestCode('''
+String s = '';
+''');
+    _assertMatcher('String',
+        expectedComponents: ['String'], expectedKinds: typeKinds);
+  }
+
+  Future<void> test_type_topLevelVariable_unresolved() async {
+    await resolveTestCode('''
+Foo s = '';
+''');
+    _assertMatcher('Foo',
+        expectedComponents: ['Foo'], expectedKinds: typeKinds);
+  }
+}
+
+@reflectiveTest
+class ElementMatcherImportsTest extends AbstractElementMatcherTest {
+  Future<void> test_imports_noImports() async {
+    await resolveTestCode('''
+String s = '';
+''');
+    _assertMatcher('s', expectedUris: ['dart:core']);
+  }
+
+  Future<void> test_imports_package() async {
+    var packageRootPath = '$workspaceRootPath/other';
+    newFile('$packageRootPath/lib/other.dart', content: '');
+    writeTestPackageConfig(
+        config: PackageConfigFileBuilder()
+          ..add(name: 'other', rootPath: packageRootPath));
+
+    await resolveTestCode('''
+import 'package:other/other.dart';
+
+String s = '';
+''');
+    _assertMatcher('s',
+        expectedUris: ['dart:core', 'package:other/other.dart']);
+  }
+
+  Future<void> test_imports_relative() async {
+    addSource('$testPackageLibPath/a.dart', '');
+    await resolveTestCode('''
+import 'a.dart';
+
+String s = '';
+''');
+    _assertMatcher('s', expectedUris: ['dart:core', 'package:test/a.dart']);
+  }
+
+  Future<void> test_imports_sdkLibraries() async {
+    await resolveTestCode('''
+import 'dart:math';
+
+int f(int x, int y) => max(x, y);
+''');
+    _assertMatcher('f', expectedUris: ['dart:core', 'dart:math']);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
index 4eb8242..22ee1a1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
@@ -8,6 +8,7 @@
 import 'code_fragment_parser_test.dart' as code_fragment_parser;
 import 'code_template_test.dart' as code_template;
 import 'diagnostics/test_all.dart' as diagnostics;
+import 'element_matcher_test.dart' as element_matcher;
 import 'end_to_end_test.dart' as end_to_end;
 import 'flutter_use_case_test.dart' as flutter_use_case;
 import 'modify_parameters_test.dart' as modify_parameters;
@@ -22,6 +23,7 @@
     code_fragment_parser.main();
     code_template.main();
     diagnostics.main();
+    element_matcher.main();
     end_to_end.main();
     flutter_use_case.main();
     modify_parameters.main();
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index b3acb30..e629ce0 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -230,7 +230,19 @@
       Set<Uri> invalidatedUris = this.invalidatedUris.toSet();
       invalidateNotKeptUserBuilders(invalidatedUris);
       ReusageResult reusedResult =
-          computeReusedLibraries(invalidatedUris, uriTranslator);
+          computeReusedLibraries(invalidatedUris, uriTranslator, entryPoints);
+
+      // Use the reused libraries to re-write entry-points.
+      if (reusedResult.arePartsUsedAsEntryPoints()) {
+        for (int i = 0; i < entryPoints.length; i++) {
+          Uri entryPoint = entryPoints[i];
+          Uri redirect =
+              reusedResult.getLibraryUriForPartUsedAsEntryPoint(entryPoint);
+          if (redirect != null) {
+            entryPoints[i] = redirect;
+          }
+        }
+      }
 
       // Experimental invalidation initialization (e.g. figure out if we can).
       ExperimentalInvalidation experimentalInvalidation =
@@ -1440,18 +1452,26 @@
   /// any saved component problems for such builders.
   List<Library> computeTransitiveClosure(
       List<Library> inputLibraries,
-      List<Uri> entries,
+      List<Uri> entryPoints,
       List<LibraryBuilder> reusedLibraries,
       ClassHierarchy hierarchy,
       UriTranslator uriTranslator,
       Map<Uri, Source> uriToSource,
       [List<Library> inputLibrariesFiltered]) {
     List<Library> result = <Library>[];
+    Map<Uri, Uri> partUriToLibraryImportUri = <Uri, Uri>{};
     Map<Uri, Library> libraryMap = <Uri, Library>{};
     Map<Uri, Library> potentiallyReferencedLibraries = <Uri, Library>{};
     Map<Uri, Library> potentiallyReferencedInputLibraries = <Uri, Library>{};
     for (Library library in inputLibraries) {
       libraryMap[library.importUri] = library;
+      if (library.parts.isNotEmpty) {
+        for (int partIndex = 0; partIndex < library.parts.length; partIndex++) {
+          LibraryPart part = library.parts[partIndex];
+          Uri partUri = getPartUri(library.importUri, part);
+          partUriToLibraryImportUri[partUri] = library.importUri;
+        }
+      }
       if (library.importUri.scheme == "dart") {
         result.add(library);
         inputLibrariesFiltered?.add(library);
@@ -1460,9 +1480,6 @@
         potentiallyReferencedInputLibraries[library.importUri] = library;
       }
     }
-
-    List<Uri> worklist = <Uri>[];
-    worklist.addAll(entries);
     for (LibraryBuilder libraryBuilder in reusedLibraries) {
       if (libraryBuilder.importUri.scheme == "dart" &&
           !libraryBuilder.isSynthetic) {
@@ -1473,6 +1490,19 @@
       libraryMap[libraryBuilder.importUri] = lib;
     }
 
+    List<Uri> worklist = <Uri>[];
+    for (Uri entry in entryPoints) {
+      if (libraryMap.containsKey(entry)) {
+        worklist.add(entry);
+      } else {
+        // If the entry is a part redirect to the "main" entry.
+        Uri partTranslation = partUriToLibraryImportUri[entry];
+        if (partTranslation != null) {
+          worklist.add(partTranslation);
+        }
+      }
+    }
+
     LibraryGraph graph = new LibraryGraph(libraryMap);
     Set<Uri> partsUsed = new Set<Uri>();
     while (worklist.isNotEmpty && potentiallyReferencedLibraries.isNotEmpty) {
@@ -1928,8 +1958,8 @@
   }
 
   /// Internal method.
-  ReusageResult computeReusedLibraries(
-      Set<Uri> invalidatedUris, UriTranslator uriTranslator) {
+  ReusageResult computeReusedLibraries(Set<Uri> invalidatedUris,
+      UriTranslator uriTranslator, List<Uri> entryPoints) {
     Set<Uri> seenUris = new Set<Uri>();
     List<LibraryBuilder> reusedLibraries = <LibraryBuilder>[];
     for (int i = 0; i < platformBuilders.length; i++) {
@@ -1938,7 +1968,7 @@
       reusedLibraries.add(builder);
     }
     if (userCode == null && userBuilders == null) {
-      return new ReusageResult(const {}, const {}, false, reusedLibraries);
+      return new ReusageResult.reusedLibrariesOnly(reusedLibraries);
     }
     bool invalidatedBecauseOfPackageUpdate = false;
     Set<LibraryBuilder> directlyInvalidated = new Set<LibraryBuilder>();
@@ -1946,6 +1976,7 @@
 
     // Maps all non-platform LibraryBuilders from their import URI.
     Map<Uri, LibraryBuilder> builders = <Uri, LibraryBuilder>{};
+    Map<Uri, LibraryBuilder> partUriToParent = <Uri, LibraryBuilder>{};
 
     // Invalidated URIs translated back to their import URI (package:, dart:,
     // etc.).
@@ -1989,7 +2020,10 @@
         invalidatedImportUris.add(uri);
       }
       if (libraryBuilder is SourceLibraryBuilder) {
+        // TODO(jensj): This shouldn't be possible anymore.
         for (LibraryBuilder part in libraryBuilder.parts) {
+          partUriToParent[part.importUri] = libraryBuilder;
+          partUriToParent[part.fileUri] = libraryBuilder;
           if (isInvalidated(part.importUri, part.fileUri)) {
             invalidatedImportUris.add(part.importUri);
             builders[part.importUri] = part;
@@ -2000,6 +2034,8 @@
           Uri partUri = getPartUri(libraryBuilder.importUri, part);
           Uri fileUri = getPartFileUri(
               libraryBuilder.library.fileUri, part, uriTranslator);
+          partUriToParent[partUri] = libraryBuilder;
+          partUriToParent[fileUri] = libraryBuilder;
 
           if (isInvalidated(partUri, fileUri)) {
             invalidatedImportUris.add(partUri);
@@ -2078,8 +2114,21 @@
       reusedLibraries.add(builder);
     }
 
-    return new ReusageResult(notReusedLibraries, directlyInvalidated,
-        invalidatedBecauseOfPackageUpdate, reusedLibraries);
+    ReusageResult result = new ReusageResult(
+        notReusedLibraries,
+        directlyInvalidated,
+        invalidatedBecauseOfPackageUpdate,
+        reusedLibraries);
+
+    for (Uri entryPoint in entryPoints) {
+      LibraryBuilder parent = partUriToParent[entryPoint];
+      if (reusedLibraries.contains(parent)) {
+        result.registerLibraryUriForPartUsedAsEntryPoint(
+            entryPoint, parent.importUri);
+      }
+    }
+
+    return result;
   }
 
   @override
@@ -2153,13 +2202,32 @@
   final Set<LibraryBuilder> directlyInvalidated;
   final bool invalidatedBecauseOfPackageUpdate;
   final List<LibraryBuilder> reusedLibraries;
+  final Map<Uri, Uri> _reusedLibrariesPartsToParentForEntryPoints;
+
+  ReusageResult.reusedLibrariesOnly(this.reusedLibraries)
+      : notReusedLibraries = const {},
+        directlyInvalidated = const {},
+        invalidatedBecauseOfPackageUpdate = false,
+        _reusedLibrariesPartsToParentForEntryPoints = const {};
 
   ReusageResult(this.notReusedLibraries, this.directlyInvalidated,
       this.invalidatedBecauseOfPackageUpdate, this.reusedLibraries)
-      : assert(notReusedLibraries != null),
+      : _reusedLibrariesPartsToParentForEntryPoints = {},
+        assert(notReusedLibraries != null),
         assert(directlyInvalidated != null),
         assert(invalidatedBecauseOfPackageUpdate != null),
         assert(reusedLibraries != null);
+
+  void registerLibraryUriForPartUsedAsEntryPoint(
+      Uri entryPoint, Uri importUri) {
+    _reusedLibrariesPartsToParentForEntryPoints[entryPoint] = importUri;
+  }
+
+  bool arePartsUsedAsEntryPoints() =>
+      _reusedLibrariesPartsToParentForEntryPoints.isNotEmpty;
+
+  Uri getLibraryUriForPartUsedAsEntryPoint(Uri entryPoint) =>
+      _reusedLibrariesPartsToParentForEntryPoints[entryPoint];
 }
 
 class ExperimentalInvalidation {
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index 70a5360..84c74bc 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -831,18 +831,20 @@
       }
 
       if (!noFullComponent) {
-        List<Library> entryLib = component.libraries
-            .where((Library lib) =>
-                entries.contains(lib.importUri) ||
-                entries.contains(lib.fileUri))
-            .toList();
-        if (entryLib.length != entries.length) {
-          return new Result<TestData>(
-              data,
-              UnexpectedEntryToLibraryCount,
-              "Expected the entries to become libraries. "
-              "Got ${entryLib.length} libraries for the expected "
-              "${entries.length} entries.");
+        if (world["checkEntries"] != false) {
+          List<Library> entryLib = component.libraries
+              .where((Library lib) =>
+                  entries.contains(lib.importUri) ||
+                  entries.contains(lib.fileUri))
+              .toList();
+          if (entryLib.length != entries.length) {
+            return new Result<TestData>(
+                data,
+                UnexpectedEntryToLibraryCount,
+                "Expected the entries to become libraries. "
+                "Got ${entryLib.length} libraries for the expected "
+                "${entries.length} entries.");
+          }
         }
       }
       if (compiler.initializedFromDill != expectInitializeFromDill) {
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml
new file mode 100644
index 0000000..aba97dff
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml
@@ -0,0 +1,32 @@
+# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    checkEntries: false
+    sources:
+      main.dart: |
+        part of 'lib.dart';
+        partMethod() {}
+      lib.dart: |
+        part 'main.dart';
+        main() {}
+    expectedLibraryCount: 1
+
+  - entry: main.dart
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    expectedLibraryCount: 1
+
+  - entry: main.dart
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - lib.dart
+    expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml
new file mode 100644
index 0000000..e599398
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml
@@ -0,0 +1,34 @@
+# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+type: newworld
+worlds:
+  - entry: package:foo/main.dart
+    checkEntries: false
+    sources:
+      .packages: |
+        foo:.
+      main.dart: |
+        part of 'lib.dart';
+        partMethod() {}
+      lib.dart: |
+        part 'main.dart';
+        main() {}
+    expectedLibraryCount: 1
+
+  - entry: package:foo/main.dart
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    expectedLibraryCount: 1
+
+  - entry: package:foo/main.dart
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - lib.dart
+    expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml
new file mode 100644
index 0000000..3d91b09
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml
@@ -0,0 +1,37 @@
+# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    warnings: true
+    checkEntries: false
+    sources:
+      .packages: |
+        foo:.
+      main.dart: |
+        part of 'lib.dart';
+        partMethod() {}
+      lib.dart: |
+        part 'main.dart';
+        main() {}
+    expectedLibraryCount: 1
+
+  - entry: main.dart
+    warnings: true
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    expectedLibraryCount: 1
+
+  - entry: main.dart
+    warnings: true
+    checkEntries: false
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - lib.dart
+    expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+  part main.dart;
+  static method main() → dynamic {}
+  static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/tools/VERSION b/tools/VERSION
index e955a98..61c91e3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 230
+PRERELEASE 231
 PRERELEASE_PATCH 0
\ No newline at end of file