mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 20:39:38 +00:00
Completion. Migrate LibraryMemberContributor.
We migrate all pre-existing contributors into the new schema, `InScopeCompletionPass`. Change-Id: Ifa2834d79525f9efefff783900e83fd4d5843b35 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358684 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Keerti Parthasarathy <keertip@google.com>
This commit is contained in:
parent
f0c4243e6c
commit
15d310a851
|
@ -348,6 +348,19 @@ final class LabelSuggestion extends CandidateSuggestion {
|
|||
String get completion => label.label.name;
|
||||
}
|
||||
|
||||
/// The suggestion for `loadLibrary()`.
|
||||
final class LoadLibraryFunctionSuggestion extends ExecutableSuggestion {
|
||||
final FunctionElement element;
|
||||
|
||||
LoadLibraryFunctionSuggestion({
|
||||
required super.kind,
|
||||
required this.element,
|
||||
});
|
||||
|
||||
@override
|
||||
String get completion => element.name;
|
||||
}
|
||||
|
||||
/// The information about a candidate suggestion based on a local function.
|
||||
final class LocalFunctionSuggestion extends ExecutableSuggestion {
|
||||
/// The element on which the suggestion is based.
|
||||
|
@ -728,6 +741,10 @@ extension SuggestionBuilderExtension on SuggestionBuilder {
|
|||
offset: suggestion.selectionOffset);
|
||||
case LabelSuggestion():
|
||||
suggestLabel(suggestion.label);
|
||||
case LoadLibraryFunctionSuggestion():
|
||||
suggestLoadLibraryFunction(
|
||||
suggestion.element,
|
||||
);
|
||||
case LocalFunctionSuggestion():
|
||||
suggestTopLevelFunction(suggestion.element);
|
||||
case LocalVariableSuggestion():
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:analysis_server/src/services/completion/dart/candidate_suggestio
|
|||
import 'package:analysis_server/src/services/completion/dart/completion_state.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/in_scope_completion_pass.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/not_imported_contributor.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/suggestion_collector.dart';
|
||||
|
@ -119,9 +118,7 @@ class DartCompletionManager {
|
|||
// Compute the list of contributors that will be run.
|
||||
var builder =
|
||||
SuggestionBuilder(request, useFilter: useFilter, listener: listener);
|
||||
var contributors = <DartCompletionContributor>[
|
||||
LibraryMemberContributor(request, builder),
|
||||
];
|
||||
var contributors = <DartCompletionContributor>[];
|
||||
|
||||
if (includedElementKinds != null) {
|
||||
_addIncludedElementKinds(request);
|
||||
|
|
|
@ -69,6 +69,10 @@ class DeclarationHelper {
|
|||
/// Whether suggestions should be limited to only include types.
|
||||
final bool mustBeType;
|
||||
|
||||
/// Whether suggestions should exclude type names, e.g. include only
|
||||
/// constructor invocations.
|
||||
final bool excludeTypeNames;
|
||||
|
||||
/// Whether suggestions should be tear-offs rather than invocations where
|
||||
/// possible.
|
||||
final bool preferNonInvocation;
|
||||
|
@ -111,6 +115,7 @@ class DeclarationHelper {
|
|||
required this.mustBeNonVoid,
|
||||
required this.mustBeStatic,
|
||||
required this.mustBeType,
|
||||
required this.excludeTypeNames,
|
||||
required this.preferNonInvocation,
|
||||
required this.suggestUnnamedAsNew,
|
||||
required this.skipImports,
|
||||
|
@ -180,6 +185,17 @@ class DeclarationHelper {
|
|||
namespace: importElement.namespace,
|
||||
prefix: null,
|
||||
);
|
||||
|
||||
if (importElement.prefix case var importPrefix?) {
|
||||
if (importPrefix is DeferredImportElementPrefix) {
|
||||
collector.addSuggestion(
|
||||
LoadLibraryFunctionSuggestion(
|
||||
kind: CompletionSuggestionKind.INVOCATION,
|
||||
element: importedLibrary.loadLibraryFunction,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1195,7 +1211,7 @@ class DeclarationHelper {
|
|||
(mustBeMixable && !element.isMixableIn(request.libraryElement))) {
|
||||
return;
|
||||
}
|
||||
if (!mustBeConstant) {
|
||||
if (!mustBeConstant && !excludeTypeNames) {
|
||||
var suggestion =
|
||||
ClassSuggestion(importData: importData, element: element);
|
||||
collector.addSuggestion(suggestion);
|
||||
|
|
|
@ -159,6 +159,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
bool mustBeNonVoid = false,
|
||||
bool mustBeStatic = false,
|
||||
bool mustBeType = false,
|
||||
bool excludeTypeNames = false,
|
||||
bool preferNonInvocation = false,
|
||||
bool suggestUnnamedAsNew = false,
|
||||
Set<AstNode> excludedNodes = const {},
|
||||
|
@ -200,6 +201,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
mustBeNonVoid: mustBeNonVoid,
|
||||
mustBeStatic: mustBeStatic,
|
||||
mustBeType: mustBeType,
|
||||
excludeTypeNames: excludeTypeNames,
|
||||
preferNonInvocation: preferNonInvocation,
|
||||
suggestUnnamedAsNew: suggestUnnamedAsNew,
|
||||
skipImports: skipImports,
|
||||
|
@ -1534,6 +1536,15 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
} else {
|
||||
type = element.type;
|
||||
}
|
||||
} else if (element is PrefixElement) {
|
||||
var isInstanceCreation =
|
||||
node.parent?.parent?.parent is InstanceCreationExpression;
|
||||
declarationHelper(
|
||||
excludeTypeNames: isInstanceCreation,
|
||||
mustBeType: !isInstanceCreation,
|
||||
mustBeNonVoid: isInstanceCreation,
|
||||
).addDeclarationsThroughImportPrefix(element);
|
||||
return;
|
||||
} else if (element is VariableElement) {
|
||||
type = element.type;
|
||||
} else {
|
||||
|
@ -1720,13 +1731,16 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
if (type != null) {
|
||||
_forMemberAccess(node, node.parent, type);
|
||||
}
|
||||
if ((type == null || type.isDartCoreType) &&
|
||||
if ((type == null || type is InvalidType || type.isDartCoreType) &&
|
||||
target is Identifier &&
|
||||
(!node.isCascaded || offset == operator.offset + 1)) {
|
||||
var element = target.staticElement;
|
||||
if (element is InterfaceElement || element is ExtensionTypeElement) {
|
||||
declarationHelper().addStaticMembersOfElement(element!);
|
||||
}
|
||||
if (element is PrefixElement) {
|
||||
declarationHelper().addDeclarationsThroughImportPrefix(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1835,7 +1849,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
}
|
||||
}
|
||||
|
||||
_forTypeAnnotation(node);
|
||||
_forTypeAnnotation(
|
||||
node,
|
||||
excludeTypeNames: node.parent?.parent is InstanceCreationExpression,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1990,11 +2007,17 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
var parent = node.parent;
|
||||
var mustBeAssignable =
|
||||
parent is AssignmentExpression && node == parent.leftHandSide;
|
||||
declarationHelper(
|
||||
mustBeAssignable: mustBeAssignable,
|
||||
preferNonInvocation: element is InterfaceElement &&
|
||||
state.request.shouldSuggestTearOff(element),
|
||||
).addStaticMembersOfElement(element);
|
||||
if (element is PrefixElement) {
|
||||
declarationHelper(
|
||||
mustBeAssignable: mustBeAssignable,
|
||||
).addDeclarationsThroughImportPrefix(element);
|
||||
} else {
|
||||
declarationHelper(
|
||||
mustBeAssignable: mustBeAssignable,
|
||||
preferNonInvocation: element is InterfaceElement &&
|
||||
state.request.shouldSuggestTearOff(element),
|
||||
).addStaticMembersOfElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2032,13 +2055,16 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
_forMemberAccess(node, parent, type,
|
||||
onlySuper: target is SuperExpression);
|
||||
}
|
||||
if ((type == null || type.isDartCoreType) &&
|
||||
if ((type == null || type is InvalidType || type.isDartCoreType) &&
|
||||
target is Identifier &&
|
||||
(!node.isCascaded || offset == operator.offset + 1)) {
|
||||
var element = target.staticElement;
|
||||
if (element is InterfaceElement || element is ExtensionTypeElement) {
|
||||
declarationHelper().addStaticMembersOfElement(element!);
|
||||
}
|
||||
if (element is PrefixElement) {
|
||||
declarationHelper().addDeclarationsThroughImportPrefix(element);
|
||||
}
|
||||
}
|
||||
if (type == null && target is ExtensionOverride) {
|
||||
declarationHelper().addMembersFromExtensionElement(target.element);
|
||||
|
@ -2255,6 +2281,18 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
}
|
||||
var type = node.type;
|
||||
if (type != null) {
|
||||
if (type is NamedType) {
|
||||
if (type.importPrefix case var importPrefix?) {
|
||||
var prefixElement = importPrefix.element;
|
||||
if (prefixElement is PrefixElement) {
|
||||
if (type.name2.coversOffset(offset)) {
|
||||
declarationHelper(
|
||||
mustBeType: true,
|
||||
).addDeclarationsThroughImportPrefix(prefixElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type.beginToken.coversOffset(offset)) {
|
||||
keywordHelper
|
||||
.addFormalParameterKeywords(node.parentFormalParameterList);
|
||||
|
@ -3261,6 +3299,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
bool mustBeImplementable = false,
|
||||
bool mustBeMixable = false,
|
||||
bool mustBeNonVoid = false,
|
||||
bool excludeTypeNames = false,
|
||||
Set<AstNode> excludedNodes = const {},
|
||||
}) {
|
||||
if (!(mustBeExtensible || mustBeImplementable || mustBeMixable)) {
|
||||
|
@ -3269,11 +3308,24 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
keywordHelper.addKeyword(Keyword.VOID);
|
||||
}
|
||||
}
|
||||
if (node is NamedType && node.importPrefix != null) {
|
||||
// TODO(brianwilkerson): Figure out a better way to handle prefixed
|
||||
// identifiers.
|
||||
return;
|
||||
|
||||
if (node is NamedType) {
|
||||
if (node.importPrefix case var importPrefix?) {
|
||||
var prefixElement = importPrefix.element;
|
||||
if (prefixElement is PrefixElement) {
|
||||
declarationHelper(
|
||||
mustBeExtensible: mustBeExtensible,
|
||||
mustBeImplementable: mustBeImplementable,
|
||||
mustBeMixable: mustBeMixable,
|
||||
mustBeNonVoid: mustBeNonVoid,
|
||||
excludedNodes: excludedNodes,
|
||||
excludeTypeNames: excludeTypeNames,
|
||||
).addDeclarationsThroughImportPrefix(prefixElement);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
declarationHelper(
|
||||
mustBeExtensible: mustBeExtensible,
|
||||
mustBeImplementable: mustBeImplementable,
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
// Copyright (c) 2014, 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/provisional/completion/dart/completion_dart.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
|
||||
/// A contributor that produces suggestions based on the members of a library
|
||||
/// when the library was imported using a prefix. More concretely, this class
|
||||
/// produces suggestions for expressions of the form `p.^`, where `p` is a
|
||||
/// prefix.
|
||||
class LibraryMemberContributor extends DartCompletionContributor {
|
||||
LibraryMemberContributor(super.request, super.builder);
|
||||
|
||||
@override
|
||||
Future<void> computeSuggestions({
|
||||
required OperationPerformanceImpl performance,
|
||||
}) async {
|
||||
// Determine if the target looks like a library prefix.
|
||||
var targetId = request.target.dotTarget;
|
||||
if (targetId is SimpleIdentifier && !request.target.isCascade) {
|
||||
var elem = targetId.staticElement;
|
||||
if (elem is PrefixElement && !elem.isSynthetic) {
|
||||
var imports = request.libraryElement.libraryImports;
|
||||
_buildSuggestions(elem, imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _buildSuggestions(
|
||||
PrefixElement elem, List<LibraryImportElement> imports) {
|
||||
var containingNode = request.target.containingNode;
|
||||
var typesOnly =
|
||||
containingNode is NamedType && containingNode.importPrefix != null;
|
||||
var isConstructor = containingNode.parent is ConstructorName;
|
||||
for (var importElem in imports) {
|
||||
if (importElem.prefix?.element.name == elem.name) {
|
||||
var library = importElem.importedLibrary;
|
||||
if (library != null) {
|
||||
builder.libraryUriStr = library.source.uri.toString();
|
||||
for (var element in importElem.namespace.definedNames.values) {
|
||||
if (typesOnly && isConstructor) {
|
||||
// Suggest constructors from the imported libraries.
|
||||
if (element is ClassElement) {
|
||||
for (var constructor in element.constructors) {
|
||||
if (!constructor.isPrivate) {
|
||||
if (!element.isAbstract || constructor.isFactory) {
|
||||
builder.suggestConstructor(constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (element is InterfaceElement ||
|
||||
element is ExtensionElement ||
|
||||
element is TypeAliasElement) {
|
||||
builder.suggestElement(element);
|
||||
} else if (!typesOnly &&
|
||||
(element is FunctionElement ||
|
||||
element is PropertyAccessorElement)) {
|
||||
builder.suggestElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the import is `deferred` then suggest `loadLibrary`.
|
||||
if (!typesOnly && importElem.prefix is DeferredImportElementPrefix) {
|
||||
builder.suggestLoadLibraryFunction(library.loadLibraryFunction);
|
||||
}
|
||||
builder.libraryUriStr = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1811,6 +1811,10 @@ suggestions
|
|||
kind: class
|
||||
isNotImported: null
|
||||
libraryUri: dart:math
|
||||
Random
|
||||
kind: constructorInvocation
|
||||
isNotImported: null
|
||||
libraryUri: dart:math
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
|
@ -10882,6 +10882,8 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
Y
|
||||
kind: class
|
||||
Y
|
||||
kind: constructorInvocation
|
||||
m
|
||||
kind: functionInvocation
|
||||
''');
|
||||
|
@ -10916,6 +10918,8 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
Y
|
||||
kind: class
|
||||
Y
|
||||
kind: constructorInvocation
|
||||
m
|
||||
kind: functionInvocation
|
||||
''');
|
||||
|
@ -10950,11 +10954,14 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
Y
|
||||
kind: class
|
||||
Y
|
||||
kind: constructorInvocation
|
||||
m
|
||||
kind: functionInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
@FailingTest(reason: 'We suggest also the variable')
|
||||
Future<void> test_library009_4() async {
|
||||
allowedIdentifiers = {'Y', 'm', 'X'};
|
||||
newFile('$testPackageLibPath/lib.dart', '''
|
||||
|
|
|
@ -5287,8 +5287,12 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
X0
|
||||
kind: class
|
||||
X0
|
||||
kind: constructorInvocation
|
||||
Y0
|
||||
kind: class
|
||||
Y0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,12 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
X0
|
||||
kind: class
|
||||
X0
|
||||
kind: constructorInvocation
|
||||
Y0
|
||||
kind: class
|
||||
Y0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -120,6 +124,14 @@ foo() {
|
|||
suggestions
|
||||
Future
|
||||
kind: class
|
||||
Future
|
||||
kind: constructorInvocation
|
||||
Future.delayed
|
||||
kind: constructorInvocation
|
||||
Future.microtask
|
||||
kind: constructorInvocation
|
||||
Future.value
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -135,6 +147,14 @@ foo() {
|
|||
suggestions
|
||||
Future
|
||||
kind: class
|
||||
Future
|
||||
kind: constructorInvocation
|
||||
Future.delayed
|
||||
kind: constructorInvocation
|
||||
Future.microtask
|
||||
kind: constructorInvocation
|
||||
Future.value
|
||||
kind: constructorInvocation
|
||||
loadLibrary
|
||||
kind: functionInvocation
|
||||
''');
|
||||
|
@ -157,6 +177,14 @@ f0() {
|
|||
suggestions
|
||||
Future
|
||||
kind: class
|
||||
Future
|
||||
kind: constructorInvocation
|
||||
Future.delayed
|
||||
kind: constructorInvocation
|
||||
Future.microtask
|
||||
kind: constructorInvocation
|
||||
Future.value
|
||||
kind: constructorInvocation
|
||||
loadLibrary
|
||||
kind: functionInvocation
|
||||
''');
|
||||
|
@ -184,11 +212,18 @@ class C0 {}
|
|||
suggestions
|
||||
A0
|
||||
kind: class
|
||||
A0
|
||||
kind: constructorInvocation
|
||||
B0
|
||||
kind: class
|
||||
B0
|
||||
kind: constructorInvocation
|
||||
B1
|
||||
kind: class
|
||||
deprecated: true
|
||||
B1
|
||||
kind: constructorInvocation
|
||||
deprecated: true
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -210,6 +245,8 @@ void f() {
|
|||
suggestions
|
||||
A0
|
||||
kind: class
|
||||
A0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -228,6 +265,8 @@ void f() {
|
|||
suggestions
|
||||
A0
|
||||
kind: class
|
||||
A0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -257,8 +296,12 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
X0
|
||||
kind: class
|
||||
X0
|
||||
kind: constructorInvocation
|
||||
Y0
|
||||
kind: class
|
||||
Y0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -328,6 +371,14 @@ foo() {
|
|||
suggestions
|
||||
Future
|
||||
kind: class
|
||||
Future
|
||||
kind: constructorInvocation
|
||||
Future.delayed
|
||||
kind: constructorInvocation
|
||||
Future.microtask
|
||||
kind: constructorInvocation
|
||||
Future.value
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
|
@ -6542,8 +6542,12 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
X0
|
||||
kind: class
|
||||
X0
|
||||
kind: constructorInvocation
|
||||
Y0
|
||||
kind: class
|
||||
Y0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
|
@ -3180,8 +3180,12 @@ class C {}
|
|||
suggestions
|
||||
A0
|
||||
kind: class
|
||||
A0
|
||||
kind: constructorInvocation
|
||||
B0
|
||||
kind: class
|
||||
B0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
@ -4445,8 +4449,12 @@ suggestions
|
|||
kind: topLevelVariable
|
||||
X0
|
||||
kind: class
|
||||
X0
|
||||
kind: constructorInvocation
|
||||
Y0
|
||||
kind: class
|
||||
Y0
|
||||
kind: constructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue