Skip to content

Commit df520c9

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Import library with prefix
[email protected] Fixes #55863 Fixes #41515 Fixes #24338 Change-Id: I8b8457488b55a468d4b3c6d34efffc7436a2ff18 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/389780 Reviewed-by: Phil Quitslund <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Phil Quitslund <[email protected]>
1 parent 09b4ec7 commit df520c9

File tree

5 files changed

+524
-49
lines changed

5 files changed

+524
-49
lines changed

pkg/analysis_server/lib/src/services/correction/dart/import_library.dart

Lines changed: 135 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:analyzer/dart/element/element.dart';
1414
import 'package:analyzer/dart/element/type.dart';
1515
import 'package:analyzer/dart/element/type_system.dart';
1616
import 'package:analyzer/source/source_range.dart';
17+
import 'package:analyzer/src/dart/ast/extensions.dart';
1718
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
1819
import 'package:analyzer/src/dart/resolver/applicable_extensions.dart';
1920
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
@@ -145,28 +146,36 @@ class ImportLibrary extends MultiCorrectionProducer {
145146
List<ResolvedCorrectionProducer> _importLibrary(
146147
FixKind fixKind,
147148
Uri library, {
149+
String? prefix,
148150
bool includeRelativeFix = false,
149151
}) {
150152
if (!includeRelativeFix) {
151-
return [_ImportAbsoluteLibrary(fixKind, library, context: context)];
153+
return [
154+
_ImportAbsoluteLibrary(fixKind, library, prefix, context: context)
155+
];
152156
}
153157
var codeStyleOptions = getCodeStyleOptions(unitResult.file);
154158
if (codeStyleOptions.usePackageUris) {
155-
return [_ImportAbsoluteLibrary(fixKind, library, context: context)];
159+
return [
160+
_ImportAbsoluteLibrary(fixKind, library, prefix, context: context)
161+
];
156162
}
157163
if (codeStyleOptions.useRelativeUris) {
158-
return [_ImportRelativeLibrary(fixKind, library, context: context)];
164+
return [
165+
_ImportRelativeLibrary(fixKind, library, prefix, context: context)
166+
];
159167
}
160168
return [
161-
_ImportAbsoluteLibrary(fixKind, library, context: context),
162-
_ImportRelativeLibrary(fixKind, library, context: context),
169+
_ImportAbsoluteLibrary(fixKind, library, prefix, context: context),
170+
_ImportRelativeLibrary(fixKind, library, prefix, context: context),
163171
];
164172
}
165173

166174
Future<List<ResolvedCorrectionProducer>> _importLibraryForElement(
167175
String name,
168-
List<ElementKind> kinds,
169-
) async {
176+
List<ElementKind> kinds, {
177+
String? prefix,
178+
}) async {
170179
// Ignore the element if the name is private.
171180
if (name.startsWith('_')) {
172181
return const [];
@@ -251,24 +260,36 @@ class ImportLibrary extends MultiCorrectionProducer {
251260
// Compute the fix kind.
252261
FixKind fixKind;
253262
if (libraryElement.isInSdk) {
254-
fixKind = DartFixKind.IMPORT_LIBRARY_SDK;
263+
fixKind = prefix.isEmptyOrNull
264+
? DartFixKind.IMPORT_LIBRARY_SDK
265+
: DartFixKind.IMPORT_LIBRARY_SDK_PREFIXED;
255266
} else if (_isLibSrcPath(librarySource.fullName)) {
256267
// Bad: non-API.
257-
fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT3;
268+
fixKind = prefix.isEmptyOrNull
269+
? DartFixKind.IMPORT_LIBRARY_PROJECT3
270+
: DartFixKind.IMPORT_LIBRARY_PROJECT3_PREFIXED;
258271
} else if (declaration.library != libraryElement) {
259272
// Ugly: exports.
260-
fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT2;
273+
fixKind = prefix.isEmptyOrNull
274+
? DartFixKind.IMPORT_LIBRARY_PROJECT2
275+
: DartFixKind.IMPORT_LIBRARY_PROJECT2_PREFIXED;
261276
} else {
262277
// Good: direct declaration.
263-
fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT1;
278+
fixKind = prefix.isEmptyOrNull
279+
? DartFixKind.IMPORT_LIBRARY_PROJECT1
280+
: DartFixKind.IMPORT_LIBRARY_PROJECT1_PREFIXED;
264281
}
265282
// If both files are in the same package's 'lib' folder, also include a
266283
// relative import.
267284
var includeRelativeUri = canBeRelativeImport(
268285
librarySource.uri, this.libraryElement.librarySource.uri);
269286
// Add the fix(es).
270-
producers.addAll(_importLibrary(fixKind, librarySource.uri,
271-
includeRelativeFix: includeRelativeUri));
287+
producers.addAll(_importLibrary(
288+
fixKind,
289+
librarySource.uri,
290+
prefix: prefix,
291+
includeRelativeFix: includeRelativeUri,
292+
));
272293
}
273294
return producers;
274295
}
@@ -284,11 +305,9 @@ class ImportLibrary extends MultiCorrectionProducer {
284305
}
285306

286307
Future<List<ResolvedCorrectionProducer>> _producersForExtension() async {
287-
if (node case SimpleIdentifier(:var name)) {
288-
return await _importLibraryForElement(
289-
name,
290-
const [ElementKind.EXTENSION],
291-
);
308+
if (node case SimpleIdentifier(:var name, :var parent)) {
309+
return await _producersForMethodInvocation(
310+
name, parent, const [ElementKind.EXTENSION]);
292311
}
293312

294313
return const [];
@@ -350,24 +369,70 @@ class ImportLibrary extends MultiCorrectionProducer {
350369

351370
Future<List<ResolvedCorrectionProducer>> _producersForFunction() async {
352371
if (node case SimpleIdentifier(:var name, :var parent)) {
353-
if (parent is MethodInvocation) {
354-
if (parent.realTarget != null || parent.methodName != node) {
355-
return const [];
372+
return await _producersForMethodInvocation(name, parent,
373+
const [ElementKind.FUNCTION, ElementKind.TOP_LEVEL_VARIABLE]);
374+
}
375+
376+
return const [];
377+
}
378+
379+
/// Returns a list of import corrections considering the [name] and [parent].
380+
///
381+
/// If the [parent] is a [MethodInvocation] it can be a method invocation or
382+
/// a prefixed identifier. So we calculate both import options for this case.
383+
///
384+
/// If we have unresolved code like `foo.bar()` then we have two options:
385+
/// - Import of some library, prefixed with `foo`, that contains a top-level
386+
/// function called bar;
387+
/// - Import of some library that contains a top-level propriety or class
388+
/// called `foo` that has a method called `bar` (has to be static for a
389+
/// _class_ with that name).
390+
Future<List<ResolvedCorrectionProducer>> _producersForMethodInvocation(
391+
String name, AstNode? parent, List<ElementKind> kinds) async {
392+
String? prefix;
393+
var producers = <ResolvedCorrectionProducer>[];
394+
if (parent case MethodInvocation(:var target?, :var function)) {
395+
// Getting the import library for elements with [name].
396+
producers.addAll(await _importLibraryForElement(name, kinds));
397+
398+
// Set the prefix and (maybe swap) name and get the other import library
399+
// option - with prefix!.
400+
if (target == node) {
401+
prefix = name;
402+
if (function case SimpleIdentifier(name: var realName)) {
403+
name = realName;
356404
}
405+
} else if (target case SimpleIdentifier(:var name)) {
406+
prefix = name;
407+
}
408+
} else if (parent
409+
case PrefixedIdentifier(prefix: var parentPrefix, :var identifier)) {
410+
producers.addAll(await _importLibraryForElement(name, kinds));
411+
412+
// Set the prefix and (maybe swap) name and get the other import library
413+
// option - with prefix!.
414+
if (identifier != node) {
415+
prefix = name;
416+
name = identifier.name;
417+
} else {
418+
prefix = parentPrefix.name;
357419
}
358-
359-
return await _importLibraryForElement(name, const [
360-
ElementKind.FUNCTION,
361-
ElementKind.TOP_LEVEL_VARIABLE,
362-
]);
363420
}
364421

365-
return const [];
422+
producers
423+
.addAll(await _importLibraryForElement(name, kinds, prefix: prefix));
424+
return producers;
366425
}
367426

368427
Future<List<ResolvedCorrectionProducer>>
369428
_producersForTopLevelVariable() async {
429+
String? prefix;
370430
var targetNode = node;
431+
if (targetNode.parent case PrefixedIdentifier prefixed
432+
when prefixed.prefix == node) {
433+
targetNode = prefixed.identifier;
434+
prefix = prefixed.prefix.name;
435+
}
371436
if (targetNode case Annotation(:var name)) {
372437
if (name.staticElement == null) {
373438
if (targetNode.arguments != null) {
@@ -377,15 +442,28 @@ class ImportLibrary extends MultiCorrectionProducer {
377442
}
378443
}
379444
if (targetNode case SimpleIdentifier(:var name)) {
380-
return await _importLibraryForElement(name, const [
381-
ElementKind.TOP_LEVEL_VARIABLE,
382-
]);
445+
return await _importLibraryForElement(
446+
name,
447+
const [ElementKind.TOP_LEVEL_VARIABLE],
448+
prefix: prefix,
449+
);
383450
}
384451

385452
return const [];
386453
}
387454

388455
Future<List<ResolvedCorrectionProducer>> _producersForType() async {
456+
const kinds = [
457+
ElementKind.CLASS,
458+
ElementKind.ENUM,
459+
ElementKind.EXTENSION_TYPE,
460+
ElementKind.FUNCTION_TYPE_ALIAS,
461+
ElementKind.MIXIN,
462+
ElementKind.TYPE_ALIAS,
463+
];
464+
if (node case SimpleIdentifier(:var name, :var parent)) {
465+
return await _producersForMethodInvocation(name, parent, kinds);
466+
}
389467
var targetNode = node;
390468
if (targetNode case Annotation(:var name)) {
391469
if (name.staticElement == null) {
@@ -395,22 +473,27 @@ class ImportLibrary extends MultiCorrectionProducer {
395473
targetNode = name;
396474
}
397475
}
476+
String? prefix;
477+
if (node case NamedType(:var importPrefix, :var parent)
478+
// Makes sure that
479+
// [ImportLibraryProject1Test.test_withClass_instanceCreation_const_namedConstructor]
480+
// and
481+
// [ImportLibraryProject1Test.test_withClass_instanceCreation_new_namedConstructor]
482+
// are not broken.
483+
when parent is! ConstructorName) {
484+
prefix = importPrefix?.name.lexeme;
485+
}
398486
var typeName = targetNode.nameOfType;
399487
if (typeName != null) {
400-
return await _importLibraryForElement(typeName, const [
401-
ElementKind.CLASS,
402-
ElementKind.ENUM,
403-
ElementKind.EXTENSION_TYPE,
404-
ElementKind.FUNCTION_TYPE_ALIAS,
405-
ElementKind.MIXIN,
406-
ElementKind.TYPE_ALIAS,
407-
]);
488+
return await _importLibraryForElement(typeName, kinds, prefix: prefix);
408489
}
409490
if (targetNode.mightBeImplicitConstructor) {
410491
var typeName = (targetNode as SimpleIdentifier).name;
411-
return await _importLibraryForElement(typeName, const [
412-
ElementKind.CLASS,
413-
]);
492+
return await _importLibraryForElement(
493+
typeName,
494+
const [ElementKind.CLASS],
495+
prefix: prefix,
496+
);
414497
}
415498

416499
return const [];
@@ -420,12 +503,12 @@ class ImportLibrary extends MultiCorrectionProducer {
420503
/// A correction processor that can add an import using an absolute URI.
421504
class _ImportAbsoluteLibrary extends ResolvedCorrectionProducer {
422505
final FixKind _fixKind;
423-
506+
final String? _prefix;
424507
final Uri _library;
425508

426509
String _uriText = '';
427510

428-
_ImportAbsoluteLibrary(this._fixKind, this._library,
511+
_ImportAbsoluteLibrary(this._fixKind, this._library, this._prefix,
429512
{required super.context});
430513

431514
@override
@@ -434,7 +517,8 @@ class _ImportAbsoluteLibrary extends ResolvedCorrectionProducer {
434517
CorrectionApplicability.singleLocation;
435518

436519
@override
437-
List<String> get fixArguments => [_uriText];
520+
List<String> get fixArguments =>
521+
[_uriText, if (_prefix != null && _prefix.isNotEmpty) _prefix];
438522

439523
@override
440524
FixKind get fixKind => _fixKind;
@@ -443,7 +527,7 @@ class _ImportAbsoluteLibrary extends ResolvedCorrectionProducer {
443527
Future<void> compute(ChangeBuilder builder) async {
444528
await builder.addDartFileEdit(file, (builder) {
445529
if (builder is DartFileEditBuilderImpl) {
446-
_uriText = builder.importLibraryWithAbsoluteUri(_library);
530+
_uriText = builder.importLibraryWithAbsoluteUri(_library, _prefix);
447531
}
448532
});
449533
}
@@ -614,14 +698,15 @@ class _ImportLibraryPrefix extends ResolvedCorrectionProducer {
614698
/// A correction processor that can add an import using a relative URI.
615699
class _ImportRelativeLibrary extends ResolvedCorrectionProducer {
616700
final FixKind _fixKind;
617-
701+
final String? _prefix;
618702
final Uri _library;
619703

620704
String _uriText = '';
621705

622706
_ImportRelativeLibrary(
623707
this._fixKind,
624-
this._library, {
708+
this._library,
709+
this._prefix, {
625710
required super.context,
626711
});
627712

@@ -631,7 +716,8 @@ class _ImportRelativeLibrary extends ResolvedCorrectionProducer {
631716
CorrectionApplicability.singleLocation;
632717

633718
@override
634-
List<String> get fixArguments => [_uriText];
719+
List<String> get fixArguments =>
720+
[_uriText, if (_prefix != null && _prefix.isNotEmpty) _prefix];
635721

636722
@override
637723
FixKind get fixKind => _fixKind;
@@ -640,7 +726,7 @@ class _ImportRelativeLibrary extends ResolvedCorrectionProducer {
640726
Future<void> compute(ChangeBuilder builder) async {
641727
await builder.addDartFileEdit(file, (builder) {
642728
if (builder is DartFileEditBuilderImpl) {
643-
_uriText = builder.importLibraryWithRelativeUri(_library);
729+
_uriText = builder.importLibraryWithRelativeUri(_library, _prefix);
644730
}
645731
});
646732
}

pkg/analysis_server/lib/src/services/correction/fix.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,21 +839,41 @@ abstract final class DartFixKind {
839839
DartFixKindPriority.standard + 3,
840840
"Import library '{0}'",
841841
);
842+
static const IMPORT_LIBRARY_PROJECT1_PREFIXED = FixKind(
843+
'dart.fix.import.libraryProject1Prefixed',
844+
DartFixKindPriority.standard + 3,
845+
"Import library '{0}' with prefix '{1}'",
846+
);
842847
static const IMPORT_LIBRARY_PROJECT2 = FixKind(
843848
'dart.fix.import.libraryProject2',
844849
DartFixKindPriority.standard + 2,
845850
"Import library '{0}'",
846851
);
852+
static const IMPORT_LIBRARY_PROJECT2_PREFIXED = FixKind(
853+
'dart.fix.import.libraryProject2Prefixed',
854+
DartFixKindPriority.standard + 2,
855+
"Import library '{0}' with prefix '{1}'",
856+
);
847857
static const IMPORT_LIBRARY_PROJECT3 = FixKind(
848858
'dart.fix.import.libraryProject3',
849859
DartFixKindPriority.standard + 1,
850860
"Import library '{0}'",
851861
);
862+
static const IMPORT_LIBRARY_PROJECT3_PREFIXED = FixKind(
863+
'dart.fix.import.libraryProject3Prefixed',
864+
DartFixKindPriority.standard + 1,
865+
"Import library '{0}' with prefix '{1}'",
866+
);
852867
static const IMPORT_LIBRARY_SDK = FixKind(
853868
'dart.fix.import.librarySdk',
854869
DartFixKindPriority.standard + 4,
855870
"Import library '{0}'",
856871
);
872+
static const IMPORT_LIBRARY_SDK_PREFIXED = FixKind(
873+
'dart.fix.import.librarySdk',
874+
DartFixKindPriority.standard + 4,
875+
"Import library '{0}' with prefix '{1}'",
876+
);
857877
static const INLINE_INVOCATION = FixKind(
858878
'dart.fix.inlineInvocation',
859879
DartFixKindPriority.standard - 20,

0 commit comments

Comments
 (0)