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