| 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);
|
| + }
|
| }
|
|
|