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

Unified Diff: pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart

Issue 2927663002: Port two completion contributors for use by plugins (Closed)
Patch Set: Created 3 years, 6 months 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/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
new file mode 100644
index 0000000000000000000000000000000000000000..24726965fe8d048702db386eee7086fdab13d7d2
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart'
+ hide Element, ElementKind;
+import 'package:analyzer_plugin/src/utilities/documentation.dart';
+import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
+import 'package:analyzer_plugin/utilities/completion/relevance.dart';
+import 'package:analyzer_plugin/utilities/completion/suggestion_builder.dart';
+import 'package:front_end/src/base/source.dart' show Source;
+import 'package:front_end/src/base/uri_kind.dart';
+
+/**
+ * An object used to build code completion suggestions for Dart code.
+ */
+class SuggestionBuilderImpl implements SuggestionBuilder {
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider resourceProvider;
+
+ /**
+ * The converter used to convert analyzer objects to protocol objects.
+ */
+ final AnalyzerConverter converter = new AnalyzerConverter();
+
+ /**
+ * Initialize a newly created suggestion builder.
+ */
+ SuggestionBuilderImpl(this.resourceProvider);
+
+ /**
+ * Add default argument list text and ranges based on the given [requiredParams]
+ * and [namedParams].
+ */
+ void addDefaultArgDetails(
+ CompletionSuggestion suggestion,
+ Element element,
+ Iterable<ParameterElement> requiredParams,
+ Iterable<ParameterElement> namedParams) {
+ // Copied from analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+ StringBuffer buffer = new StringBuffer();
+ List<int> ranges = <int>[];
+
+ int offset;
+
+ for (ParameterElement param in requiredParams) {
+ if (buffer.isNotEmpty) {
+ buffer.write(', ');
+ }
+ offset = buffer.length;
+ String name = param.name;
+ buffer.write(name);
+ ranges.addAll([offset, name.length]);
+ }
+
+ for (ParameterElement param in namedParams) {
+ if (param.isRequired) {
+ if (buffer.isNotEmpty) {
+ buffer.write(', ');
+ }
+ String name = param.name;
+ buffer.write('$name: ');
+ offset = buffer.length;
+ String defaultValue = 'null'; // originally _getDefaultValue(param)
+ buffer.write(defaultValue);
+ ranges.addAll([offset, defaultValue.length]);
+ }
+ }
+
+ suggestion.defaultArgumentListString =
+ buffer.isNotEmpty ? buffer.toString() : null;
+ suggestion.defaultArgumentListTextRanges =
+ ranges.isNotEmpty ? ranges : null;
+ }
+
+ @override
+ CompletionSuggestion forElement(Element element,
+ {String completion,
+ CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+ int relevance: DART_RELEVANCE_DEFAULT,
+ Source importForSource}) {
+ // Copied from analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+ if (element == null) {
+ return null;
+ }
+ if (element is ExecutableElement && element.isOperator) {
+ // Do not include operators in suggestions
+ return null;
+ }
+ if (completion == null) {
+ completion = element.displayName;
+ }
+ bool isDeprecated = element.isDeprecated;
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ kind,
+ isDeprecated ? DART_RELEVANCE_LOW : relevance,
+ completion,
+ completion.length,
+ 0,
+ isDeprecated,
+ false);
+
+ // Attach docs.
+ String doc = removeDartDocDelimiters(element.documentationComment);
+ suggestion.docComplete = doc;
+ suggestion.docSummary = getDartDocSummary(doc);
+
+ suggestion.element = converter.convertElement(element);
+ Element enclosingElement = element.enclosingElement;
+ if (enclosingElement is ClassElement) {
+ suggestion.declaringType = enclosingElement.displayName;
+ }
+ suggestion.returnType = getReturnTypeString(element);
+ if (element is ExecutableElement && element is! PropertyAccessorElement) {
+ suggestion.parameterNames = element.parameters
+ .map((ParameterElement parameter) => parameter.name)
+ .toList();
+ suggestion.parameterTypes =
+ element.parameters.map((ParameterElement parameter) {
+ DartType paramType = parameter.type;
+ // Gracefully degrade if type not resolved yet
+ return paramType != null ? paramType.displayName : 'var';
+ }).toList();
+
+ Iterable<ParameterElement> requiredParameters = element.parameters.where(
+ (ParameterElement param) =>
+ param.parameterKind == ParameterKind.REQUIRED);
+ suggestion.requiredParameterCount = requiredParameters.length;
+
+ Iterable<ParameterElement> namedParameters = element.parameters.where(
+ (ParameterElement param) =>
+ param.parameterKind == ParameterKind.NAMED);
+ suggestion.hasNamedParameters = namedParameters.isNotEmpty;
+
+ addDefaultArgDetails(
+ suggestion, element, requiredParameters, namedParameters);
+ }
+ if (importForSource != null) {
+ String srcPath =
+ resourceProvider.pathContext.dirname(importForSource.fullName);
+ LibraryElement libElem = element.library;
+ if (libElem != null) {
+ Source libSource = libElem.source;
+ if (libSource != null) {
+ UriKind uriKind = libSource.uriKind;
+ if (uriKind == UriKind.DART_URI) {
+ suggestion.importUri = libSource.uri.toString();
+ } else if (uriKind == UriKind.PACKAGE_URI) {
+ suggestion.importUri = libSource.uri.toString();
+ } else if (uriKind == UriKind.FILE_URI &&
+ element.source.uriKind == UriKind.FILE_URI) {
+ try {
+ suggestion.importUri = resourceProvider.pathContext
+ .relative(libSource.fullName, from: srcPath);
+ } catch (_) {
+ // ignored
+ }
+ }
+ }
+ }
+ if (suggestion.importUri == null) {
+ // Do not include out of scope suggestions
+ // for which we cannot determine an import
+ return null;
+ }
+ }
+ return suggestion;
+ }
+
+ String getReturnTypeString(Element element) {
+ // Copied from analysis_server/lib/src/protocol_server.dart
+ if (element is ExecutableElement) {
+ if (element.kind == ElementKind.SETTER) {
+ return null;
+ } else {
+ return element.returnType?.toString();
+ }
+ } else if (element is VariableElement) {
+ DartType type = element.type;
+ return type != null ? type.displayName : 'dynamic';
+ } else if (element is FunctionTypeAliasElement) {
+ return element.returnType.toString();
+ } else {
+ return null;
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698