[analyzer] Don't show duplicate code completions for items imported via multiple libraries

Fixes https://github.com/Dart-Code/Dart-Code/issues/3227.

Change-Id: Iac5704fea4f00470040b6b94bbf508dd916ed234
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196923
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny
2021-04-26 16:48:28 +00:00
committed by commit-bot@chromium.org
parent 931f7dc2e6
commit 1e51549fab
2 changed files with 97 additions and 4 deletions
@@ -357,11 +357,15 @@ class CompletionHandler
final key = _createImportedSymbolKey(nameKey, declaringUri);
final importingUris = alreadyImportedSymbols[key];
// Keep it only if there are either:
// - no URIs importing it
// - the URIs importing it include this one
// Keep it only if:
// - no existing imports include it
// (in which case all libraries will be offered as
// auto-imports)
// - this is the first imported URI that includes it
// (we don't want to repeat it for each imported library that
// includes it)
return importingUris == null ||
importingUris.contains('${library.uri}');
importingUris.first == '${library.uri}';
}).map((item) => declarationToCompletionItem(
capabilities,
unit.path!,
@@ -1192,6 +1192,95 @@ main() {
'''));
}
Future<void>
test_suggestionSets_doesNotDuplicate_importedViaMultipleLibraries() async {
// An item that's already imported through multiple libraries that
// export it should not result in multiple entries.
newFile(
join(projectFolderPath, 'lib/source_file.dart'),
content: '''
class MyExportedClass {}
''',
);
newFile(
join(projectFolderPath, 'lib/reexport1.dart'),
content: '''
export 'source_file.dart';
''',
);
newFile(
join(projectFolderPath, 'lib/reexport2.dart'),
content: '''
export 'source_file.dart';
''',
);
final content = '''
import 'reexport1.dart';
import 'reexport2.dart';
main() {
MyExported^
}
''';
final initialAnalysis = waitForAnalysisComplete();
await initialize(
workspaceCapabilities:
withApplyEditSupport(emptyWorkspaceClientCapabilities));
await openFile(mainFileUri, withoutMarkers(content));
await initialAnalysis;
final res = await getCompletion(mainFileUri, positionFromMarker(content));
final completions = res.where((c) => c.label == 'MyExportedClass').toList();
expect(completions, hasLength(1));
}
Future<void>
test_suggestionSets_doesNotDuplicate_importedViaSingleLibrary() async {
// An item that's already imported through a library that exports it
// should not result in multiple entries.
newFile(
join(projectFolderPath, 'lib/source_file.dart'),
content: '''
class MyExportedClass {}
''',
);
newFile(
join(projectFolderPath, 'lib/reexport1.dart'),
content: '''
export 'source_file.dart';
''',
);
newFile(
join(projectFolderPath, 'lib/reexport2.dart'),
content: '''
export 'source_file.dart';
''',
);
final content = '''
import 'reexport1.dart';
main() {
MyExported^
}
''';
final initialAnalysis = waitForAnalysisComplete();
await initialize(
workspaceCapabilities:
withApplyEditSupport(emptyWorkspaceClientCapabilities));
await openFile(mainFileUri, withoutMarkers(content));
await initialAnalysis;
final res = await getCompletion(mainFileUri, positionFromMarker(content));
final completions = res.where((c) => c.label == 'MyExportedClass').toList();
expect(completions, hasLength(1));
}
Future<void> test_suggestionSets_doesNotFilterSymbolsWithSameName() async {
// Classes here are not re-exports, so should not be filtered out.
newFile(