| // 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 "dart:math" as math; |
| |
| import 'package:analysis_server/src/protocol.dart' |
| show CompletionSuggestionKind; |
| 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; |
| |
| DartType result = null; |
| |
| AstNodeClassifier_CompletionEngine_typeOf(this.CompletionEngine_this); |
| |
| @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 = 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, CompletionSuggestionKind.LOCAL_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, CompletionSuggestionKind.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(CompletionSuggestionKind.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(CompletionSuggestionKind.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(CompletionSuggestionKind.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}", CompletionSuggestionKind.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) { |
| CompletionSuggestionKind 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(CompletionSuggestionKind 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) { |
| return elements.where((Element element) { |
| ElementKind kind = element.kind; |
| return kind == ElementKind.FUNCTION |
| || kind == ElementKind.TOP_LEVEL_VARIABLE |
| || kind == ElementKind.GETTER |
| || kind == ElementKind.SETTER; |
| }).toList(); |
| } |
| |
| 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) { |
| return elements.where((Element element) { |
| ElementKind kind = element.kind; |
| return kind == ElementKind.CLASS |
| || kind == ElementKind.FUNCTION_TYPE_ALIAS; |
| }).toList(); |
| } |
| |
| 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 = <ImportElement>[]; |
| for (ImportElement imp in currentLibrary.imports) { |
| PrefixElement prefix = imp.prefix; |
| if (prefix != null) { |
| String impName = prefix.displayName; |
| if (name == impName) { |
| imports.add(imp); |
| } |
| } |
| } |
| return 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(CompletionSuggestionKind.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, CompletionSuggestionKind.LOCAL_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, CompletionSuggestionKind.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(CompletionSuggestionKind.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, CompletionSuggestionKind.LOCAL_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, CompletionSuggestionKind.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(CompletionSuggestionKind.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, CompletionSuggestionKind 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, CompletionSuggestionKind 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, CompletionSuggestionKind.LOCAL_VARIABLE); |
| } |
| |
| void _pParamName(String name) { |
| if (_filterDisallows2(name)) { |
| return; |
| } |
| CompletionProposal prop = _createProposal4(CompletionSuggestionKind.PARAMETER); |
| prop.setCompletion(name); |
| _requestor.accept(prop); |
| } |
| |
| CompletionSuggestionKind _proposalKindOf(Element element) { |
| CompletionSuggestionKind kind; |
| while (true) { |
| if (element.kind == ElementKind.CONSTRUCTOR) { |
| kind = CompletionSuggestionKind.CONSTRUCTOR; |
| } else if (element.kind == ElementKind.FUNCTION) { |
| kind = CompletionSuggestionKind.FUNCTION; |
| } else if (element.kind == ElementKind.METHOD) { |
| kind = CompletionSuggestionKind.METHOD; |
| } else if (element.kind == ElementKind.GETTER) { |
| kind = CompletionSuggestionKind.GETTER; |
| } else if (element.kind == ElementKind.SETTER) { |
| kind = CompletionSuggestionKind.SETTER; |
| } else if (element.kind == ElementKind.CLASS) { |
| kind = CompletionSuggestionKind.CLASS; |
| } else if (element.kind == ElementKind.FIELD) { |
| kind = CompletionSuggestionKind.FIELD; |
| } else if (element.kind == ElementKind.IMPORT) { |
| kind = CompletionSuggestionKind.IMPORT; |
| } else if (element.kind == ElementKind.PARAMETER) { |
| kind = CompletionSuggestionKind.PARAMETER; |
| } else if (element.kind == ElementKind.PREFIX) { |
| kind = CompletionSuggestionKind.LIBRARY_PREFIX; |
| } else if (element.kind == ElementKind.FUNCTION_TYPE_ALIAS) { |
| kind = CompletionSuggestionKind.CLASS_ALIAS; |
| } else if (element.kind == ElementKind.TYPE_PARAMETER) { |
| kind = CompletionSuggestionKind.TYPE_PARAMETER; |
| } else if (element.kind == ElementKind.LOCAL_VARIABLE || element.kind == ElementKind.TOP_LEVEL_VARIABLE) { |
| kind = CompletionSuggestionKind.LOCAL_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 == CompletionSuggestionKind.FUNCTION) { |
| proposal.setKind(CompletionSuggestionKind.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, CompletionSuggestionKind.LOCAL_VARIABLE); |
| } |
| |
| void _pVar() { |
| _pWord(_C_VAR, CompletionSuggestionKind.LOCAL_VARIABLE); |
| } |
| |
| void _pVoid() { |
| _pWord(_C_VOID, CompletionSuggestionKind.LOCAL_VARIABLE); |
| } |
| |
| void _pWord(String word, CompletionSuggestionKind 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(params); |
| prop.setParameterTypes(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) { |
| AstNodeClassifier_CompletionEngine_typeOf visitor |
| = new AstNodeClassifier_CompletionEngine_typeOf(this); |
| expr.accept(visitor); |
| DartType result = visitor.result; |
| if (result != null) { |
| return result; |
| } |
| } |
| 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(CompletionSuggestionKind.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, CompletionSuggestionKind.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.insert(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(CompletionSuggestionKind 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; |
| |
| CompletionSuggestionKind 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(CompletionSuggestionKind 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; |
| |
| CompletionSuggestionKind _kind = null; |
| |
| 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 |
| CompletionSuggestionKind 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(CompletionSuggestionKind 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 (int i = elements.length - 1; i >= 0; i--) { |
| if (!_match(elements[i])) { |
| elements.removeAt(i); |
| } |
| } |
| } |
| |
| 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; |
| } |
| |
| 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); |
| } |