Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1924)

Unified Diff: pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart

Issue 1500793003: rework ArgListContributor to use new task model (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: merge Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b4a6aed91064c16b618fa547f893038d3426ee02
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -0,0 +1,244 @@
+// 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.
+
+library services.completion.contributor.dart.arglist;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Determine the number of arguments.
+ */
+int _argCount(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ return node.arguments.length;
+ }
+ return 0;
+}
+
+String _getParamType(ParameterElement param) {
+ DartType type = param.type;
+ if (type != null) {
+ return type.displayName;
+ }
+ return 'dynamic';
+}
+
+/**
+ * If the containing [node] is an argument list
+ * or named expression in an argument list
+ * then return the simple identifier for the method, constructor, or annotation
+ * to which the argument list is associated
+ */
+SimpleIdentifier _getTargetId(AstNode node) {
+ if (node is NamedExpression) {
+ return _getTargetId(node.parent);
+ }
+ if (node is ArgumentList) {
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation) {
+ return parent.methodName;
+ }
+ if (parent is InstanceCreationExpression) {
+ ConstructorName constructorName = parent.constructorName;
+ if (constructorName != null) {
+ if (constructorName.name != null) {
+ return constructorName.name;
+ }
+ Identifier typeName = constructorName.type.name;
+ if (typeName is SimpleIdentifier) {
+ return typeName;
+ }
+ if (typeName is PrefixedIdentifier) {
+ return typeName.identifier;
+ }
+ }
+ }
+ if (parent is Annotation) {
+ return parent.constructorName ?? parent.name;
+ }
+ }
+ return null;
+}
+
+/**
+ * Determine if the completion target is at the end of the list of arguments.
+ */
+bool _isAppendingToArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ var entity = request.target.entity;
+ if (entity == node.rightParenthesis) {
+ return true;
+ }
+ if (node.arguments.length > 0 && node.arguments.last == entity) {
+ return entity is SimpleIdentifier;
+ }
+ }
+ return false;
+}
+
+/**
+ * Determine if the completion target is an emtpy argument list.
+ */
+bool _isEmptyArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ return node is ArgumentList &&
+ node.leftParenthesis.next == node.rightParenthesis;
+}
+
+/**
+ * Return a collection of currently specified named arguments
+ */
+Iterable<String> _namedArgs(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ List<String> namedArgs = new List<String>();
+ if (node is ArgumentList) {
+ for (Expression arg in node.arguments) {
+ if (arg is NamedExpression) {
+ namedArgs.add(arg.name.label.name);
+ }
+ }
+ }
+ return namedArgs;
+}
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * when the cursor position is inside the arguments to a method call.
+ */
+class ArgListContributor extends DartCompletionContributor {
+ DartCompletionRequest request;
+ List<CompletionSuggestion> suggestions;
+
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ this.request = request;
+ this.suggestions = <CompletionSuggestion>[];
+
+ // Determine if the target is in an argument list
+ // for a method or a constructor or an annotation
+ // and resolve the identifier
+ SimpleIdentifier targetId = _getTargetId(request.target.containingNode);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the target expression to determine the arguments
+ await request.resolveIdentifier(targetId);
+ // Gracefully degrade if the element could not be resolved
+ // e.g. target changed, completion aborted
+ targetId = _getTargetId(request.target.containingNode);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+ Element elem = targetId.bestElement;
+ if (elem == null) {
+ return EMPTY_LIST;
+ }
+
+ // Generate argument list suggestion based upon the type of element
+ if (elem is ClassElement) {
+ for (ConstructorElement constructor in elem.constructors) {
+ if (!constructor.isFactory) {
+ _addSuggestions(constructor.parameters);
+ return suggestions;
+ }
+ }
+ }
+ if (elem is ConstructorElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+ if (elem is FunctionElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+ if (elem is MethodElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+
+ print('${elem.runtimeType} :: $elem');
+ return EMPTY_LIST;
+ }
+
+ void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
+ StringBuffer completion = new StringBuffer('(');
+ List<String> paramNames = new List<String>();
+ List<String> paramTypes = new List<String>();
+ for (ParameterElement param in requiredParam) {
+ String name = param.name;
+ if (name != null && name.length > 0) {
+ if (completion.length > 1) {
+ completion.write(', ');
+ }
+ completion.write(name);
+ paramNames.add(name);
+ paramTypes.add(_getParamType(param));
+ }
+ }
+ completion.write(')');
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.ARGUMENT_LIST,
+ DART_RELEVANCE_HIGH,
+ completion.toString(),
+ completion.length,
+ 0,
+ false,
+ false);
+ suggestion.parameterNames = paramNames;
+ suggestion.parameterTypes = paramTypes;
+ suggestions.add(suggestion);
+ }
+
+ void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
+ Iterable<String> namedArgs = _namedArgs(request);
+ for (ParameterElement param in parameters) {
+ if (param.parameterKind == ParameterKind.NAMED) {
+ _addNamedParameterSuggestion(request, namedArgs, param.name);
+ }
+ }
+ }
+
+ void _addNamedParameterSuggestion(
+ DartCompletionRequest request, List<String> namedArgs, String name) {
+ if (name != null && name.length > 0 && !namedArgs.contains(name)) {
+ suggestions.add(new CompletionSuggestion(
+ CompletionSuggestionKind.NAMED_ARGUMENT,
+ DART_RELEVANCE_NAMED_PARAMETER,
+ '$name: ',
+ name.length + 2,
+ 0,
+ false,
+ false));
+ }
+ }
+
+ void _addSuggestions(Iterable<ParameterElement> parameters) {
+ if (parameters == null || parameters.length == 0) {
+ return;
+ }
+ Iterable<ParameterElement> requiredParam = parameters.where(
+ (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
+ int requiredCount = requiredParam.length;
+ if (requiredCount > 0 && _isEmptyArgList(request)) {
+ _addArgListSuggestion(requiredParam);
+ return;
+ }
+ if (_isAppendingToArgList(request)) {
+ if (requiredCount == 0 || requiredCount < _argCount(request)) {
+ _addDefaultParamSuggestions(parameters);
+ }
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698