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

Unified Diff: pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart

Issue 2873503007: Add support for converting elements to plugin API objects (Closed)
Patch Set: Created 3 years, 7 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
« no previous file with comments | « no previous file | pkg/analyzer_plugin/test/support/abstract_context.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
diff --git a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
index 37b9dff61342765ee0e4a640486e2f17733b9498..b402ec76be9e262174057ac536c374bd3e06e8d0 100644
--- a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
+++ b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
@@ -2,10 +2,14 @@
// 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' as analyzer;
+import 'package:analyzer/dart/element/type.dart' as analyzer;
import 'package:analyzer/error/error.dart' as analyzer;
+import 'package:analyzer/exception/exception.dart' as analyzer;
import 'package:analyzer/source/error_processor.dart' as analyzer;
import 'package:analyzer/src/generated/engine.dart' as analyzer;
import 'package:analyzer/src/generated/source.dart' as analyzer;
+import 'package:analyzer/src/generated/utilities_dart.dart' as analyzer;
import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -78,6 +82,73 @@ class AnalyzerConverter {
}
/**
+ * Convert the given [element] from the 'analyzer' package to an element
+ * defined by the plugin API.
+ */
+ plugin.Element convertElement(analyzer.Element element) {
+ plugin.ElementKind kind = _convertElementToElementKind(element);
+ return new plugin.Element(
+ kind,
+ element.displayName,
+ plugin.Element.makeFlags(
+ isPrivate: element.isPrivate,
+ isDeprecated: element.isDeprecated,
+ isAbstract: _isAbstract(element),
+ isConst: _isConst(element),
+ isFinal: _isFinal(element),
+ isStatic: _isStatic(element)),
+ location: _locationFromElement(element),
+ typeParameters: _getTypeParametersString(element),
+ parameters: _getParametersString(element),
+ returnType: _getReturnTypeString(element));
+ }
+
+ /**
+ * Convert the element [kind] from the 'analyzer' package to an element kind
+ * defined by the plugin API.
+ *
+ * This method does not take into account that an instance of [ClassElement]
+ * can be an enum and an instance of [FieldElement] can be an enum constant.
+ * Use [_convertElementToElementKind] where possible.
+ */
+ plugin.ElementKind convertElementKind(analyzer.ElementKind kind) {
+ if (kind == analyzer.ElementKind.CLASS) {
+ return plugin.ElementKind.CLASS;
+ } else if (kind == analyzer.ElementKind.COMPILATION_UNIT) {
+ return plugin.ElementKind.COMPILATION_UNIT;
+ } else if (kind == analyzer.ElementKind.CONSTRUCTOR) {
+ return plugin.ElementKind.CONSTRUCTOR;
+ } else if (kind == analyzer.ElementKind.FIELD) {
+ return plugin.ElementKind.FIELD;
+ } else if (kind == analyzer.ElementKind.FUNCTION) {
+ return plugin.ElementKind.FUNCTION;
+ } else if (kind == analyzer.ElementKind.FUNCTION_TYPE_ALIAS) {
+ return plugin.ElementKind.FUNCTION_TYPE_ALIAS;
+ } else if (kind == analyzer.ElementKind.GETTER) {
+ return plugin.ElementKind.GETTER;
+ } else if (kind == analyzer.ElementKind.LABEL) {
+ return plugin.ElementKind.LABEL;
+ } else if (kind == analyzer.ElementKind.LIBRARY) {
+ return plugin.ElementKind.LIBRARY;
+ } else if (kind == analyzer.ElementKind.LOCAL_VARIABLE) {
+ return plugin.ElementKind.LOCAL_VARIABLE;
+ } else if (kind == analyzer.ElementKind.METHOD) {
+ return plugin.ElementKind.METHOD;
+ } else if (kind == analyzer.ElementKind.PARAMETER) {
+ return plugin.ElementKind.PARAMETER;
+ } else if (kind == analyzer.ElementKind.PREFIX) {
+ return plugin.ElementKind.PREFIX;
+ } else if (kind == analyzer.ElementKind.SETTER) {
+ return plugin.ElementKind.SETTER;
+ } else if (kind == analyzer.ElementKind.TOP_LEVEL_VARIABLE) {
+ return plugin.ElementKind.TOP_LEVEL_VARIABLE;
+ } else if (kind == analyzer.ElementKind.TYPE_PARAMETER) {
+ return plugin.ElementKind.TYPE_PARAMETER;
+ }
+ return plugin.ElementKind.UNKNOWN;
+ }
+
+ /**
* Convert the error [severity] from the 'analyzer' package to an analysis
* error severity defined by the plugin API.
*/
@@ -91,4 +162,211 @@ class AnalyzerConverter {
*/
plugin.AnalysisErrorType convertErrorType(analyzer.ErrorType type) =>
new plugin.AnalysisErrorType(type.name);
+
+ /**
+ * Convert the element kind of the [element] from the 'analyzer' package to an
+ * element kind defined by the plugin API.
+ */
+ plugin.ElementKind _convertElementToElementKind(analyzer.Element element) {
+ if (element is analyzer.ClassElement && element.isEnum) {
+ return plugin.ElementKind.ENUM;
+ } else if (element is analyzer.FieldElement &&
+ element.isEnumConstant &&
+ // MyEnum.values and MyEnum.one.index return isEnumConstant = true
+ // so these additional checks are necessary.
+ // TODO(danrubel) MyEnum.values is constant, but is a list
+ // so should it return isEnumConstant = true?
+ // MyEnum.one.index is final but *not* constant
+ // so should it return isEnumConstant = true?
+ // Or should we return ElementKind.ENUM_CONSTANT here
+ // in either or both of these cases?
+ element.type != null &&
+ element.type.element == element.enclosingElement) {
+ return plugin.ElementKind.ENUM_CONSTANT;
+ }
+ return convertElementKind(element.kind);
+ }
+
+ /**
+ * Return a textual representation of the parameters of the given [element],
+ * or `null` if the element does not have any parameters.
+ */
+ String _getParametersString(analyzer.Element element) {
+ // TODO(scheglov) expose the corresponding feature from ExecutableElement
+ List<analyzer.ParameterElement> parameters;
+ if (element is analyzer.ExecutableElement) {
+ // valid getters don't have parameters
+ if (element.kind == analyzer.ElementKind.GETTER &&
+ element.parameters.isEmpty) {
+ return null;
+ }
+ parameters = element.parameters;
+ } else if (element is analyzer.FunctionTypeAliasElement) {
+ parameters = element.parameters;
+ } else {
+ return null;
+ }
+ StringBuffer buffer = new StringBuffer();
+ String closeOptionalString = '';
+ buffer.write('(');
+ for (int i = 0; i < parameters.length; i++) {
+ analyzer.ParameterElement parameter = parameters[i];
+ if (i > 0) {
+ buffer.write(', ');
+ }
+ if (closeOptionalString.isEmpty) {
+ analyzer.ParameterKind kind = parameter.parameterKind;
+ if (kind == analyzer.ParameterKind.NAMED) {
+ buffer.write('{');
+ closeOptionalString = '}';
+ }
+ if (kind == analyzer.ParameterKind.POSITIONAL) {
+ buffer.write('[');
+ closeOptionalString = ']';
+ }
+ }
+ parameter.appendToWithoutDelimiters(buffer);
+ }
+ buffer.write(closeOptionalString);
+ buffer.write(')');
+ return buffer.toString();
+ }
+
+ /**
+ * Return a textual representation of the return type of the given [element],
+ * or `null` if the element does not have a return type.
+ */
+ String _getReturnTypeString(analyzer.Element element) {
+ if (element is analyzer.ExecutableElement) {
+ if (element.kind == analyzer.ElementKind.SETTER) {
+ return null;
+ }
+ return element.returnType?.toString();
+ } else if (element is analyzer.VariableElement) {
+ analyzer.DartType type = element.type;
+ return type != null ? type.displayName : 'dynamic';
+ } else if (element is analyzer.FunctionTypeAliasElement) {
+ return element.returnType.toString();
+ }
+ return null;
+ }
+
+ /**
+ * Return a textual representation of the type parameters of the given
+ * [element], or `null` if the element does not have type parameters.
+ */
+ String _getTypeParametersString(analyzer.Element element) {
+ if (element is analyzer.TypeParameterizedElement) {
+ List<analyzer.TypeParameterElement> typeParameters =
+ element.typeParameters;
+ if (typeParameters == null || typeParameters.isEmpty) {
+ return null;
+ }
+ return '<${typeParameters.join(', ')}>';
+ }
+ return null;
+ }
+
+ /**
+ * Return the compilation unit containing the given [element].
+ */
+ analyzer.CompilationUnitElement _getUnitElement(analyzer.Element element) {
+ if (element is analyzer.CompilationUnitElement) {
+ return element;
+ }
+ if (element?.enclosingElement is analyzer.LibraryElement) {
+ element = element.enclosingElement;
+ }
+ if (element is analyzer.LibraryElement) {
+ return element.definingCompilationUnit;
+ }
+ for (; element != null; element = element.enclosingElement) {
+ if (element is analyzer.CompilationUnitElement) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ bool _isAbstract(analyzer.Element element) {
+ // TODO(scheglov) add isAbstract to Element API
+ if (element is analyzer.ClassElement) {
+ return element.isAbstract;
+ } else if (element is analyzer.MethodElement) {
+ return element.isAbstract;
+ } else if (element is analyzer.PropertyAccessorElement) {
+ return element.isAbstract;
+ }
+ return false;
+ }
+
+ bool _isConst(analyzer.Element element) {
+ // TODO(scheglov) add isConst to Element API
+ if (element is analyzer.ConstructorElement) {
+ return element.isConst;
+ } else if (element is analyzer.VariableElement) {
+ return element.isConst;
+ }
+ return false;
+ }
+
+ bool _isFinal(analyzer.Element element) {
+ // TODO(scheglov) add isFinal to Element API
+ if (element is analyzer.VariableElement) {
+ return element.isFinal;
+ }
+ return false;
+ }
+
+ bool _isStatic(analyzer.Element element) {
+ // TODO(scheglov) add isStatic to Element API
+ if (element is analyzer.ExecutableElement) {
+ return element.isStatic;
+ } else if (element is analyzer.PropertyInducingElement) {
+ return element.isStatic;
+ }
+ return false;
+ }
+
+ /**
+ * Create and return a location within the given [unitElement] at the given
+ * [range].
+ */
+ plugin.Location _locationForArgs(
+ analyzer.CompilationUnitElement unitElement, analyzer.SourceRange range) {
+ int startLine = 0;
+ int startColumn = 0;
+ try {
+ analyzer.LineInfo lineInfo = unitElement.lineInfo;
+ if (lineInfo != null) {
+ analyzer.LineInfo_Location offsetLocation =
+ lineInfo.getLocation(range.offset);
+ startLine = offsetLocation.lineNumber;
+ startColumn = offsetLocation.columnNumber;
+ }
+ } on analyzer.AnalysisException {
+ // Ignore exceptions
+ }
+ return new plugin.Location(unitElement.source.fullName, range.offset,
+ range.length, startLine, startColumn);
+ }
+
+ /**
+ * Create a location based on an the given [element].
+ */
+ plugin.Location _locationFromElement(analyzer.Element element) {
+ if (element == null || element.source == null) {
+ return null;
+ }
+ int offset = element.nameOffset;
+ int length = element.nameLength;
+ if (element is analyzer.CompilationUnitElement ||
+ (element is analyzer.LibraryElement && offset < 0)) {
+ offset = 0;
+ length = 0;
+ }
+ analyzer.CompilationUnitElement unitElement = _getUnitElement(element);
+ analyzer.SourceRange range = new analyzer.SourceRange(offset, length);
+ return _locationForArgs(unitElement, range);
+ }
}
« no previous file with comments | « no previous file | pkg/analyzer_plugin/test/support/abstract_context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698