Version 2.12.0-184.0.dev

Merge commit 'ea775a6a0f1a360cdcb5f9e80684d8b2dcff381e' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/make_variable_nullable.dart b/pkg/analysis_server/lib/src/services/correction/dart/make_variable_nullable.dart
index acd8708..fcc42fd 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/make_variable_nullable.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/make_variable_nullable.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -38,6 +39,8 @@
         await _forFieldFormalParameter(builder, node, parent);
       } else if (parent is AssignmentExpression &&
           parent.rightHandSide == node) {
+        await _forAssignment(builder, node as Expression, parent);
+      } else if (parent is VariableDeclaration && parent.initializer == node) {
         await _forVariableDeclaration(builder, node, parent);
       }
     }
@@ -71,6 +74,31 @@
     return null;
   }
 
+  Future<void> _forAssignment(ChangeBuilder builder, Expression node,
+      AssignmentExpression parent) async {
+    var leftHandSide = parent.leftHandSide;
+    if (leftHandSide is SimpleIdentifier) {
+      var element = leftHandSide.staticElement;
+      if (element is LocalVariableElement) {
+        var oldType = element.type;
+        var newType = node.staticType;
+        if (node is NullLiteral) {
+          newType = (oldType as InterfaceTypeImpl)
+              .withNullability(NullabilitySuffix.question);
+        } else if (!typeSystem.isAssignableTo(
+            oldType, typeSystem.promoteToNonNull(newType))) {
+          return;
+        }
+        var declarationList =
+            _findDeclaration(element, parent.thisOrAncestorOfType<Block>());
+        if (declarationList == null || declarationList.variables.length > 1) {
+          return;
+        }
+        await _updateVariableType(builder, declarationList, newType);
+      }
+    }
+  }
+
   /// Makes [parameter] nullable if possible.
   Future<void> _forFieldFormalParameter(ChangeBuilder builder,
       SimpleIdentifier name, FieldFormalParameter parameter) async {
@@ -119,47 +147,26 @@
     });
   }
 
-  Future<void> _forVariableDeclaration(
-      ChangeBuilder builder, AstNode node, AssignmentExpression parent) async {
-    var leftHandSide = parent.leftHandSide;
-    if (leftHandSide is SimpleIdentifier) {
-      var element = leftHandSide.staticElement;
-      if (element is LocalVariableElement) {
-        var oldType = element.type;
-        var newType = (node as Expression).staticType;
-        if (node is NullLiteral) {
-          newType = (oldType as InterfaceTypeImpl)
-              .withNullability(NullabilitySuffix.question);
-        } else if (!typeSystem.isAssignableTo(
-            oldType, typeSystem.promoteToNonNull(newType))) {
-          return;
-        }
-        var declarationList =
-            _findDeclaration(element, parent.thisOrAncestorOfType<Block>());
-        if (declarationList == null || declarationList.variables.length > 1) {
-          return;
-        }
-        var variable = declarationList.variables[0];
-        _variableName = variable.name.name;
-        await builder.addDartFileEdit(file, (builder) {
-          var keyword = declarationList.keyword;
-          if (keyword != null && keyword.type == Keyword.VAR) {
-            builder.addReplacement(range.token(keyword), (builder) {
-              builder.writeType(newType);
-            });
-          } else if (keyword == null) {
-            if (declarationList.type == null) {
-              builder.addInsertion(variable.offset, (builder) {
-                builder.writeType(newType);
-                builder.write(' ');
-              });
-            } else {
-              builder.addSimpleInsertion(declarationList.type.end, '?');
-            }
-          }
-        });
-      }
+  Future<void> _forVariableDeclaration(ChangeBuilder builder, Expression node,
+      VariableDeclaration parent) async {
+    var grandParent = parent.parent;
+    if (grandParent is! VariableDeclarationList) {
+      return;
     }
+    var declarationList = grandParent as VariableDeclarationList;
+    if (declarationList.variables.length > 1) {
+      return;
+    }
+    var oldType = parent.declaredElement.type;
+    var newType = node.staticType;
+    if (node is NullLiteral) {
+      newType = (oldType as InterfaceTypeImpl)
+          .withNullability(NullabilitySuffix.question);
+    } else if (!typeSystem.isAssignableTo(
+        oldType, typeSystem.promoteToNonNull(newType))) {
+      return;
+    }
+    await _updateVariableType(builder, declarationList, newType);
   }
 
   bool _typeCanBeMadeNullable(TypeAnnotation typeAnnotation) {
@@ -173,6 +180,31 @@
     return true;
   }
 
+  /// Add edits to the [builder] to update the type in the [declarationList] to
+  /// match the [newType].
+  Future<void> _updateVariableType(ChangeBuilder builder,
+      VariableDeclarationList declarationList, DartType newType) async {
+    var variable = declarationList.variables[0];
+    _variableName = variable.name.name;
+    await builder.addDartFileEdit(file, (builder) {
+      var keyword = declarationList.keyword;
+      if (keyword != null && keyword.type == Keyword.VAR) {
+        builder.addReplacement(range.token(keyword), (builder) {
+          builder.writeType(newType);
+        });
+      } else if (keyword == null) {
+        if (declarationList.type == null) {
+          builder.addInsertion(variable.offset, (builder) {
+            builder.writeType(newType);
+            builder.write(' ');
+          });
+        } else {
+          builder.addSimpleInsertion(declarationList.type.end, '?');
+        }
+      }
+    });
+  }
+
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
   static MakeVariableNullable newInstance() => MakeVariableNullable();
 }
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 49b10c9..3260c5d 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -71,8 +71,9 @@
   Future<List<SearchMatch>> searchMemberDeclarations(String name) async {
     var allDeclarations = <SearchMatch>[];
     var drivers = _drivers.toList();
+    var searchedFiles = _createSearchedFiles(drivers);
     for (var driver in drivers) {
-      var elements = await driver.search.classMembers(name);
+      var elements = await driver.search.classMembers(name, searchedFiles);
       allDeclarations.addAll(elements.map(SearchMatchImpl.forElement));
     }
     return allDeclarations;
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 9c2c7e9..14990fd 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -49,6 +49,17 @@
   final Map<String, String> _declaredVariables = {};
   AnalysisContextCollection _analysisContextCollection;
 
+  List<AnalysisContext> get allContexts {
+    _createAnalysisContexts();
+    return _analysisContextCollection.contexts;
+  }
+
+  List<AnalysisDriver> get allDrivers {
+    return allContexts
+        .map((e) => (e as DriverBasedAnalysisContext).driver)
+        .toList();
+  }
+
   /// The file system specific `/home/test/analysis_options.yaml` path.
   String get analysisOptionsPath =>
       convertPath('/home/test/analysis_options.yaml');
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 9c46788..f090ec9 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -4,141 +4,155 @@
 
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/context/packages.dart';
-import 'package:analyzer/src/dart/analysis/byte_store.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/performance_logger.dart';
-import 'package:analyzer/src/file_system/file_system.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/source/package_map_resolver.dart';
-import 'package:analyzer/src/test_utilities/mock_sdk.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer/src/test_utilities/find_element.dart';
+import 'package:analyzer/src/test_utilities/find_node.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 '../../abstract_context.dart';
+
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(SearchEngineImplTest);
   });
 }
 
+/// TODO(scheglov) This class does not really belong here.
+/// Consider merging it into [AbstractContextTest].
+class PubPackageResolutionTest extends AbstractContextTest {
+  ResolvedUnitResult result;
+  FindNode findNode;
+  FindElement findElement;
+
+  String get testFilePath => '$testPackageLibPath/test.dart';
+
+  void addTestFile(String content) {
+    newFile(testFilePath, content: content);
+  }
+
+  /// Resolve the file with the [path] into [result].
+  Future<void> resolveFile2(String path) async {
+    path = convertPath(path);
+
+    result = await resolveFile(path);
+    expect(result.state, ResultState.VALID);
+
+    findNode = FindNode(result.content, result.unit);
+    findElement = FindElement(result.unit);
+  }
+
+  /// Put the [code] into the test file, and resolve it.
+  Future<void> resolveTestCode(String code) {
+    addTestFile(code);
+    return resolveTestFile();
+  }
+
+  Future<void> resolveTestFile() {
+    return resolveFile2(testFilePath);
+  }
+}
+
 @reflectiveTest
-class SearchEngineImplTest with ResourceProviderMixin {
-  DartSdk sdk;
-  final ByteStore byteStore = MemoryByteStore();
-  final FileContentOverlay contentOverlay = FileContentOverlay();
+class SearchEngineImplTest extends PubPackageResolutionTest {
+  SearchEngineImpl get searchEngine {
+    return SearchEngineImpl(allDrivers);
+  }
 
-  final StringBuffer logBuffer = StringBuffer();
-  PerformanceLog logger;
-
-  AnalysisDriverScheduler scheduler;
-
+  @override
   void setUp() {
-    sdk = MockSdk(resourceProvider: resourceProvider);
-    logger = PerformanceLog(logBuffer);
-    scheduler = AnalysisDriverScheduler(logger);
-    scheduler.start();
+    super.setUp();
+
+    // TODO(scheglov) This is not ideal.
+    // We write into the root because we choose the workspace root to
+    // index `aaa/lib/a.dart`. But ideally we should use the context root
+    // that contains it (i.e. `root/aaa`), or a context root where it is a
+    // package (e.g. `root/test`).
+    writePackageConfig(
+      '$workspaceRootPath/.dart_tool/package_config.json',
+      PackageConfigFileBuilder()
+        ..add(name: 'test', rootPath: testPackageRootPath),
+    );
   }
 
   Future<void> test_membersOfSubtypes_hasMembers() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   void a() {}
   void b() {}
   void c() {}
 }
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 import 'a.dart';
 class B extends A {
   void a() {}
 }
-''').path;
-    var c = newFile('/test/c.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/c.dart', content: '''
 import 'a.dart';
 class C extends A {
   void b() {}
 }
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
+    await resolveFile2('$testPackageLibPath/a.dart');
+    var A = findElement.class_('A');
 
-    driver1.addFile(a);
-    driver2.addFile(b);
-    driver2.addFile(c);
-    await scheduler.waitForIdle();
-
-    var resultA = await driver1.getResult(a);
-    var elementA = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
-    var members = await searchEngine.membersOfSubtypes(elementA);
+    var members = await searchEngine.membersOfSubtypes(A);
     expect(members, unorderedEquals(['a', 'b']));
   }
 
   Future<void> test_membersOfSubtypes_noMembers() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   void a() {}
   void b() {}
   void c() {}
 }
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 import 'a.dart';
 class B extends A {}
-''').path;
+''');
 
-    var driver = _newDriver();
+    await resolveFile2('$testPackageLibPath/a.dart');
+    var A = findElement.class_('A');
 
-    driver.addFile(a);
-    driver.addFile(b);
-    await scheduler.waitForIdle();
-
-    var resultA = await driver.getResult(a);
-    var elementA = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver]);
-    var members = await searchEngine.membersOfSubtypes(elementA);
+    var members = await searchEngine.membersOfSubtypes(A);
     expect(members, isEmpty);
   }
 
   Future<void> test_membersOfSubtypes_noSubtypes() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   void a() {}
   void b() {}
   void c() {}
 }
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 import 'a.dart';
 class B {
   void a() {}
 }
-''').path;
+''');
 
-    var driver = _newDriver();
+    await resolveFile2('$testPackageLibPath/a.dart');
+    var A = findElement.class_('A');
 
-    driver.addFile(a);
-    driver.addFile(b);
-    await scheduler.waitForIdle();
-
-    var resultA = await driver.getResult(a);
-    var elementA = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver]);
-    var members = await searchEngine.membersOfSubtypes(elementA);
+    var members = await searchEngine.membersOfSubtypes(A);
     expect(members, isNull);
   }
 
   Future<void> test_membersOfSubtypes_private() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   void a() {}
   void _b() {}
@@ -147,8 +161,9 @@
 class B extends A {
   void _b() {}
 }
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 import 'a.dart';
 class C extends A {
   void a() {}
@@ -157,38 +172,25 @@
 class D extends B {
   void _c() {}
 }
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
+    await resolveFile2('$testPackageLibPath/a.dart');
+    var A = findElement.class_('A');
 
-    driver1.addFile(a);
-    driver2.addFile(b);
-    await scheduler.waitForIdle();
-
-    var resultA = await driver1.getResult(a);
-    var elementA = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
-    var members = await searchEngine.membersOfSubtypes(elementA);
+    var members = await searchEngine.membersOfSubtypes(A);
     expect(members, unorderedEquals(['a', '_b']));
   }
 
   Future<void> test_searchAllSubtypes() async {
-    var p = newFile('/test.dart', content: '''
+    await resolveTestCode('''
 class T {}
 class A extends T {}
 class B extends A {}
 class C implements B {}
-''').path;
+''');
 
-    var driver = _newDriver();
-    driver.addFile(p);
+    var element = findElement.class_('T');
 
-    var resultA = await driver.getResult(p);
-    var element = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver]);
     var subtypes = await searchEngine.searchAllSubtypes(element);
     expect(subtypes, hasLength(3));
     _assertContainsClass(subtypes, 'A');
@@ -197,35 +199,31 @@
   }
 
   Future<void> test_searchAllSubtypes_acrossDrivers() async {
-    var a = newFile('/test/a.dart', content: '''
+    var aaaRootPath = _configureForPackage_aaa();
+
+    newFile('$aaaRootPath/lib/a.dart', content: '''
 class T {}
 class A extends T {}
-''').path;
-    var b = newFile('/test/b.dart', content: '''
-import 'a.dart';
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
+import 'package:aaa/a.dart';
 class B extends A {}
 class C extends B {}
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
+    await resolveFile2('$aaaRootPath/lib/a.dart');
+    var element = findElement.class_('T');
 
-    driver1.addFile(a);
-    driver2.addFile(b);
-
-    var resultA = await driver1.getResult(a);
-    var element = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var subtypes = await searchEngine.searchAllSubtypes(element);
     expect(subtypes, hasLength(3));
-    expect(subtypes, contains(predicate((ClassElement e) => e.name == 'A')));
-    expect(subtypes, contains(predicate((ClassElement e) => e.name == 'B')));
-    expect(subtypes, contains(predicate((ClassElement e) => e.name == 'C')));
+    _assertContainsClass(subtypes, 'A');
+    _assertContainsClass(subtypes, 'B');
+    _assertContainsClass(subtypes, 'C');
   }
 
   Future<void> test_searchAllSubtypes_mixin() async {
-    var p = newFile('/test.dart', content: '''
+    await resolveTestCode('''
 class T {}
 
 mixin A on T {}
@@ -235,15 +233,10 @@
 
 mixin D on C {}
 mixin E implements C {}
-''').path;
+''');
 
-    var driver = _newDriver();
-    driver.addFile(p);
+    var element = findElement.class_('T');
 
-    var resultA = await driver.getResult(p);
-    var element = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver]);
     var subtypes = await searchEngine.searchAllSubtypes(element);
     expect(subtypes, hasLength(5));
     _assertContainsClass(subtypes, 'A');
@@ -268,20 +261,9 @@
 int test;
 ''';
 
-    var a = newFile('/test/a.dart', content: codeA).path;
-    var b = newFile('/test/b.dart', content: codeB).path;
+    newFile('$testPackageLibPath/a.dart', content: codeA);
+    newFile('$testPackageLibPath/b.dart', content: codeB);
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
-
-    driver1.addFile(a);
-    driver2.addFile(b);
-
-    while (scheduler.isAnalyzing) {
-      await Future.delayed(Duration(milliseconds: 1));
-    }
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var matches = await searchEngine.searchMemberDeclarations('test');
     expect(matches, hasLength(2));
 
@@ -299,28 +281,22 @@
   }
 
   Future<void> test_searchMemberReferences() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   int test;
 }
 foo(p) {
   p.test;
 }
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 import 'a.dart';
 bar(p) {
   p.test = 1;
 }
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
-
-    driver1.addFile(a);
-    driver2.addFile(b);
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var matches = await searchEngine.searchMemberReferences('test');
     expect(matches, hasLength(2));
     expect(
@@ -334,25 +310,19 @@
   }
 
   Future<void> test_searchReferences() async {
-    var a = newFile('/test/a.dart', content: '''
+    var aaaRootPath = _configureForPackage_aaa();
+
+    newFile('$aaaRootPath/lib/a.dart', content: '''
 class T {}
 T a;
-''').path;
-    var b = newFile('/test/b.dart', content: '''
-import 'a.dart';
+''');
+
+    await resolveTestCode('''
+import 'package:aaa/a.dart';
 T b;
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
-
-    driver1.addFile(a);
-    driver2.addFile(b);
-
-    var resultA = await driver1.getResult(a);
-    var element = resultA.unit.declaredElement.types[0];
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
+    var element = findElement.importFind('package:aaa/a.dart').class_('T');
     var matches = await searchEngine.searchReferences(element);
     expect(matches, hasLength(2));
     expect(
@@ -362,24 +332,20 @@
   }
 
   Future<void> test_searchReferences_discover_owned() async {
-    var t = newFile('/test/lib/t.dart', content: '''
-import 'package:aaa/a.dart';
-int t;
-''').path;
-    var a = newFile('/aaa/lib/a.dart', content: '''
+    var aaaRootPath = _configureForPackage_aaa();
+
+    var a = newFile('$aaaRootPath/lib/a.dart', content: '''
 int a;
 ''').path;
 
-    var driver1 = _newDriver(packageUriResolver: _mapUriResolver('aaa', a));
-    var driver2 = _newDriver();
+    var t = newFile('$testPackageLibPath/lib/t.dart', content: '''
+import 'package:aaa/a.dart';
+int t;
+''').path;
 
-    driver1.addFile(t);
-    driver2.addFile(a);
-
-    var coreLib = await driver1.getLibraryByUri('dart:core');
+    var coreLib = await driverFor(testFilePath).getLibraryByUri('dart:core');
     var intElement = coreLib.getType('int');
 
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var matches = await searchEngine.searchReferences(intElement);
 
     void assertHasOne(String path, String name) {
@@ -394,26 +360,18 @@
   }
 
   Future<void> test_searchTopLevelDeclarations() async {
-    var a = newFile('/test/a.dart', content: '''
+    newFile('$testPackageLibPath/a.dart', content: '''
 class A {}
 int a;
-''').path;
-    var b = newFile('/test/b.dart', content: '''
+''');
+
+    newFile('$testPackageLibPath/b.dart', content: '''
 class B {}
 get b => 42;
-''').path;
+''');
 
-    var driver1 = _newDriver();
-    var driver2 = _newDriver();
+    await _ensureContainedFilesKnown();
 
-    driver1.addFile(a);
-    driver2.addFile(b);
-
-    while (scheduler.isAnalyzing) {
-      await Future.delayed(Duration(milliseconds: 1));
-    }
-
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var matches = await searchEngine.searchTopLevelDeclarations('.*');
     matches.removeWhere((match) => match.libraryElement.isInSdk);
     expect(matches, hasLength(4));
@@ -431,31 +389,27 @@
   }
 
   Future<void> test_searchTopLevelDeclarations_dependentPackage() async {
-    var a = newFile('/a/lib/a.dart', content: '''
-class A {}
-''').path;
-    var driver1 = _newDriver();
-    driver1.addFile(a);
+    var aaaRootPath = _configureForPackage_aaa();
 
-    // The package:b uses the class A from the package:a,
-    // so it sees the declaration the element A.
-    var b = newFile('/b/lib/b.dart', content: '''
-import 'package:a/a.dart';
+    newFile('$aaaRootPath/lib/a.dart', content: '''
+class A {}
+''');
+
+    // The `package:test` uses the class `A` from the `package:aaa`.
+    // So it sees the declaration the element `A`.
+    newFile('$testFilePath', content: '''
+import 'package:aaa/a.dart';
 class B extends A {}
 ''');
-    var driver2 = _newDriver(packageUriResolver: _mapUriResolver('a', a));
-    driver2.addFile(b.path);
 
-    while (scheduler.isAnalyzing) {
-      await Future.delayed(Duration(milliseconds: 1));
-    }
+    await _ensureContainedFilesKnown();
 
-    var searchEngine = SearchEngineImpl([driver1, driver2]);
     var matches = await searchEngine.searchTopLevelDeclarations('.*');
-    // We get exactly two items: A and B.
-    // I.e. we get exactly one A.
-    expect(
-        matches.where((match) => !match.libraryElement.isInSdk), hasLength(2));
+    matches.removeWhere((match) => match.libraryElement.isInSdk);
+
+    // We get exactly two items: `A` and `B`.
+    // Specifically, we get exactly one `A`.
+    expect(matches, hasLength(2));
 
     void assertHasOneElement(String name) {
       var nameMatches = matches.where((SearchMatch m) =>
@@ -467,25 +421,35 @@
     assertHasOneElement('B');
   }
 
-  UriResolver _mapUriResolver(String packageName, String path) {
-    return PackageMapUriResolver(resourceProvider, {
-      packageName: [resourceProvider.getFile(path).parent]
-    });
+  String _configureForPackage_aaa() {
+    var aaaRootPath = '$workspaceRootPath/aaa';
+
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath),
+    );
+
+    // TODO(scheglov) This is not ideal.
+    // We write into the root because we choose the workspace root to
+    // index `aaa/lib/a.dart`. But ideally we should use the context root
+    // that contains it (i.e. `root/aaa`), or a context root where it is a
+    // package (e.g. `root/test`).
+    writePackageConfig(
+      '$workspaceRootPath/.dart_tool/package_config.json',
+      PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath)
+        ..add(name: 'test', rootPath: testPackageRootPath),
+    );
+    return aaaRootPath;
   }
 
-  AnalysisDriver _newDriver({UriResolver packageUriResolver}) {
-    var resolvers = <UriResolver>[
-      DartUriResolver(sdk),
-      ResourceUriResolver(resourceProvider)
-    ];
-    if (packageUriResolver != null) {
-      resolvers.add(packageUriResolver);
+  Future _ensureContainedFilesKnown() async {
+    for (var driver in allDrivers) {
+      var contextRoot = driver.analysisContext.contextRoot;
+      for (var file in contextRoot.analyzedFiles()) {
+        await driver.getUnitElement(file);
+      }
     }
-    resolvers.add(ResourceUriResolver(resourceProvider));
-
-    return AnalysisDriver(scheduler, logger, resourceProvider, byteStore,
-        contentOverlay, null, SourceFactory(resolvers), AnalysisOptionsImpl(),
-        packages: Packages.empty, enableIndex: true);
   }
 
   static void _assertContainsClass(Set<ClassElement> subtypes, String name) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_variable_nullable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_variable_nullable_test.dart
index 804f106..f619f67 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/make_variable_nullable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_variable_nullable_test.dart
@@ -29,7 +29,9 @@
 }
 ''');
     // TODO(srawlins): Remove the type if the quick fix as is would use the same
-    // type as the field's type.
+    //  type as the field's type. (brianwilkerson) I would argue that removing
+    //  the type should be a separate fix/assist. There was a reason why the
+    //  user used an explicit type, and we shouldn't remove it when it's valid.
     await assertHasFix('''
 class C {
   String? s;
@@ -95,6 +97,55 @@
     await assertNoFix();
   }
 
+  Future<void> test_localVariable_initializedToNull() async {
+    await resolveTestCode('''
+void f() {
+  String s = null;
+  print(s);
+}
+''');
+    await assertHasFix('''
+void f() {
+  String? s = null;
+  print(s);
+}
+''');
+  }
+
+  Future<void> test_localVariable_type() async {
+    await resolveTestCode('''
+void f() {
+  String s = '';
+  s = null;
+  print(s);
+}
+''');
+    await assertHasFix('''
+void f() {
+  String? s = '';
+  s = null;
+  print(s);
+}
+''');
+  }
+
+  Future<void> test_localVariable_var() async {
+    await resolveTestCode('''
+void f() {
+  var s = '';
+  s = null;
+  print(s);
+}
+''');
+    await assertHasFix('''
+void f() {
+  String? s = '';
+  s = null;
+  print(s);
+}
+''');
+  }
+
   Future<void> test_multipleVariables() async {
     await resolveTestCode('''
 void f() {
@@ -159,38 +210,4 @@
 void f<T>({T? s}) {}
 ''');
   }
-
-  Future<void> test_type() async {
-    await resolveTestCode('''
-void f() {
-  String s = '';
-  s = null;
-  print(s);
-}
-''');
-    await assertHasFix('''
-void f() {
-  String? s = '';
-  s = null;
-  print(s);
-}
-''');
-  }
-
-  Future<void> test_var() async {
-    await resolveTestCode('''
-void f() {
-  var s = '';
-  s = null;
-  print(s);
-}
-''');
-    await assertHasFix('''
-void f() {
-  String? s = '';
-  s = null;
-  print(s);
-}
-''');
-  }
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index b51c2cf..d9cf7b5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -32,7 +32,8 @@
   Search(this._driver);
 
   /// Returns class or mixin members with the given [name].
-  Future<List<Element>> classMembers(String name) async {
+  Future<List<Element>> classMembers(
+      String name, SearchedFiles searchedFiles) async {
     List<Element> elements = <Element>[];
 
     void addElement(Element element) {
@@ -49,10 +50,12 @@
 
     List<String> files = await _driver.getFilesDefiningClassMemberName(name);
     for (String file in files) {
-      UnitElementResult unitResult = await _driver.getUnitElement(file);
-      if (unitResult != null) {
-        unitResult.element.types.forEach(addElements);
-        unitResult.element.mixins.forEach(addElements);
+      if (searchedFiles.add(file, this)) {
+        UnitElementResult unitResult = await _driver.getUnitElement(file);
+        if (unitResult != null) {
+          unitResult.element.types.forEach(addElements);
+          unitResult.element.mixins.forEach(addElements);
+        }
       }
     }
     return elements;
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index c91db90..646bada 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -84,7 +84,8 @@
 ''');
     var a = findElement.class_('A');
     var b = findElement.class_('B');
-    expect(await driver.search.classMembers('test'),
+
+    expect(await _findClassMembers('test'),
         unorderedEquals([a.methods[0], b.fields[0]]));
   }
 
@@ -92,7 +93,7 @@
     await resolveTestCode('''
 import 'not-dart.txt';
 ''');
-    expect(await driver.search.classMembers('test'), isEmpty);
+    expect(await _findClassMembers('test'), isEmpty);
   }
 
   test_classMembers_mixin() async {
@@ -110,7 +111,7 @@
 ''');
     var a = findElement.mixin('A');
     var b = findElement.mixin('B');
-    expect(await driver.search.classMembers('test'),
+    expect(await _findClassMembers('test'),
         unorderedEquals([a.methods[0], b.fields[0]]));
   }
 
@@ -1827,6 +1828,11 @@
         isQualified: false, isResolved: false, length: length);
   }
 
+  Future<List<Element>> _findClassMembers(String name) {
+    var searchedFiles = SearchedFiles();
+    return driver.search.classMembers(name, searchedFiles);
+  }
+
   Future<void> _verifyNameReferences(
       String name, List<ExpectedResult> expectedMatches) async {
     var searchedFiles = SearchedFiles();
diff --git a/tools/VERSION b/tools/VERSION
index efc228c..f4ded95 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 183
+PRERELEASE 184
 PRERELEASE_PATCH 0
\ No newline at end of file