| Index: pkg/analysis_services/lib/src/generated/completion.dart
|
| diff --git a/pkg/analysis_services/lib/src/generated/completion.dart b/pkg/analysis_services/lib/src/generated/completion.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..175132526ecb72eda86ab499082b796ac2b1fc37
|
| --- /dev/null
|
| +++ b/pkg/analysis_services/lib/src/generated/completion.dart
|
| @@ -0,0 +1,3770 @@
|
| +// 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.
|
| +
|
| +// This code was auto-generated, is not intended to be edited, and is subject to
|
| +// significant change. Please see the README file for more information.
|
| +
|
| +library services.completion;
|
| +
|
| +import 'dart:collection';
|
| +import 'package:analyzer/src/generated/java_core.dart' hide StringUtils;
|
| +import 'package:analyzer/src/generated/java_engine.dart';
|
| +import 'package:analyzer/src/generated/java_io.dart';
|
| +import 'package:analyzer/src/generated/ast.dart';
|
| +import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/error.dart';
|
| +import 'package:analyzer/src/generated/resolver.dart';
|
| +import 'package:analyzer/src/generated/scanner.dart';
|
| +import 'package:analyzer/src/generated/sdk.dart';
|
| +import 'package:analyzer/src/generated/source_io.dart';
|
| +import 'package:analyzer/src/generated/utilities_dart.dart';
|
| +import 'stubs.dart';
|
| +import 'util.dart';
|
| +
|
| +class AstNodeClassifier_CompletionEngine_typeOf extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + List<DartType> result;
|
| +
|
| + AstNodeClassifier_CompletionEngine_typeOf(this.CompletionEngine_this, this.result) : super();
|
| +
|
| + @override
|
| + Object visitPrefixedIdentifier(PrefixedIdentifier node) => visitSimpleIdentifier(node.identifier);
|
| +
|
| + @override
|
| + Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| + Element elem = node.bestElement;
|
| + if (elem != null && elem.kind == ElementKind.GETTER) {
|
| + PropertyAccessorElement accessor = elem as PropertyAccessorElement;
|
| + if (accessor.isSynthetic) {
|
| + PropertyInducingElement var2 = accessor.variable;
|
| + result[0] = CompletionEngine_this._typeSearch(var2);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * The analysis engine for code completion.
|
| + *
|
| + * Note: During development package-private methods are used to group element-specific completion
|
| + * utilities.
|
| + *
|
| + * TODO: Recognize when completion is requested in the middle of a multi-character operator.
|
| + * Re-write the AST as it would be if an identifier were present at the completion point then
|
| + * restart the analysis.
|
| + */
|
| +class CompletionEngine {
|
| + static String _C_DYNAMIC = "dynamic";
|
| +
|
| + static String _C_FALSE = "false";
|
| +
|
| + static String _C_NULL = "null";
|
| +
|
| + static String _C_PARAMNAME = "arg";
|
| +
|
| + static String _C_TRUE = "true";
|
| +
|
| + static String _C_VAR = "var";
|
| +
|
| + static String _C_VOID = "void";
|
| +
|
| + static bool _isPrivate(Element element) {
|
| + String name = element.displayName;
|
| + return Identifier.isPrivateName(name);
|
| + }
|
| +
|
| + static bool _isSyntheticIdentifier(Expression expression) => expression is SimpleIdentifier && expression.isSynthetic;
|
| +
|
| + CompletionRequestor _requestor;
|
| +
|
| + final CompletionFactory _factory;
|
| +
|
| + AssistContext _context;
|
| +
|
| + Filter _filter;
|
| +
|
| + CompletionState _state;
|
| +
|
| + List<LibraryElement> _libraries;
|
| +
|
| + CompletionEngine(CompletionRequestor requestor, this._factory) {
|
| + this._requestor = requestor;
|
| + this._state = new CompletionState();
|
| + }
|
| +
|
| + /**
|
| + * Analyze the source unit in the given context to determine completion proposals at the selection
|
| + * offset of the context.
|
| + *
|
| + * @throws Exception
|
| + */
|
| + void complete(AssistContext context) {
|
| + this._context = context;
|
| + _requestor.beginReporting();
|
| + AstNode completionNode = context.coveredNode;
|
| + if (completionNode != null) {
|
| + _state.context = completionNode;
|
| + CompletionEngine_TerminalNodeCompleter visitor = new CompletionEngine_TerminalNodeCompleter(this);
|
| + completionNode.accept(visitor);
|
| + }
|
| + _requestor.endReporting();
|
| + }
|
| +
|
| + void _analyzeAnnotationName(SimpleIdentifier identifier) {
|
| + _filter = _createFilter(identifier);
|
| + CompletionEngine_NameCollector names = _collectTopLevelElementVisibleAt(identifier);
|
| + for (Element element in names.uniqueElements) {
|
| + if (element is PropertyAccessorElement) {
|
| + element = (element as PropertyAccessorElement).variable;
|
| + }
|
| + if (element is TopLevelVariableElement) {
|
| + TopLevelVariableElement variable = element as TopLevelVariableElement;
|
| + if (_state._isCompileTimeConstantRequired && !variable.isConst) {
|
| + continue;
|
| + }
|
| + _proposeName(element, identifier, names);
|
| + }
|
| + if (element is ClassElement) {
|
| + ClassElement classElement = element as ClassElement;
|
| + for (ConstructorElement constructor in classElement.constructors) {
|
| + _pNamedConstructor(classElement, constructor, identifier);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzeConstructorTypeName(SimpleIdentifier identifier) {
|
| + _filter = _createFilter(identifier);
|
| + List<Element> types = _findAllTypes(currentLibrary, TopLevelNamesKind.DECLARED_AND_IMPORTS);
|
| + for (Element type in types) {
|
| + if (type is ClassElement) {
|
| + _namedConstructorReference(type, identifier);
|
| + }
|
| + }
|
| + List<Element> prefixes = _findAllPrefixes();
|
| + for (Element prefix in prefixes) {
|
| + _pName(prefix, identifier);
|
| + }
|
| + }
|
| +
|
| + void _analyzeDeclarationName(VariableDeclaration varDecl) {
|
| + // We might want to propose multiple names for a declaration based on types someday.
|
| + // For now, just use whatever is already there.
|
| + SimpleIdentifier identifier = varDecl.name;
|
| + _filter = _createFilter(identifier);
|
| + VariableDeclarationList varList = varDecl.parent as VariableDeclarationList;
|
| + TypeName type = varList.type;
|
| + if (identifier.length > 0) {
|
| + _pName3(identifier.name, ProposalKind.VARIABLE);
|
| + }
|
| + if (type == null) {
|
| + if (varList.keyword == null) {
|
| + // Interpret as the type name of a typed variable declaration { DivE!; }
|
| + _analyzeLocalName(identifier);
|
| + }
|
| + } else {
|
| + _pParamName(type.name.name.toLowerCase());
|
| + }
|
| + }
|
| +
|
| + void _analyzeDirectAccess(DartType receiverType, SimpleIdentifier completionNode) {
|
| + if (receiverType != null) {
|
| + // Complete this.!y where this is absent
|
| + Element rcvrTypeElem = receiverType.element;
|
| + if (receiverType.isDynamic) {
|
| + rcvrTypeElem = objectClassElement;
|
| + }
|
| + if (rcvrTypeElem is ClassElement) {
|
| + _directAccess(rcvrTypeElem as ClassElement, completionNode);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzeImmediateField(SimpleIdentifier fieldName) {
|
| + _filter = _createFilter(fieldName);
|
| + ClassDeclaration classDecl = fieldName.getAncestor((node) => node is ClassDeclaration);
|
| + ClassElement classElement = classDecl.element;
|
| + for (FieldElement field in classElement.fields) {
|
| + _pName3(field.displayName, ProposalKind.FIELD);
|
| + }
|
| + }
|
| +
|
| + void _analyzeLiteralReference(BooleanLiteral literal) {
|
| + // state.setContext(literal);
|
| + Ident ident = _createIdent(literal.parent);
|
| + ident.token = literal.literal;
|
| + _filter = _createFilter(ident);
|
| + _analyzeLocalName(ident);
|
| + }
|
| +
|
| + void _analyzeLocalName(SimpleIdentifier identifier) {
|
| + // Completion x!
|
| + _filter = _createFilter(identifier);
|
| + // TODO Filter out types that have no static members.
|
| + CompletionEngine_NameCollector names = _collectIdentifiersVisibleAt(identifier);
|
| + for (Element element in names.uniqueElements) {
|
| + if (_state._isSourceDeclarationStatic) {
|
| + if (element is FieldElement) {
|
| + if (!element.isStatic) {
|
| + continue;
|
| + }
|
| + } else if (element is PropertyAccessorElement) {
|
| + if (!element.isStatic) {
|
| + continue;
|
| + }
|
| + }
|
| + }
|
| + if (_state._isOptionalArgumentRequired) {
|
| + if (element is! ParameterElement) {
|
| + continue;
|
| + }
|
| + ParameterElement param = element as ParameterElement;
|
| + if (!param.parameterKind.isOptional) {
|
| + continue;
|
| + }
|
| + }
|
| + _proposeName(element, identifier, names);
|
| + }
|
| + if (_state._areLiteralsAllowed) {
|
| + _pNull();
|
| + _pTrue();
|
| + _pFalse();
|
| + }
|
| + }
|
| +
|
| + void _analyzeNamedParameter(ArgumentList args, SimpleIdentifier identifier) {
|
| + // Completion x!
|
| + _filter = _createFilter(identifier);
|
| + // prepare parameters
|
| + List<ParameterElement> parameters = _getParameterElements(args);
|
| + if (parameters == null) {
|
| + return;
|
| + }
|
| + // remember already used names
|
| + Set<String> usedNames = new Set();
|
| + for (Expression arg in args.arguments) {
|
| + if (arg is NamedExpression) {
|
| + NamedExpression namedExpr = arg;
|
| + String name = namedExpr.name.label.name;
|
| + usedNames.add(name);
|
| + }
|
| + }
|
| + // propose named parameters
|
| + for (ParameterElement parameterElement in parameters) {
|
| + // should be named
|
| + if (parameterElement.parameterKind != ParameterKind.NAMED) {
|
| + continue;
|
| + }
|
| + // filter by name
|
| + if (_filterDisallows(parameterElement)) {
|
| + continue;
|
| + }
|
| + // may be already used
|
| + String parameterName = parameterElement.name;
|
| + if (usedNames.contains(parameterName)) {
|
| + continue;
|
| + }
|
| + // OK, add proposal
|
| + CompletionProposal prop = _createProposal4(ProposalKind.NAMED_ARGUMENT);
|
| + prop.setCompletion(parameterName);
|
| + prop.setParameterName(parameterName);
|
| + prop.setParameterType(parameterElement.type.displayName);
|
| + prop.setLocation(identifier.offset);
|
| + prop.setReplacementLength(identifier.length);
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_HIGH);
|
| + _requestor.accept(prop);
|
| + }
|
| + }
|
| +
|
| + void _analyzeNewParameterName(List<FormalParameter> params, SimpleIdentifier typeIdent, String identifierName) {
|
| + String typeName = typeIdent.name;
|
| + _filter = _createFilter(_createIdent(typeIdent));
|
| + List<String> names = new List<String>();
|
| + for (FormalParameter node in params) {
|
| + names.add(node.identifier.name);
|
| + }
|
| + // Find name similar to typeName not in names, ditto for identifierName.
|
| + if (identifierName == null || identifierName.isEmpty) {
|
| + String candidate = typeName == null || typeName.isEmpty ? _C_PARAMNAME : typeName.toLowerCase();
|
| + _pParamName(_makeNonconflictingName(candidate, names));
|
| + } else {
|
| + _pParamName(_makeNonconflictingName(identifierName, names));
|
| + if (typeName != null && !typeName.isEmpty) {
|
| + _pParamName(_makeNonconflictingName(typeName.toLowerCase(), names));
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzePositionalArgument(ArgumentList args, SimpleIdentifier identifier) {
|
| + // Show parameter name only if there is nothing to complete, so that if there is only
|
| + // one match, we won't to force user to choose.
|
| + if (!StringUtils.isEmpty(identifier.name)) {
|
| + return;
|
| + }
|
| + // prepare parameters
|
| + List<ParameterElement> parameters = _getParameterElements(args);
|
| + if (parameters == null) {
|
| + return;
|
| + }
|
| + // show current parameter
|
| + int argIndex = args.arguments.indexOf(identifier);
|
| + if (argIndex == -1) {
|
| + argIndex = 0;
|
| + }
|
| + if (argIndex >= 0 && argIndex < parameters.length) {
|
| + ParameterElement parameter = parameters[argIndex];
|
| + if (parameter.parameterKind != ParameterKind.NAMED) {
|
| + String parameterName = parameter.displayName;
|
| + CompletionProposal prop = _createProposal4(ProposalKind.OPTIONAL_ARGUMENT);
|
| + prop.setCompletion(parameterName);
|
| + prop.setParameterName(parameterName);
|
| + prop.setParameterType(parameter.type.displayName);
|
| + prop.setLocation(identifier.offset);
|
| + prop.setReplacementLength(identifier.length);
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_HIGH);
|
| + _requestor.accept(prop);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzePrefixedAccess(Expression receiver, SimpleIdentifier completionNode) {
|
| + if (receiver is ThisExpression && !_state._isThisAllowed) {
|
| + return;
|
| + }
|
| + DartType receiverType = _typeOf2(receiver);
|
| + bool forSuper = receiver is SuperExpression;
|
| + _analyzePrefixedAccess2(receiverType, forSuper, completionNode);
|
| + }
|
| +
|
| + void _analyzePrefixedAccess2(DartType receiverType, bool forSuper, SimpleIdentifier completionNode) {
|
| + if (receiverType != null) {
|
| + // Complete x.!y
|
| + Element rcvrTypeElem = receiverType.element;
|
| + if (receiverType.isBottom) {
|
| + receiverType = objectType;
|
| + }
|
| + if (receiverType.isDynamic) {
|
| + receiverType = objectType;
|
| + }
|
| + if (receiverType is InterfaceType) {
|
| + _prefixedAccess(receiverType, forSuper, completionNode);
|
| + } else if (rcvrTypeElem is TypeParameterElement) {
|
| + TypeParameterElement typeParamElem = rcvrTypeElem;
|
| + _analyzePrefixedAccess2(typeParamElem.bound, false, completionNode);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzeReceiver(SimpleIdentifier identifier) {
|
| + // Completion x!.y
|
| + _filter = _createFilter(identifier);
|
| + CompletionEngine_NameCollector names = _collectIdentifiersVisibleAt(identifier);
|
| + for (Element element in names.uniqueElements) {
|
| + _proposeName(element, identifier, names);
|
| + }
|
| + }
|
| +
|
| + void _analyzeSuperConstructorInvocation(SuperConstructorInvocation node) {
|
| + ClassDeclaration enclosingClassNode = node.getAncestor((node) => node is ClassDeclaration);
|
| + if (enclosingClassNode != null) {
|
| + ClassElement enclosingClassElement = enclosingClassNode.element;
|
| + if (enclosingClassElement != null) {
|
| + ClassElement superClassElement = enclosingClassElement.supertype.element;
|
| + _constructorReference(superClassElement, node.constructorName);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _analyzeTypeName(SimpleIdentifier identifier, SimpleIdentifier nameIdent) {
|
| + _filter = _createFilter(identifier);
|
| + String name = nameIdent == null ? "" : nameIdent.name;
|
| + List<Element> types = _findAllTypes(currentLibrary, TopLevelNamesKind.DECLARED_AND_IMPORTS);
|
| + for (Element type in types) {
|
| + if (_state._isForMixin) {
|
| + if (type is! ClassElement) {
|
| + continue;
|
| + }
|
| + ClassElement classElement = type as ClassElement;
|
| + if (!classElement.isValidMixin) {
|
| + continue;
|
| + }
|
| + }
|
| + if (type.displayName == name) {
|
| + continue;
|
| + }
|
| + _pName(type, nameIdent);
|
| + }
|
| + if (!_state._isForMixin) {
|
| + ClassDeclaration classDecl = identifier.getAncestor((node) => node is ClassDeclaration);
|
| + if (classDecl != null) {
|
| + ClassElement classElement = classDecl.element;
|
| + for (TypeParameterElement param in classElement.typeParameters) {
|
| + _pName(param, nameIdent);
|
| + }
|
| + }
|
| + }
|
| + List<Element> prefixes = _findAllPrefixes();
|
| + for (Element prefix in prefixes) {
|
| + _pName(prefix, nameIdent);
|
| + }
|
| + if (_state._isDynamicAllowed) {
|
| + _pDynamic();
|
| + }
|
| + if (_state._isVarAllowed) {
|
| + _pVar();
|
| + }
|
| + if (_state._isVoidAllowed) {
|
| + _pVoid();
|
| + }
|
| + }
|
| +
|
| + void _constructorReference(ClassElement classElement, SimpleIdentifier identifier) {
|
| + // Complete identifier when it refers to a constructor defined in classElement.
|
| + _filter = _createFilter(identifier);
|
| + for (ConstructorElement cons in classElement.constructors) {
|
| + if (_state._isCompileTimeConstantRequired == cons.isConst && _filterAllows(cons)) {
|
| + _pExecutable2(cons, identifier, false);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _directAccess(ClassElement classElement, SimpleIdentifier identifier) {
|
| + _filter = _createFilter(identifier);
|
| + CompletionEngine_NameCollector names = _createNameCollector();
|
| + names.addLocalNames(identifier);
|
| + names._addNamesDefinedByHierarchy(classElement, false);
|
| + names._addTopLevelNames2(currentLibrary, TopLevelNamesKind.DECLARED_AND_IMPORTS);
|
| + _proposeNames(names, identifier);
|
| + }
|
| +
|
| + void _dispatchPrefixAnalysis(InstanceCreationExpression node) {
|
| + // prepare ClassElement
|
| + ClassElement classElement;
|
| + {
|
| + Element typeElement = _typeOf2(node).element;
|
| + if (typeElement is! ClassElement) {
|
| + return;
|
| + }
|
| + classElement = typeElement as ClassElement;
|
| + }
|
| + // prepare constructor name
|
| + Identifier typeName = node.constructorName.type.name;
|
| + SimpleIdentifier identifier = null;
|
| + if (typeName is SimpleIdentifier) {
|
| + identifier = typeName;
|
| + } else if (typeName is PrefixedIdentifier) {
|
| + identifier = typeName.identifier;
|
| + }
|
| + if (identifier == null) {
|
| + identifier = _createIdent(node);
|
| + }
|
| + // analyze constructor name
|
| + _analyzeConstructorTypeName(identifier);
|
| + _constructorReference(classElement, identifier);
|
| + }
|
| +
|
| + void _dispatchPrefixAnalysis2(MethodInvocation node) {
|
| + // This might be a library prefix on a top-level function
|
| + Expression expr = node.realTarget;
|
| + if (expr is SimpleIdentifier) {
|
| + SimpleIdentifier ident = expr;
|
| + if (ident.bestElement is PrefixElement) {
|
| + _prefixedAccess2(ident, node.methodName);
|
| + return;
|
| + } else if (ident.bestElement is ClassElement) {
|
| + _state._areInstanceReferencesProhibited = true;
|
| + _state._areStaticReferencesProhibited = false;
|
| + } else {
|
| + _state._areInstanceReferencesProhibited = false;
|
| + _state._areStaticReferencesProhibited = true;
|
| + }
|
| + }
|
| + if (expr == null) {
|
| + _analyzeLocalName(_createIdent(node));
|
| + } else {
|
| + _analyzePrefixedAccess(expr, node.methodName);
|
| + }
|
| + }
|
| +
|
| + void _dispatchPrefixAnalysis3(PrefixedIdentifier node, SimpleIdentifier identifier) {
|
| + SimpleIdentifier receiverName = node.prefix;
|
| + Element receiver = receiverName.bestElement;
|
| + if (receiver == null) {
|
| + _prefixedAccess2(receiverName, identifier);
|
| + return;
|
| + }
|
| + while (true) {
|
| + if (receiver.kind == ElementKind.PREFIX || receiver.kind == ElementKind.IMPORT) {
|
| + // Complete lib_prefix.name
|
| + _prefixedAccess2(receiverName, identifier);
|
| + } else {
|
| + {
|
| + DartType receiverType;
|
| + DartType propType = _typeOf2(receiverName);
|
| + if (propType == null || propType.isDynamic) {
|
| + receiverType = _typeOf(receiver);
|
| + } else {
|
| + DartType declType = _typeOf(receiver);
|
| + if (propType.isMoreSpecificThan(declType)) {
|
| + receiverType = propType;
|
| + } else {
|
| + receiverType = declType;
|
| + }
|
| + }
|
| + _analyzePrefixedAccess2(receiverType, false, identifier);
|
| + break;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void _fieldReference(ClassElement classElement, SimpleIdentifier identifier) {
|
| + // Complete identifier when it refers to a constructor defined in classElement.
|
| + _filter = _createFilter(identifier);
|
| + for (FieldElement cons in classElement.fields) {
|
| + if (_filterAllows(cons)) {
|
| + _pField(cons, identifier, classElement);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _namedConstructorReference(ClassElement classElement, SimpleIdentifier identifier) {
|
| + // Complete identifier when it refers to a named constructor defined in classElement.
|
| + if (_filter == null) {
|
| + _filter = _createFilter(identifier);
|
| + }
|
| + for (ConstructorElement cons in classElement.constructors) {
|
| + if (!_isVisible(cons)) {
|
| + continue;
|
| + }
|
| + if (_state._isCompileTimeConstantRequired && !cons.isConst) {
|
| + continue;
|
| + }
|
| + _pNamedConstructor(classElement, cons, identifier);
|
| + }
|
| + }
|
| +
|
| + void _namespacePubReference(NamespaceDirective node, Set<String> packageUris) {
|
| + // no import URI or package:
|
| + String prefix = _filter._prefix;
|
| + List<String> prefixStrings = prefix.split(":");
|
| + if (!prefix.isEmpty && !"package:".startsWith(prefixStrings[0])) {
|
| + return;
|
| + }
|
| + // if no URI yet, propose package:
|
| + if (prefix.isEmpty) {
|
| + _pImportUriWithScheme(node, "package:");
|
| + return;
|
| + }
|
| + // check "packages" folder for package libraries that are not added to AnalysisContext
|
| + {
|
| + Source contextSource = _context.source;
|
| + if (contextSource is FileBasedSource) {
|
| + FileBasedSource contextFileSource = contextSource;
|
| + String contextFilePath = contextFileSource.fullName;
|
| + JavaFile contextFile = new JavaFile(contextFilePath);
|
| + JavaFile contextFolder = contextFile.getParentFile();
|
| + JavaFile contextPackages = new JavaFile.relative(contextFolder, "packages");
|
| + if (contextPackages.isDirectory()) {
|
| + for (JavaFile packageFolder in contextPackages.listFiles()) {
|
| + String packageName = packageFolder.getName();
|
| + String packageLibName = "${packageName}.dart";
|
| + JavaFile packageFile = new JavaFile.relative(packageFolder, packageLibName);
|
| + if (packageFile.exists() && packageFile.isFile()) {
|
| + packageUris.add("package:${packageName}/${packageLibName}");
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + // add known package: URIs
|
| + for (String uri in packageUris) {
|
| + if (_filterDisallows2(uri)) {
|
| + continue;
|
| + }
|
| + CompletionProposal prop = _createProposal4(ProposalKind.IMPORT);
|
| + prop.setCompletion(uri);
|
| + // put "lib" before "lib/src"
|
| + if (!uri.contains("/src/")) {
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_HIGH);
|
| + }
|
| + // done
|
| + _requestor.accept(prop);
|
| + }
|
| + }
|
| +
|
| + void _namespaceReference(NamespaceDirective node, SimpleStringLiteral literal) {
|
| + String lit = literal.literal.lexeme;
|
| + if (!lit.isEmpty) {
|
| + lit = lit.substring(1, Math.max(lit.length - 1, 0));
|
| + }
|
| + _filter = _createFilter(new Ident.con2(node, lit, literal.offset + 1));
|
| + Set<String> packageUris = new Set();
|
| + List<LibraryElement> libraries = new List<LibraryElement>();
|
| + List<LibraryElement> librariesInLib = new List<LibraryElement>();
|
| + String currentLibraryName = currentLibrary.source.fullName;
|
| + AnalysisContext ac = analysisContext;
|
| + List<Source> sources = ac.librarySources;
|
| + for (Source s in sources) {
|
| + String sName = s.fullName;
|
| + // skip current library
|
| + if (currentLibraryName == sName) {
|
| + continue;
|
| + }
|
| + // ".pub-cache/..../unittest-0.8.8/lib/unittest.dart" -> "package:unittest/unittest.dart"
|
| + {
|
| + Uri uri = ac.sourceFactory.restoreUri(s);
|
| + if (uri != null) {
|
| + String uriString = uri.toString();
|
| + if (uriString.startsWith("package:")) {
|
| + packageUris.add(uriString);
|
| + }
|
| + }
|
| + }
|
| + LibraryElement lib = ac.getLibraryElement(s);
|
| + if (lib == null) {
|
| + continue;
|
| + } else if (_isUnitInLibFolder(lib.definingCompilationUnit)) {
|
| + librariesInLib.add(lib);
|
| + } else {
|
| + libraries.add(lib);
|
| + }
|
| + }
|
| + _namespaceSdkReference(node);
|
| + _namespacePubReference(node, packageUris);
|
| + }
|
| +
|
| + void _namespaceSdkReference(NamespaceDirective node) {
|
| + String prefix = _filter._prefix;
|
| + List<String> prefixStrings = prefix.split(":");
|
| + if (!prefix.isEmpty && !"dart:".startsWith(prefixStrings[0])) {
|
| + return;
|
| + }
|
| + if (prefix.isEmpty) {
|
| + _pImportUriWithScheme(node, "dart:");
|
| + return;
|
| + }
|
| + // add DartSdk libraries
|
| + DartSdk dartSdk = analysisContext.sourceFactory.dartSdk;
|
| + for (SdkLibrary library in dartSdk.sdkLibraries) {
|
| + String name = library.shortName;
|
| + // ignore internal
|
| + if (library.isInternal) {
|
| + continue;
|
| + }
|
| + // ignore implementation
|
| + if (library.isImplementation) {
|
| + continue;
|
| + }
|
| + // standard libraries name name starting with "dart:"
|
| + name = StringUtils.removeStart(name, "dart:");
|
| + // ignore private libraries
|
| + if (Identifier.isPrivateName(name)) {
|
| + continue;
|
| + }
|
| + // add with "dart:" prefix
|
| + _pName3("dart:${name}", ProposalKind.IMPORT);
|
| + }
|
| + }
|
| +
|
| + void _operatorAccess(Expression expr, SimpleIdentifier identifier) {
|
| + _state._requiresOperators();
|
| + _analyzePrefixedAccess(expr, identifier);
|
| + }
|
| +
|
| + void _prefixedAccess(InterfaceType type, bool forSuper, SimpleIdentifier identifier) {
|
| + // Complete identifier when it refers to field or method in classElement.
|
| + _filter = _createFilter(identifier);
|
| + CompletionEngine_NameCollector names = _createNameCollector();
|
| + if (_state._areInstanceReferencesProhibited) {
|
| + names._addNamesDefinedByType2(type);
|
| + } else {
|
| + names._addNamesDefinedByHierarchy2(type, forSuper);
|
| + }
|
| + _proposeNames(names, identifier);
|
| + }
|
| +
|
| + void _prefixedAccess2(SimpleIdentifier prefixName, SimpleIdentifier identifier) {
|
| + if (_filter == null) {
|
| + _filter = _createFilter(identifier);
|
| + }
|
| + CompletionEngine_NameCollector names = _createNameCollector();
|
| + List<ImportElement> prefixImports = _importsWithName(prefixName);
|
| + // Library prefixes do not have a unique AST representation so we need to fudge state vars.
|
| + bool litsAllowed = _state._areLiteralsAllowed;
|
| + _state._areLiteralsAllowed = false;
|
| + names._addTopLevelNames(prefixImports, TopLevelNamesKind.DECLARED_AND_EXPORTS);
|
| + _state._areLiteralsAllowed = litsAllowed;
|
| + _proposeNames(names, identifier);
|
| + }
|
| +
|
| + List<InterfaceType> _allSubtypes(ClassElement classElement) {
|
| + // TODO(scheglov) translate it
|
| + return [];
|
| + }
|
| +
|
| + CompletionEngine_NameCollector _collectIdentifiersVisibleAt(AstNode ident) {
|
| + CompletionEngine_NameCollector names = _createNameCollector();
|
| + ScopedNameFinder finder = new ScopedNameFinder(_completionLocation());
|
| + ident.accept(finder);
|
| + names.addAll(finder.locals.values);
|
| + Declaration decl = finder.declaration;
|
| + if (decl != null && decl.parent is ClassDeclaration) {
|
| + ClassElement classElement = (decl.parent as ClassDeclaration).element;
|
| + names._addNamesDefinedByHierarchy(classElement, false);
|
| + }
|
| + names._addTopLevelNames2(currentLibrary, TopLevelNamesKind.DECLARED_AND_IMPORTS);
|
| + return names;
|
| + }
|
| +
|
| + CompletionEngine_NameCollector _collectTopLevelElementVisibleAt(AstNode ident) {
|
| + CompletionEngine_NameCollector names = _createNameCollector();
|
| + names._addTopLevelNames2(currentLibrary, TopLevelNamesKind.DECLARED_AND_IMPORTS);
|
| + return names;
|
| + }
|
| +
|
| + int _completionLocation() => _context.selectionOffset;
|
| +
|
| + int _completionTokenOffset() => _completionLocation() - _filter._prefix.length;
|
| +
|
| + List<FormalParameter> _copyWithout(NodeList oldList, AstNode deletion) {
|
| + List<FormalParameter> newList = new List<FormalParameter>();
|
| + oldList.accept(new GeneralizingAstVisitor_CompletionEngine_copyWithout(deletion, newList));
|
| + return newList;
|
| + }
|
| +
|
| + Filter _createFilter(SimpleIdentifier ident) => new Filter.con1(ident, _context.selectionOffset);
|
| +
|
| + Ident _createIdent(AstNode node) => new Ident.con1(node, _completionLocation());
|
| +
|
| + CompletionEngine_NameCollector _createNameCollector() => new CompletionEngine_NameCollector(this);
|
| +
|
| + CompletionProposal _createProposal(Element element) {
|
| + String completion = element.displayName;
|
| + return _createProposal3(element, completion);
|
| + }
|
| +
|
| + CompletionProposal _createProposal2(Element element, SimpleIdentifier identifier) {
|
| + // Create a completion proposal for the element: variable, field, class, function.
|
| + if (_filterDisallows(element)) {
|
| + return null;
|
| + }
|
| + CompletionProposal prop = _createProposal(element);
|
| + Element container = element.enclosingElement;
|
| + if (container != null) {
|
| + prop.setDeclaringType(container.displayName);
|
| + }
|
| + DartType type = _typeOf(element);
|
| + if (type != null) {
|
| + prop.setReturnType(type.name);
|
| + }
|
| + if (identifier != null) {
|
| + prop.setReplacementLengthIdentifier(identifier.length);
|
| + }
|
| + return prop;
|
| + }
|
| +
|
| + CompletionProposal _createProposal3(Element element, String completion) {
|
| + ProposalKind kind = _proposalKindOf(element);
|
| + CompletionProposal prop = _createProposal4(kind);
|
| + prop.setElement(element);
|
| + prop.setCompletion(completion);
|
| + prop.setDeprecated(_isDeprecated(element));
|
| + if (_isPrivate(element)) {
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_LOW);
|
| + }
|
| + if (_filter._isSameCasePrefix(element.name)) {
|
| + prop.incRelevance();
|
| + }
|
| + return prop;
|
| + }
|
| +
|
| + CompletionProposal _createProposal4(ProposalKind kind) => _factory.createCompletionProposal(kind, _completionTokenOffset());
|
| +
|
| + List<LibraryElement> _currentLibraryList() {
|
| + Set<LibraryElement> libraries = new Set<LibraryElement>();
|
| + LibraryElement curLib = currentLibrary;
|
| + libraries.add(curLib);
|
| + Queue<LibraryElement> queue = new Queue<LibraryElement>();
|
| + queue.addAll(curLib.importedLibraries);
|
| + _currentLibraryLister(queue, libraries);
|
| + return new List.from(libraries);
|
| + }
|
| +
|
| + void _currentLibraryLister(Queue<LibraryElement> queue, Set<LibraryElement> libraries) {
|
| + while (!queue.isEmpty) {
|
| + LibraryElement sourceLib = queue.removeFirst();
|
| + libraries.add(sourceLib);
|
| + List<LibraryElement> expLibs = sourceLib.exportedLibraries;
|
| + for (LibraryElement lib in expLibs) {
|
| + if (!libraries.contains(lib)) {
|
| + queue.add(lib);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool _filterAllows(Element element) => _filter._match(element);
|
| +
|
| + bool _filterDisallows(Element element) => !_filter._match(element);
|
| +
|
| + bool _filterDisallows2(String name) => !_filter._match2(name);
|
| +
|
| + List<Element> _findAllNotTypes(List<Element> elements) {
|
| + elements = [];
|
| + for (JavaIterator<Element> I = new JavaIterator(elements); I.hasNext;) {
|
| + Element element = I.next();
|
| + ElementKind kind = element.kind;
|
| + if (kind == ElementKind.FUNCTION || kind == ElementKind.TOP_LEVEL_VARIABLE || kind == ElementKind.GETTER || kind == ElementKind.SETTER) {
|
| + continue;
|
| + }
|
| + I.remove();
|
| + }
|
| + return new List.from(elements);
|
| + }
|
| +
|
| + List<Element> _findAllPrefixes() {
|
| + LibraryElement lib = _context.compilationUnitElement.enclosingElement;
|
| + return lib.prefixes;
|
| + }
|
| +
|
| + List<Element> _findAllTypes(LibraryElement library, TopLevelNamesKind topKind) {
|
| + List<Element> elements = _findTopLevelElements(library, topKind);
|
| + return _findAllTypes2(elements);
|
| + }
|
| +
|
| + List<Element> _findAllTypes2(List<Element> elements) {
|
| + elements = [];
|
| + for (JavaIterator<Element> I = new JavaIterator(elements); I.hasNext;) {
|
| + Element element = I.next();
|
| + ElementKind kind = element.kind;
|
| + if (kind == ElementKind.CLASS || kind == ElementKind.FUNCTION_TYPE_ALIAS) {
|
| + continue;
|
| + }
|
| + I.remove();
|
| + }
|
| + return new List.from(elements);
|
| + }
|
| +
|
| + List<Element> _findTopLevelElements(LibraryElement library, TopLevelNamesKind topKind) {
|
| + List<Element> elements = [];
|
| + if (topKind == TopLevelNamesKind.DECLARED_AND_IMPORTS) {
|
| + elements.addAll(CorrectionUtils.getTopLevelElements(library));
|
| + for (ImportElement imp in library.imports) {
|
| + elements.addAll(CorrectionUtils.getImportNamespace(imp).values);
|
| + }
|
| + _removeNotMatchingFilter(elements);
|
| + }
|
| + if (topKind == TopLevelNamesKind.DECLARED_AND_EXPORTS) {
|
| + elements.addAll(CorrectionUtils.getExportNamespace2(library).values);
|
| + _removeNotMatchingFilter(elements);
|
| + }
|
| + return elements;
|
| + }
|
| +
|
| + AnalysisContext get analysisContext => _context.compilationUnitElement.context;
|
| +
|
| + LibraryElement get currentLibrary => _context.compilationUnitElement.enclosingElement;
|
| +
|
| + FunctionType _getFunctionType(Element element) {
|
| + if (element is ExecutableElement) {
|
| + ExecutableElement executableElement = element;
|
| + return executableElement.type;
|
| + }
|
| + if (element is VariableElement) {
|
| + VariableElement variableElement = element;
|
| + DartType type = variableElement.type;
|
| + if (type is FunctionType) {
|
| + return type;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + ClassElement get objectClassElement => typeProvider.objectType.element;
|
| +
|
| + InterfaceType get objectType => typeProvider.objectType;
|
| +
|
| + List<ParameterElement> _getParameterElements(ArgumentList args) {
|
| + List<ParameterElement> parameters = null;
|
| + AstNode argsParent = args.parent;
|
| + if (argsParent is MethodInvocation) {
|
| + MethodInvocation invocation = argsParent;
|
| + Element nameElement = invocation.methodName.staticElement;
|
| + FunctionType functionType = _getFunctionType(nameElement);
|
| + if (functionType != null) {
|
| + parameters = functionType.parameters;
|
| + }
|
| + }
|
| + if (argsParent is InstanceCreationExpression) {
|
| + InstanceCreationExpression creation = argsParent;
|
| + ConstructorElement element = creation.staticElement;
|
| + if (element != null) {
|
| + parameters = element.parameters;
|
| + }
|
| + }
|
| + if (argsParent is Annotation) {
|
| + Annotation annotation = argsParent;
|
| + Element element = annotation.element;
|
| + if (element is ConstructorElement) {
|
| + parameters = element.parameters;
|
| + }
|
| + }
|
| + return parameters;
|
| + }
|
| +
|
| + TypeProvider get typeProvider {
|
| + AnalysisContext analysisContext = _context.compilationUnitElement.context;
|
| + try {
|
| + return (analysisContext as InternalAnalysisContext).typeProvider;
|
| + } on AnalysisException catch (exception) {
|
| + // TODO(brianwilkerson) Figure out the right thing to do if the core cannot be resolved.
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + bool get hasErrorBeforeCompletionLocation {
|
| + List<AnalysisError> errors = _context.errors;
|
| + if (errors == null || errors.length == 0) {
|
| + return false;
|
| + }
|
| + return errors[0].offset <= _completionLocation();
|
| + }
|
| +
|
| + List<ImportElement> _importsWithName(SimpleIdentifier libName) {
|
| + String name = libName.name;
|
| + List<ImportElement> imports = [];
|
| + for (ImportElement imp in currentLibrary.imports) {
|
| + PrefixElement prefix = imp.prefix;
|
| + if (prefix != null) {
|
| + String impName = prefix.displayName;
|
| + if (name == impName) {
|
| + imports.add(imp);
|
| + }
|
| + }
|
| + }
|
| + return new List.from(imports);
|
| + }
|
| +
|
| + bool _isCompletingKeyword(Token keyword) {
|
| + if (keyword == null) {
|
| + return false;
|
| + }
|
| + int completionLoc = _context.selectionOffset;
|
| + if (completionLoc >= keyword.offset && completionLoc <= keyword.end) {
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool _isCompletionAfter(int loc) => loc <= _completionLocation();
|
| +
|
| + bool _isCompletionBefore(int loc) => _completionLocation() <= loc;
|
| +
|
| + bool _isCompletionBetween(int firstLoc, int secondLoc) => _isCompletionAfter(firstLoc) && _isCompletionBefore(secondLoc);
|
| +
|
| + bool _isDeprecated(Element element) => element != null && element.isDeprecated;
|
| +
|
| + bool _isInCurrentLibrary(Element element) {
|
| + LibraryElement libElement = currentLibrary;
|
| + return identical(element.library, libElement);
|
| + }
|
| +
|
| + bool _isUnitInLibFolder(CompilationUnitElement cu) {
|
| + String pathString = cu.source.fullName;
|
| + if (pathString.indexOf("/lib/") == -1) {
|
| + return false;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + bool _isVisible(Element element) => !_isPrivate(element) || _isInCurrentLibrary(element);
|
| +
|
| + String _makeNonconflictingName(String candidate, List<String> names) {
|
| + String possibility = candidate;
|
| + int count = 0;
|
| + loop: while (true) {
|
| + String name = count == 0 ? possibility : "${possibility}${count}";
|
| + for (String conflict in names) {
|
| + if (name == conflict) {
|
| + count += 1;
|
| + continue loop;
|
| + }
|
| + }
|
| + return name;
|
| + }
|
| + }
|
| +
|
| + void _pArgumentList(CompletionProposal proposal, int offset, int len) {
|
| + // prepare parameters
|
| + List<String> parameterNames = proposal.parameterNames;
|
| + if (parameterNames.length == 0) {
|
| + return;
|
| + }
|
| + // fill arguments proposal
|
| + CompletionProposal prop = _createProposal4(ProposalKind.ARGUMENT_LIST);
|
| + prop.setElement(proposal.element);
|
| + prop.setCompletion(proposal.completion).setReturnType(proposal.returnType);
|
| + prop.setParameterNames(parameterNames);
|
| + prop.setParameterTypes(proposal.parameterTypes);
|
| + prop.setParameterStyle(proposal.positionalParameterCount, proposal.hasNamed, proposal.hasPositional);
|
| + prop.setReplacementLength(0).setLocation(_completionLocation());
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_HIGH);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pDynamic() {
|
| + _pWord(_C_DYNAMIC, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pExecutable(Element element, FunctionType functionType, SimpleIdentifier identifier, bool isPotentialMatch) {
|
| + // Create a completion proposal for the element: function, method, getter, setter, constructor.
|
| + String name = element.displayName;
|
| + if (name.isEmpty) {
|
| + return;
|
| + }
|
| + if (_filterDisallows(element)) {
|
| + return;
|
| + }
|
| + if (!_isVisible(element)) {
|
| + return;
|
| + }
|
| + // May be we are in argument of function type parameter, propose function reference.
|
| + if (_state._targetParameter != null) {
|
| + DartType parameterType = _state._targetParameter.type;
|
| + if (parameterType is FunctionType) {
|
| + if (functionType.isAssignableTo(parameterType)) {
|
| + _pName2(name, element, CompletionProposal.RELEVANCE_HIGH, ProposalKind.METHOD_NAME);
|
| + }
|
| + }
|
| + }
|
| + CompletionProposal prop = _createProposal(element);
|
| + prop.setPotentialMatch(isPotentialMatch);
|
| + if (isPotentialMatch) {
|
| + prop.setRelevance(CompletionProposal.RELEVANCE_LOW);
|
| + }
|
| + _setParameterInfo(functionType, prop);
|
| + prop.setCompletion(name).setReturnType(functionType.returnType.displayName);
|
| + // If there is already argument list, then update only method name.
|
| + if (identifier.parent is MethodInvocation && (identifier.parent as MethodInvocation).argumentList != null) {
|
| + prop.setKind(ProposalKind.METHOD_NAME);
|
| + }
|
| + Element container = element.enclosingElement;
|
| + if (container != null) {
|
| + prop.setDeclaringType(container.displayName);
|
| + }
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pExecutable2(ExecutableElement element, SimpleIdentifier identifier, bool isPotentialMatch) {
|
| + _pExecutable(element, element.type, identifier, isPotentialMatch);
|
| + }
|
| +
|
| + void _pExecutable3(VariableElement element, SimpleIdentifier identifier) {
|
| + // Create a completion proposal for the element: top-level variable.
|
| + String name = element.displayName;
|
| + if (name.isEmpty || _filterDisallows(element)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal(element);
|
| + if (element.type != null) {
|
| + prop.setReturnType(element.type.name);
|
| + }
|
| + Element container = element.enclosingElement;
|
| + if (container != null) {
|
| + prop.setDeclaringType(container.displayName);
|
| + }
|
| + if (identifier != null) {
|
| + prop.setReplacementLengthIdentifier(identifier.length);
|
| + }
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pFalse() {
|
| + _pWord(_C_FALSE, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pField(FieldElement element, SimpleIdentifier identifier, ClassElement classElement) {
|
| + // Create a completion proposal for the element: field only.
|
| + if (_filterDisallows(element)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal(element);
|
| + Element container = element.enclosingElement;
|
| + prop.setDeclaringType(container.displayName);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + /**
|
| + * Proposes URI with the given scheme for the given [NamespaceDirective].
|
| + */
|
| + void _pImportUriWithScheme(NamespaceDirective node, String uriScheme) {
|
| + String newUri = "${uriScheme}${new String.fromCharCode(CompletionProposal.CURSOR_MARKER)}";
|
| + if (node.uri.isSynthetic) {
|
| + newUri = "'${newUri}'";
|
| + if (node.semicolon == null || node.semicolon.isSynthetic) {
|
| + newUri += ";";
|
| + }
|
| + }
|
| + if (_context.selectionOffset == node.keyword.end) {
|
| + newUri = " ${newUri}";
|
| + }
|
| + _pName3(newUri, ProposalKind.IMPORT);
|
| + }
|
| +
|
| + void _pKeyword(Token keyword) {
|
| + _filter = new Filter.con2(keyword.lexeme, keyword.offset, _completionLocation());
|
| + // This isn't as useful as it might seem. It only works in the case that completion
|
| + // is requested on an existing recognizable keyword.
|
| + // TODO: Add keyword proposal kind
|
| + CompletionProposal prop = _createProposal4(ProposalKind.LIBRARY_PREFIX);
|
| + prop.setCompletion(keyword.lexeme);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pName(Element element, SimpleIdentifier identifier) {
|
| + CompletionProposal prop = _createProposal2(element, identifier);
|
| + if (prop != null) {
|
| + _requestor.accept(prop);
|
| + }
|
| + }
|
| +
|
| + void _pName2(String name, Element element, int relevance, ProposalKind kind) {
|
| + if (_filterDisallows2(name)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal4(kind);
|
| + prop.setRelevance(relevance);
|
| + prop.setCompletion(name);
|
| + prop.setElement(element);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pName3(String name, ProposalKind kind) {
|
| + if (_filterDisallows2(name)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal4(kind);
|
| + prop.setCompletion(name);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pNamedConstructor(ClassElement classElement, ConstructorElement element, SimpleIdentifier identifier) {
|
| + // Create a completion proposal for the named constructor.
|
| + String name = classElement.displayName;
|
| + if (!element.displayName.isEmpty) {
|
| + name += ".${element.displayName}";
|
| + }
|
| + if (_filterDisallows2(name)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal3(element, name);
|
| + _setParameterInfo(element.type, prop);
|
| + prop.setReturnType(element.type.returnType.name);
|
| + Element container = element.enclosingElement;
|
| + prop.setDeclaringType(container.displayName);
|
| + if (identifier != null) {
|
| + prop.setReplacementLengthIdentifier(identifier.length);
|
| + }
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _pNull() {
|
| + _pWord(_C_NULL, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pParamName(String name) {
|
| + if (_filterDisallows2(name)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal4(ProposalKind.PARAMETER);
|
| + prop.setCompletion(name);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + ProposalKind _proposalKindOf(Element element) {
|
| + ProposalKind kind;
|
| + while (true) {
|
| + if (element.kind == ElementKind.CONSTRUCTOR) {
|
| + kind = ProposalKind.CONSTRUCTOR;
|
| + } else if (element.kind == ElementKind.FUNCTION) {
|
| + kind = ProposalKind.FUNCTION;
|
| + } else if (element.kind == ElementKind.METHOD) {
|
| + kind = ProposalKind.METHOD;
|
| + } else if (element.kind == ElementKind.GETTER) {
|
| + kind = ProposalKind.GETTER;
|
| + } else if (element.kind == ElementKind.SETTER) {
|
| + kind = ProposalKind.SETTER;
|
| + } else if (element.kind == ElementKind.CLASS) {
|
| + kind = ProposalKind.CLASS;
|
| + } else if (element.kind == ElementKind.FIELD) {
|
| + kind = ProposalKind.FIELD;
|
| + } else if (element.kind == ElementKind.IMPORT) {
|
| + kind = ProposalKind.IMPORT;
|
| + } else if (element.kind == ElementKind.PARAMETER) {
|
| + kind = ProposalKind.PARAMETER;
|
| + } else if (element.kind == ElementKind.PREFIX) {
|
| + kind = ProposalKind.LIBRARY_PREFIX;
|
| + } else if (element.kind == ElementKind.FUNCTION_TYPE_ALIAS) {
|
| + kind = ProposalKind.CLASS_ALIAS;
|
| + } else if (element.kind == ElementKind.TYPE_PARAMETER) {
|
| + kind = ProposalKind.TYPE_PARAMETER;
|
| + } else if (element.kind == ElementKind.LOCAL_VARIABLE || element.kind == ElementKind.TOP_LEVEL_VARIABLE) {
|
| + kind = ProposalKind.VARIABLE;
|
| + } else {
|
| + throw new IllegalArgumentException();
|
| + }
|
| + break;
|
| + }
|
| + return kind;
|
| + }
|
| +
|
| + void _proposeCombinator(Combinator node, SimpleIdentifier identifier) {
|
| + _filter = _createFilter(identifier);
|
| + NamespaceDirective directive = node.parent as NamespaceDirective;
|
| + LibraryElement libraryElement = directive.uriElement;
|
| + if (libraryElement != null) {
|
| + // prepare Elements with unique names
|
| + CompletionEngine_NameCollector nameCollector = _createNameCollector();
|
| + Iterable<Element> elements = CorrectionUtils.getExportNamespace2(libraryElement).values;
|
| + for (Element element in elements) {
|
| + if (_filterDisallows(element)) {
|
| + continue;
|
| + }
|
| + nameCollector._mergeName(element);
|
| + }
|
| + // propose each Element
|
| + for (Element element in nameCollector.uniqueElements) {
|
| + CompletionProposal proposal = _createProposal(element);
|
| + if (proposal.kind == ProposalKind.FUNCTION) {
|
| + proposal.setKind(ProposalKind.METHOD_NAME);
|
| + }
|
| + _requestor.accept(proposal);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _proposeName(Element element, SimpleIdentifier identifier, CompletionEngine_NameCollector names) {
|
| + while (true) {
|
| + if (element.kind == ElementKind.FUNCTION || element.kind == ElementKind.GETTER || element.kind == ElementKind.METHOD || element.kind == ElementKind.SETTER) {
|
| + ExecutableElement candidate = element as ExecutableElement;
|
| + _pExecutable2(candidate, identifier, names._isPotentialMatch(candidate));
|
| + } else if (element.kind == ElementKind.LOCAL_VARIABLE || element.kind == ElementKind.PARAMETER || element.kind == ElementKind.TOP_LEVEL_VARIABLE) {
|
| + FunctionType functionType = _getFunctionType(element);
|
| + if (functionType != null) {
|
| + _pExecutable(element, functionType, identifier, names._isPotentialMatch(element));
|
| + } else {
|
| + VariableElement var2 = element as VariableElement;
|
| + _pExecutable3(var2, identifier);
|
| + }
|
| + } else if (element.kind == ElementKind.CLASS) {
|
| + _pName(element, identifier);
|
| + } else {
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void _proposeNames(CompletionEngine_NameCollector names, SimpleIdentifier identifier) {
|
| + for (Element element in names.uniqueElements) {
|
| + _proposeName(element, identifier, names);
|
| + }
|
| + }
|
| +
|
| + void _pTrue() {
|
| + _pWord(_C_TRUE, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pVar() {
|
| + _pWord(_C_VAR, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pVoid() {
|
| + _pWord(_C_VOID, ProposalKind.VARIABLE);
|
| + }
|
| +
|
| + void _pWord(String word, ProposalKind kind) {
|
| + if (_filterDisallows2(word)) {
|
| + return;
|
| + }
|
| + CompletionProposal prop = _createProposal4(kind);
|
| + prop.setCompletion(word);
|
| + _requestor.accept(prop);
|
| + }
|
| +
|
| + void _removeNotMatchingFilter(List<Element> elements) {
|
| + if (_filter == null) {
|
| + return;
|
| + }
|
| + _filter._makePattern();
|
| + _filter._removeNotMatching(elements);
|
| + }
|
| +
|
| + void _setParameterInfo(FunctionType functionType, CompletionProposal prop) {
|
| + List<String> params = new List<String>();
|
| + List<String> types = new List<String>();
|
| + bool named = false, positional = false;
|
| + int posCount = 0;
|
| + for (ParameterElement param in functionType.parameters) {
|
| + if (!param.isSynthetic) {
|
| + while (true) {
|
| + if (param.parameterKind == ParameterKind.REQUIRED) {
|
| + posCount += 1;
|
| + } else if (param.parameterKind == ParameterKind.NAMED) {
|
| + named = true;
|
| + } else if (param.parameterKind == ParameterKind.POSITIONAL) {
|
| + positional = true;
|
| + }
|
| + break;
|
| + }
|
| + params.add(param.displayName);
|
| + types.add(param.type.toString());
|
| + }
|
| + }
|
| + prop.setParameterNames(new List.from(params));
|
| + prop.setParameterTypes(new List.from(types));
|
| + prop.setParameterStyle(posCount, named, positional);
|
| + }
|
| +
|
| + SimpleIdentifier _typeDeclarationName(AstNode node) {
|
| + AstNode parent = node;
|
| + while (parent != null) {
|
| + if (parent is ClassDeclaration) {
|
| + return (parent as ClassDeclaration).name;
|
| + }
|
| + if (parent is ClassTypeAlias) {
|
| + return (parent as ClassTypeAlias).name;
|
| + }
|
| + if (parent is FunctionTypeAlias) {
|
| + return (parent as FunctionTypeAlias).name;
|
| + }
|
| + parent = parent.parent;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + DartType _typeOf(Element receiver) {
|
| + DartType receiverType;
|
| + while (true) {
|
| + if (receiver.kind == ElementKind.FIELD || receiver.kind == ElementKind.PARAMETER || receiver.kind == ElementKind.LOCAL_VARIABLE || receiver.kind == ElementKind.TOP_LEVEL_VARIABLE) {
|
| + {
|
| + VariableElement receiverElement = receiver as VariableElement;
|
| + receiverType = receiverElement.type;
|
| + break;
|
| + }
|
| + } else if (receiver.kind == ElementKind.GETTER) {
|
| + PropertyAccessorElement accessor = receiver as PropertyAccessorElement;
|
| + if (accessor.isSynthetic) {
|
| + PropertyInducingElement inducer = accessor.variable;
|
| + DartType inducerType = inducer.type;
|
| + if (inducerType == null || inducerType.isDynamic) {
|
| + receiverType = _typeSearch(inducer);
|
| + if (receiverType != null) {
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + FunctionType accType = accessor.type;
|
| + receiverType = accType == null ? null : accType.returnType;
|
| + } else if (receiver.kind == ElementKind.CONSTRUCTOR || receiver.kind == ElementKind.FUNCTION || receiver.kind == ElementKind.METHOD || receiver.kind == ElementKind.SETTER) {
|
| + {
|
| + ExecutableElement receiverElement = receiver as ExecutableElement;
|
| + FunctionType funType = receiverElement.type;
|
| + receiverType = funType == null ? null : funType.returnType;
|
| + break;
|
| + }
|
| + } else if (receiver.kind == ElementKind.CLASS) {
|
| + {
|
| + ClassElement receiverElement = receiver as ClassElement;
|
| + receiverType = receiverElement.type;
|
| + break;
|
| + }
|
| + } else if (receiver.kind == ElementKind.DYNAMIC) {
|
| + {
|
| + receiverType = DynamicTypeImpl.instance;
|
| + break;
|
| + }
|
| + } else if (receiver.kind == ElementKind.FUNCTION_TYPE_ALIAS) {
|
| + {
|
| + FunctionTypeAliasElement receiverElement = receiver as FunctionTypeAliasElement;
|
| + FunctionType funType = receiverElement.type;
|
| + receiverType = funType == null ? null : funType.returnType;
|
| + break;
|
| + }
|
| + } else {
|
| + {
|
| + receiverType = null;
|
| + break;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + return receiverType;
|
| + }
|
| +
|
| + DartType _typeOf2(Expression expr) {
|
| + DartType type = expr.bestType;
|
| + if (type.isDynamic) {
|
| + List<DartType> result = new List<DartType>(1);
|
| + CompletionEngine_AstNodeClassifier visitor = new AstNodeClassifier_CompletionEngine_typeOf(this, result);
|
| + expr.accept(visitor);
|
| + if (result[0] != null) {
|
| + return result[0];
|
| + }
|
| + }
|
| + return type;
|
| + }
|
| +
|
| + DartType _typeOfContainingClass(AstNode node) {
|
| + AstNode parent = node;
|
| + while (parent != null) {
|
| + if (parent is ClassDeclaration) {
|
| + return (parent as ClassDeclaration).element.type;
|
| + }
|
| + parent = parent.parent;
|
| + }
|
| + return DynamicTypeImpl.instance;
|
| + }
|
| +
|
| + DartType _typeSearch(PropertyInducingElement varElement) {
|
| + // TODO(scheglov) translate it
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +abstract class CompletionEngine_AstNodeClassifier extends GeneralizingAstVisitor<Object> {
|
| + @override
|
| + Object visitNode(AstNode node) => null;
|
| +}
|
| +
|
| +class CompletionEngine_CommentReferenceCompleter extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + final SimpleIdentifier _identifier;
|
| +
|
| + CompletionEngine_NameCollector _names;
|
| +
|
| + Set<Element> _enclosingElements = new Set();
|
| +
|
| + CompletionEngine_CommentReferenceCompleter(this.CompletionEngine_this, this._identifier) {
|
| + CompletionEngine_this._filter = CompletionEngine_this._createFilter(_identifier);
|
| + _names = CompletionEngine_this._collectTopLevelElementVisibleAt(_identifier);
|
| + }
|
| +
|
| + @override
|
| + Object visitClassDeclaration(ClassDeclaration node) {
|
| + ClassElement classElement = node.element;
|
| + _names._addNamesDefinedByHierarchy(classElement, false);
|
| + _enclosingElements.add(classElement);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitComment(Comment node) {
|
| + node.parent.accept(this);
|
| + // propose names
|
| + for (Element element in _names.uniqueElements) {
|
| + CompletionProposal proposal = CompletionEngine_this._createProposal2(element, _identifier);
|
| + if (proposal != null) {
|
| + // we don't want to add arguments, just names
|
| + if (element is MethodElement || element is FunctionElement) {
|
| + proposal.setKind(ProposalKind.METHOD_NAME);
|
| + }
|
| + // elevate priority for local elements
|
| + if (_enclosingElements.contains(element.enclosingElement)) {
|
| + proposal.setRelevance(CompletionProposal.RELEVANCE_HIGH);
|
| + }
|
| + // propose
|
| + CompletionEngine_this._requestor.accept(proposal);
|
| + }
|
| + }
|
| + // done
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + _visitExecutableDeclaration(node);
|
| + // pass through
|
| + return node.parent.accept(this);
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionDeclaration(FunctionDeclaration node) {
|
| + _visitExecutableDeclaration(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + FunctionTypeAliasElement element = node.element;
|
| + _names._mergeNames(element.parameters);
|
| + _enclosingElements.add(element);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + _visitExecutableDeclaration(node);
|
| + // pass through
|
| + return node.parent.accept(this);
|
| + }
|
| +
|
| + void _visitExecutableDeclaration(Declaration node) {
|
| + ExecutableElement element = node.element as ExecutableElement;
|
| + _names._mergeNames(element.parameters);
|
| + _enclosingElements.add(element);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An IdentifierCompleter is used to classify the parent of the completion node when it has
|
| + * previously been determined that the completion node is a SimpleIdentifier.
|
| + */
|
| +class CompletionEngine_IdentifierCompleter extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + SimpleIdentifier _completionNode;
|
| +
|
| + CompletionEngine_IdentifierCompleter(this.CompletionEngine_this, SimpleIdentifier node) {
|
| + _completionNode = node;
|
| + }
|
| +
|
| + @override
|
| + Object visitAnnotation(Annotation node) {
|
| + if (_completionNode is SimpleIdentifier) {
|
| + CompletionEngine_this._analyzeAnnotationName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitArgumentList(ArgumentList node) {
|
| + if (_completionNode is SimpleIdentifier) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftParenthesis.end, node.rightParenthesis.offset)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + CompletionEngine_this._analyzePositionalArgument(node, _completionNode);
|
| + CompletionEngine_this._analyzeNamedParameter(node, _completionNode);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitAssignmentExpression(AssignmentExpression node) {
|
| + if (_completionNode is SimpleIdentifier) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitBinaryExpression(BinaryExpression node) {
|
| + if (identical(node.leftOperand, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + } else if (identical(node.rightOperand, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCombinator(Combinator node) {
|
| + CompletionEngine_this._proposeCombinator(node, _completionNode);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCommentReference(CommentReference node) {
|
| + AstNode comment = node.parent;
|
| + CompletionEngine_CommentReferenceCompleter visitor = new CompletionEngine_CommentReferenceCompleter(CompletionEngine_this, _completionNode);
|
| + return comment.accept(visitor);
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + if (identical(node.returnType, _completionNode)) {
|
| + CompletionEngine_this._filter = CompletionEngine_this._createFilter(_completionNode);
|
| + CompletionEngine_this._pName3(_completionNode.name, ProposalKind.CONSTRUCTOR);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
|
| + // { A() : this.!x = 1; }
|
| + if (identical(node.fieldName, _completionNode)) {
|
| + ClassElement classElement = (node.parent as ConstructorDeclaration).element.enclosingElement;
|
| + CompletionEngine_this._fieldReference(classElement, node.fieldName);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorName(ConstructorName node) {
|
| + if (identical(node.name, _completionNode)) {
|
| + // { new A.!c(); }
|
| + TypeName typeName = node.type;
|
| + if (typeName != null) {
|
| + DartType type = typeName.type;
|
| + Element typeElement = type.element;
|
| + if (typeElement is ClassElement) {
|
| + ClassElement classElement = typeElement;
|
| + CompletionEngine_this._constructorReference(classElement, node.name);
|
| + }
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitDoStatement(DoStatement node) {
|
| + if (identical(node.condition, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpression(Expression node) {
|
| + SimpleIdentifier ident;
|
| + if (_completionNode is SimpleIdentifier) {
|
| + ident = _completionNode;
|
| + } else {
|
| + ident = CompletionEngine_this._createIdent(node);
|
| + }
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| + if (identical(_completionNode, node.expression)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpressionStatement(ExpressionStatement node) {
|
| + SimpleIdentifier ident;
|
| + if (_completionNode is SimpleIdentifier) {
|
| + ident = _completionNode;
|
| + } else {
|
| + ident = CompletionEngine_this._createIdent(node);
|
| + }
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFieldFormalParameter(FieldFormalParameter node) {
|
| + if (identical(_completionNode, node.identifier)) {
|
| + CompletionEngine_this._analyzeImmediateField(node.identifier);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitForEachStatement(ForEachStatement node) {
|
| + if (identical(node.iterator, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + if (identical(node.name, _completionNode)) {
|
| + if (node.returnType == null) {
|
| + // This may be an incomplete class type alias
|
| + CompletionEngine_this._state._includesUndefinedTypes();
|
| + CompletionEngine_this._analyzeTypeName(node.name, CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitIfStatement(IfStatement node) {
|
| + if (identical(node.condition, _completionNode)) {
|
| + // { if (!) }
|
| + CompletionEngine_this._analyzeLocalName(new Ident.con3(node, _completionNode.token));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitInterpolationExpression(InterpolationExpression node) {
|
| + if (node.expression is SimpleIdentifier) {
|
| + SimpleIdentifier ident = node.expression as SimpleIdentifier;
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitLibraryIdentifier(LibraryIdentifier node) => null;
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + if (identical(_completionNode, node.name)) {
|
| + if (node.returnType == null) {
|
| + // class Foo {const F!(); }
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodInvocation(MethodInvocation node) {
|
| + if (identical(node.methodName, _completionNode)) {
|
| + // { x.!y() }
|
| + Expression expr = node.realTarget;
|
| + DartType receiverType;
|
| + if (expr == null) {
|
| + receiverType = CompletionEngine_this._typeOfContainingClass(node);
|
| + CompletionEngine_this._analyzeDirectAccess(receiverType, node.methodName);
|
| + } else {
|
| + CompletionEngine_this._dispatchPrefixAnalysis2(node);
|
| + }
|
| + } else if (identical(node.target, _completionNode)) {
|
| + // { x!.y() } -- only reached when node.getTarget() is a simple identifier.
|
| + if (_completionNode is SimpleIdentifier) {
|
| + SimpleIdentifier ident = _completionNode;
|
| + CompletionEngine_this._analyzeReceiver(ident);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitParenthesizedExpression(ParenthesizedExpression node) {
|
| + // Incomplete closure: foo((Str!)); We check if "()" is argument for function typed parameter.
|
| + if (node.parent is ArgumentList) {
|
| + ParameterElement parameterElement = node.bestParameterElement;
|
| + if (parameterElement != null && parameterElement.type is FunctionType) {
|
| + Ident ident = CompletionEngine_this._createIdent(_completionNode);
|
| + CompletionEngine_this._analyzeTypeName(_completionNode, ident);
|
| + }
|
| + }
|
| + return super.visitParenthesizedExpression(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + if (identical(node.prefix, _completionNode)) {
|
| + // { x!.y }
|
| + CompletionEngine_this._analyzeLocalName(node.prefix);
|
| + } else {
|
| + // { v.! }
|
| + CompletionEngine_this._dispatchPrefixAnalysis3(node, node.identifier);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitPropertyAccess(PropertyAccess node) {
|
| + if (node.target != null && node.target.length == 0) {
|
| + return null;
|
| + }
|
| + // { o.!hashCode }
|
| + if (identical(node.propertyName, _completionNode)) {
|
| + CompletionEngine_this._analyzePrefixedAccess(node.realTarget, node.propertyName);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
|
| + // { A.Fac() : this.!b(); }
|
| + if (identical(node.constructorName, _completionNode)) {
|
| + ClassElement classElement = node.staticElement.enclosingElement;
|
| + CompletionEngine_this._constructorReference(classElement, node.constructorName);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitReturnStatement(ReturnStatement node) {
|
| + if (_completionNode is SimpleIdentifier) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + if (identical(node.identifier, _completionNode)) {
|
| + if (node.keyword == null && node.type == null) {
|
| + Ident ident = CompletionEngine_this._createIdent(node);
|
| + CompletionEngine_this._analyzeTypeName(node.identifier, ident);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
| + CompletionEngine_this._analyzeSuperConstructorInvocation(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchCase(SwitchCase node) {
|
| + if (identical(_completionNode, node.expression)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchStatement(SwitchStatement node) {
|
| + if (identical(node.expression, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeName(TypeName node) {
|
| + AstNode parent = node.parent;
|
| + if (parent != null) {
|
| + CompletionEngine_TypeNameCompleter visitor = new CompletionEngine_TypeNameCompleter(CompletionEngine_this, _completionNode, node);
|
| + return parent.accept(visitor);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeParameter(TypeParameter node) {
|
| + // { X<!Y> }
|
| + if (CompletionEngine_this._isCompletionBetween(node.offset, node.end)) {
|
| + CompletionEngine_this._analyzeTypeName(_completionNode, CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclaration(VariableDeclaration node) {
|
| + if (identical(node.name, _completionNode)) {
|
| + CompletionEngine_this._analyzeDeclarationName(node);
|
| + } else if (identical(node.initializer, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(node.initializer as SimpleIdentifier);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitWhileStatement(WhileStatement node) {
|
| + if (identical(node.condition, _completionNode)) {
|
| + CompletionEngine_this._analyzeLocalName(_completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +class CompletionEngine_NameCollector {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + Map<String, List<Element>> _uniqueNames = new Map<String, List<Element>>();
|
| +
|
| + Set<Element> _potentialMatches;
|
| +
|
| + CompletionEngine_NameCollector(this.CompletionEngine_this);
|
| +
|
| + void addAll(Iterable<SimpleIdentifier> values) {
|
| + for (SimpleIdentifier id in values) {
|
| + _mergeName(id.bestElement);
|
| + }
|
| + }
|
| +
|
| + void addLocalNames(SimpleIdentifier identifier) {
|
| + AstNode node = identifier;
|
| + Declaration decl;
|
| + while ((decl = node.getAncestor((node) => node is Declaration)) != null) {
|
| + Element declElement = decl.element;
|
| + if (declElement is ExecutableElement) {
|
| + _addNamesDefinedByExecutable(declElement);
|
| + } else {
|
| + return;
|
| + }
|
| + node = decl.parent;
|
| + }
|
| + }
|
| +
|
| + void _addNamesDefinedByExecutable(ExecutableElement execElement) {
|
| + _mergeNames(execElement.parameters);
|
| + _mergeNames(execElement.localVariables);
|
| + _mergeNames(execElement.functions);
|
| + }
|
| +
|
| + void _addNamesDefinedByHierarchy(ClassElement classElement, bool forSuper) {
|
| + _addNamesDefinedByHierarchy2(classElement.type, forSuper);
|
| + }
|
| +
|
| + void _addNamesDefinedByHierarchy2(InterfaceType type, bool forSuper) {
|
| + List<InterfaceType> superTypes = type.element.allSupertypes;
|
| + if (!forSuper) {
|
| + superTypes = ArrayUtils.add(superTypes, 0, type);
|
| + }
|
| + _addNamesDefinedByTypes(superTypes);
|
| + // Collect names defined by subtypes separately so they can be identified later.
|
| + CompletionEngine_NameCollector potentialMatchCollector = CompletionEngine_this._createNameCollector();
|
| + if (!type.isObject) {
|
| + potentialMatchCollector._addNamesDefinedByTypes(CompletionEngine_this._allSubtypes(type.element));
|
| + }
|
| + _potentialMatches = new Set<Element>();
|
| + for (List<Element> matches in potentialMatchCollector._uniqueNames.values) {
|
| + for (Element match in matches) {
|
| + _mergeName(match);
|
| + _potentialMatches.add(match);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _addNamesDefinedByType(ClassElement classElement) {
|
| + _addNamesDefinedByType2(classElement.type);
|
| + }
|
| +
|
| + void _addNamesDefinedByType2(InterfaceType type) {
|
| + if (_inPrivateLibrary(type)) {
|
| + return;
|
| + }
|
| + List<PropertyAccessorElement> accessors = type.accessors;
|
| + _mergeNames(accessors);
|
| + List<MethodElement> methods = type.methods;
|
| + _mergeNames(methods);
|
| + _mergeNames(type.element.typeParameters);
|
| + _filterStaticRefs(accessors);
|
| + _filterStaticRefs(methods);
|
| + }
|
| +
|
| + void _addNamesDefinedByTypes(List<InterfaceType> types) {
|
| + for (InterfaceType type in types) {
|
| + _addNamesDefinedByType2(type);
|
| + }
|
| + }
|
| +
|
| + void _addTopLevelNames(List<ImportElement> imports, TopLevelNamesKind topKind) {
|
| + for (ImportElement imp in imports) {
|
| + Iterable<Element> elementsCollection = CorrectionUtils.getImportNamespace(imp).values;
|
| + List<Element> elements = [];
|
| + _addTopLevelNames4(elements);
|
| + }
|
| + }
|
| +
|
| + void _addTopLevelNames2(LibraryElement library, TopLevelNamesKind topKind) {
|
| + List<Element> elements = CompletionEngine_this._findTopLevelElements(library, topKind);
|
| + _addTopLevelNames4(elements);
|
| + }
|
| +
|
| + void _addTopLevelNames3(List<LibraryElement> libraries, TopLevelNamesKind topKind) {
|
| + for (LibraryElement library in libraries) {
|
| + _addTopLevelNames2(library, topKind);
|
| + }
|
| + }
|
| +
|
| + Iterable<List<Element>> get names => _uniqueNames.values;
|
| +
|
| + Iterable<Element> get uniqueElements {
|
| + List<Element> uniqueElements = [];
|
| + for (List<Element> uniques in _uniqueNames.values) {
|
| + Element element = uniques[0];
|
| + uniqueElements.add(element);
|
| + }
|
| + return uniqueElements;
|
| + }
|
| +
|
| + bool _isPotentialMatch(Element element) => _potentialMatches != null && _potentialMatches.contains(element);
|
| +
|
| + void _remove(Element element) {
|
| + String name = element.displayName;
|
| + List<Element> list = _uniqueNames[name];
|
| + if (list == null) {
|
| + return;
|
| + }
|
| + list.remove(element);
|
| + if (list.isEmpty) {
|
| + _uniqueNames.remove(name);
|
| + }
|
| + }
|
| +
|
| + void _addTopLevelNames4(List<Element> elements) {
|
| + _mergeNames(CompletionEngine_this._findAllTypes2(elements));
|
| + if (!CompletionEngine_this._state._areClassesRequired) {
|
| + _mergeNames(CompletionEngine_this._findAllNotTypes(elements));
|
| + _mergeNames(CompletionEngine_this._findAllPrefixes());
|
| + }
|
| + }
|
| +
|
| + void _filterStaticRefs(List<ExecutableElement> elements) {
|
| + for (ExecutableElement execElem in elements) {
|
| + if (CompletionEngine_this._state._areInstanceReferencesProhibited && !execElem.isStatic) {
|
| + _remove(execElem);
|
| + } else if (CompletionEngine_this._state._areStaticReferencesProhibited && execElem.isStatic) {
|
| + _remove(execElem);
|
| + } else if (!CompletionEngine_this._state._areOperatorsAllowed && execElem.isOperator) {
|
| + _remove(execElem);
|
| + } else if (CompletionEngine_this._state._areMethodsProhibited && !execElem.isOperator) {
|
| + _remove(execElem);
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool _inPrivateLibrary(InterfaceType type) {
|
| + LibraryElement lib = type.element.library;
|
| + if (!lib.name.startsWith("_")) {
|
| + return false;
|
| + }
|
| + // allow completion in the same library
|
| + if (identical(lib, CompletionEngine_this.currentLibrary)) {
|
| + return false;
|
| + }
|
| + // eliminate types defined in private libraries
|
| + return true;
|
| + }
|
| +
|
| + void _mergeName(Element element) {
|
| + if (element == null) {
|
| + return;
|
| + }
|
| + // ignore private
|
| + String name = element.displayName;
|
| + if (Identifier.isPrivateName(name)) {
|
| + if (!CompletionEngine_this._isInCurrentLibrary(element)) {
|
| + return;
|
| + }
|
| + }
|
| + // add to other Element(s) with such name
|
| + List<Element> dups = _uniqueNames[name];
|
| + if (dups == null) {
|
| + dups = new List<Element>();
|
| + _uniqueNames[name] = dups;
|
| + }
|
| + dups.add(element);
|
| + }
|
| +
|
| + void _mergeNames(List<Element> elements) {
|
| + for (Element element in elements) {
|
| + _mergeName(element);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An StringCompleter is used to classify the parent of the completion node when it has previously
|
| + * been determined that the completion node is a SimpleStringLiteral.
|
| + */
|
| +class CompletionEngine_StringCompleter extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + SimpleStringLiteral _completionNode;
|
| +
|
| + CompletionEngine_StringCompleter(this.CompletionEngine_this, SimpleStringLiteral node) {
|
| + _completionNode = node;
|
| + }
|
| +
|
| + @override
|
| + Object visitNamespaceDirective(NamespaceDirective node) {
|
| + if (identical(_completionNode, node.uri)) {
|
| + CompletionEngine_this._namespaceReference(node, _completionNode);
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A TerminalNodeCompleter is used to classify the completion node when nothing else is known
|
| + * about it.
|
| + */
|
| +class CompletionEngine_TerminalNodeCompleter extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + CompletionEngine_TerminalNodeCompleter(this.CompletionEngine_this);
|
| +
|
| + @override
|
| + Object visitArgumentList(ArgumentList node) {
|
| + if (node.arguments.isEmpty && CompletionEngine_this._isCompletionBetween(node.leftParenthesis.end, node.rightParenthesis.offset)) {
|
| + if (node.parent is MethodInvocation) {
|
| + // or node.getParent().accept(this); ?
|
| + MethodInvocation invokeNode = node.parent as MethodInvocation;
|
| + SimpleIdentifier methodName = invokeNode.methodName;
|
| + ProposalCollector proposalRequestor = new ProposalCollector(CompletionEngine_this._requestor);
|
| + try {
|
| + CompletionEngine_this._requestor = proposalRequestor;
|
| + CompletionEngine_this._dispatchPrefixAnalysis2(invokeNode);
|
| + } finally {
|
| + CompletionEngine_this._requestor = proposalRequestor.requestor;
|
| + }
|
| + int offset = methodName.offset;
|
| + int len = node.rightParenthesis.end - offset;
|
| + String name = methodName.name;
|
| + for (CompletionProposal proposal in proposalRequestor.proposals) {
|
| + if (proposal.completion == name) {
|
| + CompletionEngine_this._pArgumentList(proposal, offset, len);
|
| + }
|
| + }
|
| + } else if (node.parent is InstanceCreationExpression) {
|
| + InstanceCreationExpression invokeNode = node.parent as InstanceCreationExpression;
|
| + ConstructorName methodName = invokeNode.constructorName;
|
| + ProposalCollector proposalRequestor = new ProposalCollector(CompletionEngine_this._requestor);
|
| + try {
|
| + CompletionEngine_this._requestor = proposalRequestor;
|
| + CompletionEngine_this._dispatchPrefixAnalysis(invokeNode);
|
| + } finally {
|
| + CompletionEngine_this._requestor = proposalRequestor.requestor;
|
| + }
|
| + int offset = methodName.offset;
|
| + int len = node.rightParenthesis.end - offset;
|
| + for (CompletionProposal proposal in proposalRequestor.proposals) {
|
| + if (proposal.element == invokeNode.staticElement) {
|
| + CompletionEngine_this._pArgumentList(proposal, offset, len);
|
| + }
|
| + }
|
| + } else if (node.parent is Annotation) {
|
| + Annotation annotation = node.parent as Annotation;
|
| + Element annotationElement = annotation.element;
|
| + if (annotationElement is ConstructorElement) {
|
| + ConstructorElement constructorElement = annotationElement;
|
| + // we don't need any filter
|
| + CompletionEngine_this._filter = new Filter.con2("", -1, 0);
|
| + // fill parameters for "pArgumentList"
|
| + CompletionProposal prop = CompletionEngine_this._createProposal(constructorElement);
|
| + CompletionEngine_this._setParameterInfo(constructorElement.type, prop);
|
| + prop.setCompletion(constructorElement.enclosingElement.name);
|
| + // propose the whole parameters list
|
| + CompletionEngine_this._pArgumentList(prop, 0, 0);
|
| + }
|
| + }
|
| + }
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftParenthesis.end, node.rightParenthesis.offset)) {
|
| + Ident ident = CompletionEngine_this._createIdent(node);
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + CompletionEngine_this._analyzePositionalArgument(node, ident);
|
| + CompletionEngine_this._analyzeNamedParameter(node, ident);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitAsExpression(AsExpression node) {
|
| + if (CompletionEngine_this._isCompletionAfter(node.asOperator.end)) {
|
| + CompletionEngine_this._state._isDynamicAllowed = false;
|
| + CompletionEngine_this._state._isVoidAllowed = false;
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitAssertStatement(AssertStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitBlock(Block node) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftBracket.end, node.rightBracket.offset)) {
|
| + // { {! stmt; !} }
|
| + CompletionEngine_this._analyzeLocalName(CompletionEngine_this._createIdent(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitBooleanLiteral(BooleanLiteral node) {
|
| + CompletionEngine_this._analyzeLiteralReference(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitBreakStatement(BreakStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCatchClause(CatchClause node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.onKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.onKeyword);
|
| + } else if (CompletionEngine_this._isCompletingKeyword(node.catchKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.catchKeyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitClassDeclaration(ClassDeclaration node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.classKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.classKeyword);
|
| + } else if (CompletionEngine_this._isCompletingKeyword(node.abstractKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.abstractKeyword);
|
| + } else if (!node.leftBracket.isSynthetic) {
|
| + if (CompletionEngine_this._isCompletionAfter(node.leftBracket.end)) {
|
| + if (node.rightBracket.isSynthetic || CompletionEngine_this._isCompletionBefore(node.rightBracket.offset)) {
|
| + if (!CompletionEngine_this.hasErrorBeforeCompletionLocation) {
|
| + CompletionEngine_this._analyzeLocalName(CompletionEngine_this._createIdent(node));
|
| + }
|
| + }
|
| + }
|
| + }
|
| + // TODO { abstract ! class ! A ! extends B implements C, D ! {}}
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitClassTypeAlias(ClassTypeAlias node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + // TODO { typedef ! A ! = ! B ! with C, D !; }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCombinator(Combinator node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCompilationUnit(CompilationUnit node) => null;
|
| +
|
| + @override
|
| + Object visitConstructorName(ConstructorName node) {
|
| + // { new A.!c(); }
|
| + TypeName typeName = node.type;
|
| + if (typeName != null) {
|
| + DartType type = typeName.type;
|
| + Element typeElement = type.element;
|
| + if (typeElement is ClassElement) {
|
| + ClassElement classElement = typeElement;
|
| + CompletionEngine_this._constructorReference(classElement, node.name);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitContinueStatement(ContinueStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitDirective(Directive node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitDoStatement(DoStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.doKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.doKeyword);
|
| + } else if (CompletionEngine_this._isCompletingKeyword(node.whileKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.whileKeyword);
|
| + } else if (CompletionEngine_this._isCompletionBetween(node.condition.end, node.rightParenthesis.offset)) {
|
| + CompletionEngine_this._operatorAccess(node.condition, CompletionEngine_this._createIdent(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitDoubleLiteral(DoubleLiteral node) => null;
|
| +
|
| + @override
|
| + Object visitExportDirective(ExportDirective node) {
|
| + visitNamespaceDirective(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpression(Expression node) {
|
| + CompletionEngine_this._analyzeLocalName(CompletionEngine_this._createIdent(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| + if (node.expression != null && node.semicolon != null) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.expression.end, node.semicolon.offset)) {
|
| + CompletionEngine_this._operatorAccess(node.expression, CompletionEngine_this._createIdent(node));
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExpressionStatement(ExpressionStatement node) {
|
| + CompletionEngine_this._analyzeLocalName(CompletionEngine_this._createIdent(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExtendsClause(ExtendsClause node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + } else if (node.superclass == null) {
|
| + // { X extends ! }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + } else {
|
| + // { X extends ! Y }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitForEachStatement(ForEachStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.forKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.forKeyword);
|
| + } else if (CompletionEngine_this._isCompletingKeyword(node.inKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.inKeyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFormalParameterList(FormalParameterList node) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftParenthesis.end, node.rightParenthesis.offset)) {
|
| + NodeList<FormalParameter> params = node.parameters;
|
| + if (!params.isEmpty) {
|
| + FormalParameter last = params[params.length - 1];
|
| + if (CompletionEngine_this._isCompletionBetween(last.end, node.rightParenthesis.offset)) {
|
| + List<FormalParameter> newParams = CompletionEngine_this._copyWithout(params, last);
|
| + CompletionEngine_this._analyzeNewParameterName(newParams, last.identifier, null);
|
| + } else {
|
| + Ident ident = CompletionEngine_this._createIdent(node);
|
| + CompletionEngine_this._analyzeTypeName(ident, ident);
|
| + }
|
| + } else {
|
| + Ident ident = CompletionEngine_this._createIdent(node);
|
| + CompletionEngine_this._analyzeTypeName(ident, ident);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitForStatement(ForStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.forKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.forKeyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitIfStatement(IfStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.ifKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.ifKeyword);
|
| + } else if (CompletionEngine_this._isCompletingKeyword(node.elseKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.elseKeyword);
|
| + } else if (CompletionEngine_this._isCompletionBetween(node.condition.end, node.rightParenthesis.offset)) {
|
| + CompletionEngine_this._operatorAccess(node.condition, CompletionEngine_this._createIdent(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitImplementsClause(ImplementsClause node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + } else if (node.interfaces.isEmpty) {
|
| + // { X implements ! }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + } else {
|
| + // { X implements ! Y }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitImportDirective(ImportDirective node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.asToken)) {
|
| + CompletionEngine_this._pKeyword(node.asToken);
|
| + } else {
|
| + visitNamespaceDirective(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + Ident ident = new Ident.con3(node, node.keyword);
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + } else {
|
| + Ident ident = CompletionEngine_this._createIdent(node);
|
| + CompletionEngine_this._analyzeConstructorTypeName(ident);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitIsExpression(IsExpression node) {
|
| + Ident ident;
|
| + Token isToken = node.isOperator;
|
| + int isTokenEnd = isToken.end;
|
| + if (isTokenEnd == CompletionEngine_this._completionLocation()) {
|
| + Expression expression = node.expression;
|
| + int offset = isToken.offset;
|
| + // { target.is! } possible name completion, parsed as "target.{synthetic} is!"
|
| + if (expression is PrefixedIdentifier) {
|
| + PrefixedIdentifier prefIdent = expression;
|
| + if (prefIdent.identifier.isSynthetic) {
|
| + CompletionEngine_this._analyzePrefixedAccess(prefIdent.prefix, new Ident.con2(node, "is", offset));
|
| + } else {
|
| + CompletionEngine_this._pKeyword(isToken);
|
| + }
|
| + return null;
|
| + }
|
| + // { expr is! }
|
| + if (!CompletionEngine._isSyntheticIdentifier(expression)) {
|
| + CompletionEngine_this._pKeyword(node.isOperator);
|
| + return null;
|
| + }
|
| + // { is! } possible name completion
|
| + ident = new Ident.con2(node, "is", offset);
|
| + } else if (CompletionEngine_this._isCompletionAfter(isTokenEnd)) {
|
| + CompletionEngine_this._state._isDynamicAllowed = false;
|
| + CompletionEngine_this._state._isVoidAllowed = false;
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), null);
|
| + return null;
|
| + } else {
|
| + ident = CompletionEngine_this._createIdent(node);
|
| + }
|
| + CompletionEngine_this._analyzeLocalName(ident);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitLibraryIdentifier(LibraryIdentifier node) => null;
|
| +
|
| + @override
|
| + Object visitMethodInvocation(MethodInvocation node) {
|
| + Token period = node.period;
|
| + if (period != null && CompletionEngine_this._isCompletionAfter(period.end)) {
|
| + // { x.!y() }
|
| + CompletionEngine_this._dispatchPrefixAnalysis2(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitNamespaceDirective(NamespaceDirective node) {
|
| + StringLiteral uri = node.uri;
|
| + if (uri != null && uri.isSynthetic && node.keyword.end <= CompletionEngine_this._context.selectionOffset) {
|
| + uri.accept(this);
|
| + }
|
| + return super.visitNamespaceDirective(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitPartOfDirective(PartOfDirective node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.ofToken)) {
|
| + CompletionEngine_this._pKeyword(node.ofToken);
|
| + } else {
|
| + visitDirective(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + if (CompletionEngine_this._isCompletionAfter(node.period.end)) {
|
| + if (CompletionEngine_this._isCompletionBefore(node.identifier.offset)) {
|
| + // { x.! } or { x.! y } Note missing/implied semicolon before y; this looks like an
|
| + // obscure case but it occurs frequently when editing existing code.
|
| + CompletionEngine_this._dispatchPrefixAnalysis3(node, node.identifier);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitPropertyAccess(PropertyAccess node) {
|
| + if (node.target != null && node.target.length == 0) {
|
| + return null;
|
| + }
|
| + Expression target = node.realTarget;
|
| + // The "1 + str.!.length" is parsed as "(1 + str).!.length",
|
| + // but actually user wants "1 + (str.!).length".
|
| + // So, if completion inside of period-period ".!." then it is not really a cascade completion.
|
| + Token operator = node.operator;
|
| + if (operator.type == TokenType.PERIOD_PERIOD) {
|
| + int completionLocation = CompletionEngine_this._completionLocation();
|
| + if (completionLocation > operator.offset && completionLocation < operator.end) {
|
| + while (target is BinaryExpression) {
|
| + target = (target as BinaryExpression).rightOperand;
|
| + }
|
| + }
|
| + }
|
| + // do prefixed completion
|
| + CompletionEngine_this._analyzePrefixedAccess(target, node.propertyName);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitReturnStatement(ReturnStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + return null;
|
| + }
|
| + Expression expression = node.expression;
|
| + // return !
|
| + if (expression is SimpleIdentifier) {
|
| + SimpleIdentifier identifier = expression;
|
| + CompletionEngine_this._analyzeLocalName(identifier);
|
| + return null;
|
| + }
|
| + // return expression ! ;
|
| + Token semicolon = node.semicolon;
|
| + if (expression != null && semicolon != null && CompletionEngine_this._isCompletionBetween(expression.end, semicolon.offset)) {
|
| + CompletionEngine_this._operatorAccess(expression, CompletionEngine_this._createIdent(node));
|
| + return null;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + if (node.keyword != null && CompletionEngine_this._isCompletionBefore(node.keyword.end)) {
|
| + // f() { g(var! z) }
|
| + Token token = node.keyword;
|
| + Ident ident = new Ident.con3(node, token);
|
| + CompletionEngine_this._analyzeTypeName(ident, ident);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| + AstNode parent = node.parent;
|
| + if (parent != null) {
|
| + CompletionEngine_IdentifierCompleter visitor = new CompletionEngine_IdentifierCompleter(CompletionEngine_this, node);
|
| + return parent.accept(visitor);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleStringLiteral(SimpleStringLiteral node) {
|
| + AstNode parent = node.parent;
|
| + if (parent is Directive) {
|
| + CompletionEngine_StringCompleter visitor = new CompletionEngine_StringCompleter(CompletionEngine_this, node);
|
| + return parent.accept(visitor);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
| + CompletionEngine_this._analyzeSuperConstructorInvocation(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchMember(SwitchMember node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchStatement(SwitchStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTryStatement(TryStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.tryKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.tryKeyword);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeArgumentList(TypeArgumentList node) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftBracket.end, node.rightBracket.offset)) {
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeParameter(TypeParameter node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + } else if (node.name.name.isEmpty && CompletionEngine_this._isCompletionBefore(node.keyword.offset)) {
|
| + // { < ! extends X> }
|
| + CompletionEngine_this._analyzeTypeName(node.name, CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + // { <! X ! extends ! Y !> }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeParameterList(TypeParameterList node) {
|
| + // { <X extends A,! B,! > }
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftBracket.end, node.rightBracket.offset)) {
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclaration(VariableDeclaration node) {
|
| + if (CompletionEngine_this._isCompletionAfter(node.equals.end)) {
|
| + // { var x =! ...}
|
| + CompletionEngine_this._analyzeLocalName(CompletionEngine_this._createIdent(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclarationList(VariableDeclarationList node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + CompletionEngine_this._analyzeTypeName(new Ident.con3(node, node.keyword), null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitWhileStatement(WhileStatement node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.keyword)) {
|
| + CompletionEngine_this._pKeyword(node.keyword);
|
| + } else if (CompletionEngine_this._isCompletionBetween(node.condition.end, node.rightParenthesis.offset)) {
|
| + CompletionEngine_this._operatorAccess(node.condition, CompletionEngine_this._createIdent(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitWithClause(WithClause node) {
|
| + if (CompletionEngine_this._isCompletingKeyword(node.withKeyword)) {
|
| + CompletionEngine_this._pKeyword(node.withKeyword);
|
| + } else if (node.mixinTypes.isEmpty) {
|
| + // { X with ! }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + } else {
|
| + // { X with ! Y }
|
| + CompletionEngine_this._analyzeTypeName(CompletionEngine_this._createIdent(node), CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A TypeNameCompleter is used to classify the parent of a SimpleIdentifier after it has been
|
| + * identified as a TypeName by the IdentifierCompleter.
|
| + */
|
| +class CompletionEngine_TypeNameCompleter extends CompletionEngine_AstNodeClassifier {
|
| + final CompletionEngine CompletionEngine_this;
|
| +
|
| + final SimpleIdentifier _identifier;
|
| +
|
| + final TypeName _typeName;
|
| +
|
| + CompletionEngine_TypeNameCompleter(this.CompletionEngine_this, this._identifier, this._typeName);
|
| +
|
| + @override
|
| + Object visitAsExpression(AsExpression node) {
|
| + if (identical(node.type, _typeName)) {
|
| + CompletionEngine_this._state._isDynamicAllowed = false;
|
| + CompletionEngine_this._state._isVoidAllowed = false;
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCatchClause(CatchClause node) {
|
| + if (identical(node.exceptionType, _typeName)) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitClassTypeAlias(ClassTypeAlias node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorName(ConstructorName node) {
|
| + if (identical(_typeName, node.type)) {
|
| + if (node.period != null) {
|
| + if (CompletionEngine_this._isCompletionAfter(node.period.end)) {
|
| + // Is this branch reachable? Probably only in IdentifierCompleter.
|
| + "".toString();
|
| + } else {
|
| + // { new Cla!ss.cons() }
|
| + Element element = _identifier.bestElement;
|
| + if (element is ClassElement) {
|
| + CompletionEngine_this._namedConstructorReference(element, _identifier);
|
| + }
|
| + }
|
| + } else {
|
| + // { new ! } { new Na!me(); } { new js!on. }
|
| + CompletionEngine_this._analyzeConstructorTypeName(_identifier);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitExtendsClause(ExtendsClause node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitImplementsClause(ImplementsClause node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitIsExpression(IsExpression node) {
|
| + if (identical(_typeName, node.type)) {
|
| + Token isToken = node.isOperator;
|
| + if (CompletionEngine_this._completionLocation() == isToken.end) {
|
| + Expression expression = node.expression;
|
| + int offset = isToken.offset;
|
| + // { target.is! } possible name completion, parsed as "target.{synthetic} is!"
|
| + if (expression is PrefixedIdentifier) {
|
| + PrefixedIdentifier prefIdent = expression;
|
| + if (prefIdent.identifier.isSynthetic) {
|
| + CompletionEngine_this._analyzePrefixedAccess(prefIdent.prefix, new Ident.con2(node, "is", offset));
|
| + } else {
|
| + CompletionEngine_this._pKeyword(node.isOperator);
|
| + }
|
| + return null;
|
| + }
|
| + // { expr is! }
|
| + if (!CompletionEngine._isSyntheticIdentifier(expression)) {
|
| + CompletionEngine_this._pKeyword(node.isOperator);
|
| + return null;
|
| + }
|
| + // { is! } possible name completion
|
| + CompletionEngine_this._analyzeLocalName(new Ident.con2(node, "is", offset));
|
| + } else {
|
| + CompletionEngine_this._analyzeTypeName(node.type.name as SimpleIdentifier, null);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + if (identical(node.returnType, _typeName)) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeArgumentList(TypeArgumentList node) {
|
| + if (CompletionEngine_this._isCompletionBetween(node.leftBracket.end, node.rightBracket.offset)) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeParameter(TypeParameter node) {
|
| + if (identical(node.bound, _typeName)) {
|
| + // { X<A extends !Y> }
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclarationList(VariableDeclarationList node) {
|
| + if (node.parent is Statement) {
|
| + CompletionEngine_this._analyzeLocalName(_identifier);
|
| + } else {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, null);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitWithClause(WithClause node) {
|
| + CompletionEngine_this._analyzeTypeName(_identifier, CompletionEngine_this._typeDeclarationName(node));
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * The factory class used to create completion proposals.
|
| + */
|
| +class CompletionFactory {
|
| + /**
|
| + * Create a completion proposal of the given kind.
|
| + */
|
| + CompletionProposal createCompletionProposal(ProposalKind kind, int insertionPoint) {
|
| + CompletionProposalImpl prop = new CompletionProposalImpl();
|
| + prop.setKind(kind);
|
| + prop.setLocation(insertionPoint);
|
| + return prop;
|
| + }
|
| +}
|
| +
|
| +abstract class CompletionProposal {
|
| + static final int RELEVANCE_LOW = 0;
|
| +
|
| + static final int RELEVANCE_DEFAULT = 10;
|
| +
|
| + static final int RELEVANCE_HIGH = 20;
|
| +
|
| + /**
|
| + * This character is used to specify location of the cursor after completion.
|
| + */
|
| + static final int CURSOR_MARKER = 0x2758;
|
| +
|
| + void applyPartitionOffset(int partitionOffset);
|
| +
|
| + String get completion;
|
| +
|
| + String get declaringType;
|
| +
|
| + Element get element;
|
| +
|
| + ProposalKind get kind;
|
| +
|
| + int get location;
|
| +
|
| + String get parameterName;
|
| +
|
| + List<String> get parameterNames;
|
| +
|
| + String get parameterType;
|
| +
|
| + List<String> get parameterTypes;
|
| +
|
| + int get positionalParameterCount;
|
| +
|
| + int get relevance;
|
| +
|
| + int get replacementLength;
|
| +
|
| + int get replacementLengthIdentifier;
|
| +
|
| + String get returnType;
|
| +
|
| + bool get hasNamed;
|
| +
|
| + bool get hasPositional;
|
| +
|
| + CompletionProposal incRelevance();
|
| +
|
| + bool get isDeprecated;
|
| +
|
| + bool get isPotentialMatch;
|
| +
|
| + CompletionProposal setCompletion(String x);
|
| +
|
| + CompletionProposal setDeclaringType(String name);
|
| +
|
| + CompletionProposal setDeprecated(bool deprecated);
|
| +
|
| + CompletionProposal setElement(Element element);
|
| +
|
| + CompletionProposal setKind(ProposalKind x);
|
| +
|
| + CompletionProposal setLocation(int x);
|
| +
|
| + CompletionProposal setParameterName(String paramName);
|
| +
|
| + CompletionProposal setParameterNames(List<String> paramNames);
|
| +
|
| + CompletionProposal setParameterStyle(int count, bool named, bool positional);
|
| +
|
| + CompletionProposal setParameterType(String paramType);
|
| +
|
| + CompletionProposal setParameterTypes(List<String> paramTypes);
|
| +
|
| + CompletionProposal setPotentialMatch(bool isPotentialMatch);
|
| +
|
| + CompletionProposal setRelevance(int n);
|
| +
|
| + CompletionProposal setReplacementLength(int x);
|
| +
|
| + CompletionProposal setReplacementLengthIdentifier(int x);
|
| +
|
| + CompletionProposal setReturnType(String name);
|
| +}
|
| +
|
| +class CompletionProposalImpl implements CompletionProposal {
|
| + Element _element;
|
| +
|
| + String _completion = "";
|
| +
|
| + String _returnType = "";
|
| +
|
| + String _declaringType = "";
|
| +
|
| + List<String> _parameterNames = StringUtilities.EMPTY_ARRAY;
|
| +
|
| + List<String> _parameterTypes = StringUtilities.EMPTY_ARRAY;
|
| +
|
| + String _parameterName;
|
| +
|
| + String _parameterType;
|
| +
|
| + ProposalKind _kind = ProposalKind.NONE;
|
| +
|
| + int _location = 0;
|
| +
|
| + int _replacementLength = 0;
|
| +
|
| + int _replacementLength2 = 0;
|
| +
|
| + int _positionalParameterCount = 0;
|
| +
|
| + bool _named = false;
|
| +
|
| + bool _positional = false;
|
| +
|
| + bool _deprecated = false;
|
| +
|
| + bool _potential = false;
|
| +
|
| + int _relevance = CompletionProposal.RELEVANCE_DEFAULT;
|
| +
|
| + @override
|
| + void applyPartitionOffset(int partitionOffset) {
|
| + _location += partitionOffset;
|
| + }
|
| +
|
| + @override
|
| + String get completion => _completion;
|
| +
|
| + @override
|
| + String get declaringType => _declaringType;
|
| +
|
| + @override
|
| + Element get element => _element;
|
| +
|
| + @override
|
| + ProposalKind get kind => _kind;
|
| +
|
| + @override
|
| + int get location => _location;
|
| +
|
| + @override
|
| + String get parameterName => _parameterName;
|
| +
|
| + @override
|
| + List<String> get parameterNames => _parameterNames;
|
| +
|
| + @override
|
| + String get parameterType => _parameterType;
|
| +
|
| + @override
|
| + List<String> get parameterTypes => _parameterTypes;
|
| +
|
| + @override
|
| + int get positionalParameterCount => _positionalParameterCount;
|
| +
|
| + @override
|
| + int get relevance => _relevance;
|
| +
|
| + @override
|
| + int get replacementLength => _replacementLength;
|
| +
|
| + @override
|
| + int get replacementLengthIdentifier => _replacementLength2;
|
| +
|
| + @override
|
| + String get returnType => _returnType;
|
| +
|
| + @override
|
| + bool get hasNamed => _named;
|
| +
|
| + @override
|
| + bool get hasPositional => _positional;
|
| +
|
| + @override
|
| + CompletionProposal incRelevance() {
|
| + _relevance++;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + bool get isDeprecated => _deprecated;
|
| +
|
| + @override
|
| + bool get isPotentialMatch => _potential;
|
| +
|
| + @override
|
| + CompletionProposal setCompletion(String x) {
|
| + _completion = x;
|
| + if (_replacementLength == 0) {
|
| + setReplacementLength(x.length);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setDeclaringType(String name) {
|
| + _declaringType = name;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setDeprecated(bool deprecated) {
|
| + this._deprecated = deprecated;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setElement(Element element) {
|
| + this._element = element;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setKind(ProposalKind x) {
|
| + _kind = x;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setLocation(int x) {
|
| + _location = x;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setParameterName(String parameterName) {
|
| + this._parameterName = parameterName;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setParameterNames(List<String> paramNames) {
|
| + _parameterNames = paramNames;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setParameterStyle(int count, bool named, bool positional) {
|
| + this._named = named;
|
| + this._positional = positional;
|
| + this._positionalParameterCount = count;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setParameterType(String parameterType) {
|
| + this._parameterType = parameterType;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setParameterTypes(List<String> paramTypes) {
|
| + _parameterTypes = paramTypes;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setPotentialMatch(bool isPotentialMatch) {
|
| + _potential = isPotentialMatch;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setRelevance(int n) {
|
| + _relevance = n;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setReplacementLength(int x) {
|
| + _replacementLength = x;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setReplacementLengthIdentifier(int x) {
|
| + _replacementLength2 = x;
|
| + return this;
|
| + }
|
| +
|
| + @override
|
| + CompletionProposal setReturnType(String name) {
|
| + _returnType = name;
|
| + return this;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A pathway for reporting completion proposals back to the client.
|
| + */
|
| +abstract class CompletionRequestor {
|
| + /**
|
| + * Record the given completion proposal for eventual presentation to the user.
|
| + */
|
| + accept(CompletionProposal proposal);
|
| +
|
| + void beginReporting();
|
| +
|
| + void endReporting();
|
| +}
|
| +
|
| +/**
|
| + */
|
| +class CompletionState {
|
| + bool _isForMixin = false;
|
| +
|
| + bool _isVoidAllowed = false;
|
| +
|
| + bool _isDynamicAllowed = false;
|
| +
|
| + bool _isSourceDeclarationStatic = false;
|
| +
|
| + bool _isThisAllowed = true;
|
| +
|
| + bool _isVarAllowed = false;
|
| +
|
| + bool _areLiteralsAllowed = false;
|
| +
|
| + bool _areLiteralsProhibited = false;
|
| +
|
| + bool _areOperatorsAllowed = false;
|
| +
|
| + bool _areStaticReferencesProhibited = false;
|
| +
|
| + bool _areInstanceReferencesProhibited = false;
|
| +
|
| + bool _areUndefinedTypesProhibited = false;
|
| +
|
| + bool _isCompileTimeConstantRequired = false;
|
| +
|
| + bool _isOptionalArgumentRequired = false;
|
| +
|
| + bool _areMethodsProhibited = false;
|
| +
|
| + bool _areClassesRequired = false;
|
| +
|
| + ParameterElement _targetParameter;
|
| +
|
| + void mustBeInstantiableType() {
|
| + _areClassesRequired = true;
|
| + _prohibitsLiterals();
|
| + }
|
| +
|
| + void _includesLiterals() {
|
| + if (!_areLiteralsProhibited) {
|
| + _areLiteralsAllowed = true;
|
| + }
|
| + }
|
| +
|
| + void _includesOperators() {
|
| + _areOperatorsAllowed = true;
|
| + }
|
| +
|
| + void _includesUndefinedDeclarationTypes() {
|
| + if (!_areUndefinedTypesProhibited) {
|
| + _isVoidAllowed = true;
|
| + _isDynamicAllowed = true;
|
| + }
|
| + }
|
| +
|
| + void _includesUndefinedTypes() {
|
| + _isVarAllowed = true;
|
| + _isDynamicAllowed = true;
|
| + }
|
| +
|
| + void _mustBeMixin() {
|
| + _isForMixin = true;
|
| + }
|
| +
|
| + void _prohibitsInstanceReferences() {
|
| + _areInstanceReferencesProhibited = true;
|
| + }
|
| +
|
| + void _prohibitsLiterals() {
|
| + _areLiteralsAllowed = false;
|
| + _areLiteralsProhibited = true;
|
| + }
|
| +
|
| + void _prohibitsStaticReferences() {
|
| + _areStaticReferencesProhibited = true;
|
| + }
|
| +
|
| + void _prohibitThis() {
|
| + _isThisAllowed = false;
|
| + }
|
| +
|
| + void _prohibitsUndefinedTypes() {
|
| + _areUndefinedTypesProhibited = true;
|
| + }
|
| +
|
| + void _requiresConst(bool isConst) {
|
| + _isCompileTimeConstantRequired = isConst;
|
| + }
|
| +
|
| + void _requiresOperators() {
|
| + _includesOperators();
|
| + _areMethodsProhibited = true;
|
| + }
|
| +
|
| + void _requiresOptionalArgument() {
|
| + _isOptionalArgumentRequired = true;
|
| + _prohibitsLiterals();
|
| + }
|
| +
|
| + void set context(AstNode base) {
|
| + base.accept(new ContextAnalyzer(this, base));
|
| + }
|
| +
|
| + void _sourceDeclarationIsStatic(bool state) {
|
| + _isSourceDeclarationStatic = state;
|
| + if (state) {
|
| + if (!_areStaticReferencesProhibited) {
|
| + _prohibitsInstanceReferences();
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + */
|
| +class ContextAnalyzer extends GeneralizingAstVisitor<Object> {
|
| + final CompletionState _state;
|
| +
|
| + final AstNode _completionNode;
|
| +
|
| + AstNode _child;
|
| +
|
| + bool _inExpression = false;
|
| +
|
| + bool _inIdentifier = false;
|
| +
|
| + bool _inTypeName = false;
|
| +
|
| + bool _maybeInvocationArgument = true;
|
| +
|
| + ContextAnalyzer(this._state, this._completionNode);
|
| +
|
| + @override
|
| + Object visitAnnotation(Annotation node) {
|
| + _state._requiresConst(true);
|
| + return super.visitAnnotation(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitCatchClause(CatchClause node) {
|
| + if (identical(node.exceptionType, _child)) {
|
| + _state._prohibitsLiterals();
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitCompilationUnitMember(CompilationUnitMember node) {
|
| + if (node is! ClassDeclaration) {
|
| + _state._prohibitThis();
|
| + }
|
| + return super.visitCompilationUnitMember(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitConstructorInitializer(ConstructorInitializer node) {
|
| + _state._prohibitThis();
|
| + return super.visitConstructorInitializer(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitDirective(Directive node) {
|
| + _state._prohibitsLiterals();
|
| + return super.visitDirective(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitDoStatement(DoStatement node) {
|
| + if (identical(_child, node.condition)) {
|
| + _state._includesLiterals();
|
| + }
|
| + return super.visitDoStatement(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitExpression(Expression node) {
|
| + _inExpression = true;
|
| + _state._includesLiterals();
|
| + _mayBeSetParameterElement(node);
|
| + return super.visitExpression(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitFieldDeclaration(FieldDeclaration node) {
|
| + _state._prohibitThis();
|
| + return super.visitFieldDeclaration(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitForEachStatement(ForEachStatement node) {
|
| + if (identical(_child, node.iterator)) {
|
| + _state._includesLiterals();
|
| + }
|
| + return super.visitForEachStatement(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionExpression(FunctionExpression node) {
|
| + if (node.parent is Declaration) {
|
| + // Function expressions that are part of a declaration are not to be treated as expressions.
|
| + return visitNode(node);
|
| + } else {
|
| + return visitExpression(node);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + if (_inTypeName || node.returnType == null) {
|
| + // This may be an incomplete class type alias
|
| + _state._includesUndefinedDeclarationTypes();
|
| + }
|
| + return super.visitFunctionTypeAlias(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitIdentifier(Identifier node) {
|
| + _mayBeSetParameterElement(node);
|
| + // Identifiers cannot safely be generalized to expressions, so just walk up one level.
|
| + // LibraryIdentifier is never an expression. PrefixedIdentifier may be an expression, but
|
| + // not in a catch-clause or a declaration. SimpleIdentifier may be an expression, but not
|
| + // in a constructor name, label, or where PrefixedIdentifier is not.
|
| + return visitNode(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + _state._requiresConst(node.isConst);
|
| + if (identical(_completionNode.parent.parent, _child)) {
|
| + _state.mustBeInstantiableType();
|
| + }
|
| + return super.visitInstanceCreationExpression(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitMethodDeclaration(MethodDeclaration node) {
|
| + _state._sourceDeclarationIsStatic(node.isStatic);
|
| + if (identical(_child, node.returnType)) {
|
| + _state._includesUndefinedDeclarationTypes();
|
| + }
|
| + if (node.isStatic) {
|
| + _state._prohibitThis();
|
| + }
|
| + return super.visitMethodDeclaration(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitNode(AstNode node) {
|
| + // Walk UP the tree, not down.
|
| + AstNode parent = node.parent;
|
| + _updateIfShouldGetTargetParameter(node, parent);
|
| + if (parent != null) {
|
| + _child = node;
|
| + parent.accept(this);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + if (identical(node, _completionNode) || identical(node.identifier, _completionNode)) {
|
| + SimpleIdentifier prefix = node.prefix;
|
| + if (_isClassLiteral(prefix)) {
|
| + _state._prohibitsInstanceReferences();
|
| + } else {
|
| + _state._prohibitsStaticReferences();
|
| + }
|
| + }
|
| + return super.visitPrefixedIdentifier(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitPropertyAccess(PropertyAccess node) {
|
| + if (identical(node, _completionNode) || identical(node.propertyName, _completionNode)) {
|
| + Expression target = node.realTarget;
|
| + if (_isClassLiteral(target)) {
|
| + _state._prohibitsInstanceReferences();
|
| + } else {
|
| + _state._prohibitsStaticReferences();
|
| + }
|
| + }
|
| + return super.visitPropertyAccess(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + _state._includesUndefinedTypes();
|
| + return super.visitSimpleFormalParameter(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| + _inIdentifier = true;
|
| + return super.visitSimpleIdentifier(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitSwitchStatement(SwitchStatement node) {
|
| + if (identical(_child, node.expression)) {
|
| + _state._includesLiterals();
|
| + }
|
| + return super.visitSwitchStatement(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeArgumentList(TypeArgumentList node) {
|
| + _state._prohibitsUndefinedTypes();
|
| + return super.visitTypeArgumentList(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitTypeName(TypeName node) {
|
| + _inTypeName = true;
|
| + return super.visitTypeName(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclaration(VariableDeclaration node) {
|
| + if (identical(node.name, _completionNode)) {
|
| + _state._prohibitsLiterals();
|
| + }
|
| + return super.visitVariableDeclaration(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitVariableDeclarationList(VariableDeclarationList node) {
|
| + _state._includesUndefinedDeclarationTypes();
|
| + return super.visitVariableDeclarationList(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitWhileStatement(WhileStatement node) {
|
| + if (identical(_child, node.condition)) {
|
| + _state._includesLiterals();
|
| + }
|
| + return super.visitWhileStatement(node);
|
| + }
|
| +
|
| + @override
|
| + Object visitWithClause(WithClause node) {
|
| + _state._mustBeMixin();
|
| + return super.visitWithClause(node);
|
| + }
|
| +
|
| + bool _isClassLiteral(Expression expression) => expression is Identifier && expression.staticElement is ClassElement;
|
| +
|
| + void _mayBeSetParameterElement(Expression node) {
|
| + if (!_maybeInvocationArgument) {
|
| + return;
|
| + }
|
| + if (node.parent is ArgumentList) {
|
| + if (_state._targetParameter == null) {
|
| + _state._targetParameter = node.bestParameterElement;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _updateIfShouldGetTargetParameter(AstNode node, AstNode parent) {
|
| + if (!_maybeInvocationArgument) {
|
| + return;
|
| + }
|
| + // prefix.node
|
| + if (parent is PrefixedIdentifier) {
|
| + if (identical(parent.identifier, node)) {
|
| + return;
|
| + }
|
| + }
|
| + // something unknown
|
| + _maybeInvocationArgument = false;
|
| + }
|
| +}
|
| +
|
| +class Filter {
|
| + String _prefix;
|
| +
|
| + String _originalPrefix;
|
| +
|
| + RegExp _pattern;
|
| +
|
| + Filter.con1(SimpleIdentifier ident, int loc) : this.con2(ident.name, ident.offset, loc);
|
| +
|
| + Filter.con2(String name, int pos, int loc) {
|
| + int len = loc - pos;
|
| + if (len > 0) {
|
| + if (len <= name.length) {
|
| + _prefix = name.substring(0, len);
|
| + } else {
|
| + _prefix = name;
|
| + }
|
| + } else {
|
| + _prefix = "";
|
| + }
|
| + _originalPrefix = _prefix;
|
| + _prefix = _prefix.toLowerCase();
|
| + }
|
| +
|
| + /**
|
| + * @return `true` if the given name starts with the same prefix as used for filter.
|
| + */
|
| + bool _isSameCasePrefix(String name) => name.startsWith(_originalPrefix);
|
| +
|
| + String _makePattern() {
|
| + // TODO(scheglov) translate it
|
| + return null;
|
| + }
|
| +
|
| + bool _match(Element elem) => _match2(elem.displayName);
|
| +
|
| + bool _match2(String name) {
|
| + // Return true if the filter passes.
|
| + if (name.toLowerCase().startsWith(_prefix)) {
|
| + return true;
|
| + }
|
| + return _matchPattern(name);
|
| + }
|
| +
|
| + void _removeNotMatching(List<Element> elements) {
|
| + for (JavaIterator<Element> I = new JavaIterator(elements); I.hasNext;) {
|
| + Element element = I.next();
|
| + if (!_match(element)) {
|
| + I.remove();
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool _matchPattern(String name) {
|
| + // TODO(scheglov) translate it
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +class GeneralizingAstVisitor_CompletionEngine_copyWithout extends GeneralizingAstVisitor<Object> {
|
| + AstNode deletion;
|
| +
|
| + List<FormalParameter> newList;
|
| +
|
| + GeneralizingAstVisitor_CompletionEngine_copyWithout(this.deletion, this.newList) : super();
|
| +
|
| + @override
|
| + Object visitNode(AstNode node) {
|
| + if (!identical(node, deletion)) {
|
| + newList.add(node as FormalParameter);
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An [Ident] is a wrapper for a String that provides type equivalence with SimpleIdentifier.
|
| + */
|
| +class Ident extends EphemeralIdentifier {
|
| + String _name;
|
| +
|
| + Ident.con1(AstNode parent, int offset) : super(parent, offset);
|
| +
|
| + Ident.con2(AstNode parent, String name, int offset) : super(parent, offset) {
|
| + this._name = name;
|
| + }
|
| +
|
| + Ident.con3(AstNode parent, Token name) : super(parent, name.offset) {
|
| + this._name = name.lexeme;
|
| + }
|
| +
|
| + @override
|
| + String get name {
|
| + if (_name != null) {
|
| + return _name;
|
| + }
|
| + String n = super.name;
|
| + if (n != null) {
|
| + return n;
|
| + }
|
| + return "";
|
| + }
|
| +}
|
| +
|
| +class ProposalCollector implements CompletionRequestor {
|
| + final CompletionRequestor requestor;
|
| +
|
| + List<CompletionProposal> _proposals;
|
| +
|
| + ProposalCollector(this.requestor) {
|
| + this._proposals = new List<CompletionProposal>();
|
| + }
|
| +
|
| + @override
|
| + accept(CompletionProposal proposal) {
|
| + _proposals.add(proposal);
|
| + }
|
| +
|
| + @override
|
| + void beginReporting() {
|
| + requestor.beginReporting();
|
| + }
|
| +
|
| + @override
|
| + void endReporting() {
|
| + requestor.endReporting();
|
| + }
|
| +
|
| + List<CompletionProposal> get proposals => _proposals;
|
| +}
|
| +
|
| +/**
|
| + * The various kinds of completion proposals. Each specifies the kind of completion to be created,
|
| + * corresponding to different syntactical elements.
|
| + */
|
| +class ProposalKind extends Enum<ProposalKind> {
|
| + static const ProposalKind NONE = const ProposalKind('NONE', 0);
|
| +
|
| + static const ProposalKind CLASS = const ProposalKind('CLASS', 1);
|
| +
|
| + static const ProposalKind CLASS_ALIAS = const ProposalKind('CLASS_ALIAS', 2);
|
| +
|
| + static const ProposalKind CONSTRUCTOR = const ProposalKind('CONSTRUCTOR', 3);
|
| +
|
| + static const ProposalKind FIELD = const ProposalKind('FIELD', 4);
|
| +
|
| + static const ProposalKind FUNCTION = const ProposalKind('FUNCTION', 5);
|
| +
|
| + static const ProposalKind FUNCTION_ALIAS = const ProposalKind('FUNCTION_ALIAS', 6);
|
| +
|
| + static const ProposalKind GETTER = const ProposalKind('GETTER', 7);
|
| +
|
| + static const ProposalKind IMPORT = const ProposalKind('IMPORT', 8);
|
| +
|
| + static const ProposalKind LIBRARY_PREFIX = const ProposalKind('LIBRARY_PREFIX', 9);
|
| +
|
| + static const ProposalKind METHOD = const ProposalKind('METHOD', 10);
|
| +
|
| + static const ProposalKind METHOD_NAME = const ProposalKind('METHOD_NAME', 11);
|
| +
|
| + static const ProposalKind PARAMETER = const ProposalKind('PARAMETER', 12);
|
| +
|
| + static const ProposalKind SETTER = const ProposalKind('SETTER', 13);
|
| +
|
| + static const ProposalKind VARIABLE = const ProposalKind('VARIABLE', 14);
|
| +
|
| + static const ProposalKind TYPE_PARAMETER = const ProposalKind('TYPE_PARAMETER', 15);
|
| +
|
| + static const ProposalKind ARGUMENT_LIST = const ProposalKind('ARGUMENT_LIST', 16);
|
| +
|
| + static const ProposalKind OPTIONAL_ARGUMENT = const ProposalKind('OPTIONAL_ARGUMENT', 17);
|
| +
|
| + static const ProposalKind NAMED_ARGUMENT = const ProposalKind('NAMED_ARGUMENT', 18);
|
| +
|
| + static const List<ProposalKind> values = const [
|
| + NONE,
|
| + CLASS,
|
| + CLASS_ALIAS,
|
| + CONSTRUCTOR,
|
| + FIELD,
|
| + FUNCTION,
|
| + FUNCTION_ALIAS,
|
| + GETTER,
|
| + IMPORT,
|
| + LIBRARY_PREFIX,
|
| + METHOD,
|
| + METHOD_NAME,
|
| + PARAMETER,
|
| + SETTER,
|
| + VARIABLE,
|
| + TYPE_PARAMETER,
|
| + ARGUMENT_LIST,
|
| + OPTIONAL_ARGUMENT,
|
| + NAMED_ARGUMENT];
|
| +
|
| + const ProposalKind(String name, int ordinal) : super(name, ordinal);
|
| +}
|
| +
|
| +class SearchFilter_CompletionEngine_allSubtypes implements SearchFilter {
|
| + ClassElement classElement;
|
| +
|
| + SearchFilter_CompletionEngine_allSubtypes(this.classElement);
|
| +
|
| + @override
|
| + bool passes(SearchMatch match) {
|
| + Element element = match.element;
|
| + if (element is ClassElement) {
|
| + ClassElement clElem = element;
|
| + while (clElem != null) {
|
| + InterfaceType ifType = clElem.supertype;
|
| + if (ifType == null) {
|
| + return false;
|
| + }
|
| + clElem = ifType.element;
|
| + if (identical(clElem, classElement)) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +class TopLevelNamesKind extends Enum<TopLevelNamesKind> {
|
| + static const TopLevelNamesKind DECLARED_AND_IMPORTS = const TopLevelNamesKind('DECLARED_AND_IMPORTS', 0);
|
| +
|
| + static const TopLevelNamesKind DECLARED_AND_EXPORTS = const TopLevelNamesKind('DECLARED_AND_EXPORTS', 1);
|
| +
|
| + static const List<TopLevelNamesKind> values = const [DECLARED_AND_IMPORTS, DECLARED_AND_EXPORTS];
|
| +
|
| + const TopLevelNamesKind(String name, int ordinal) : super(name, ordinal);
|
| +}
|
|
|