// 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. /// Utilities for converting Dart entities into analysis server's protocol /// entities. library; import 'package:analysis_server/src/protocol_server.dart'; import 'package:analyzer/dart/element/element.dart' as engine; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/source/file_source.dart'; import 'package:analyzer/src/dart/element/element.dart'; Element convertElement(engine.Element element) { var kind = convertElementToElementKind(element); var name = getElementDisplayName(element); var elementTypeParameters = _getTypeParametersString(element); var aliasedType = getAliasedTypeString(element); var elementParameters = getParametersString(element); var elementReturnType = getReturnTypeString(element); var extendedType = getExtendedTypeString(element); return Element( kind, name, Element.makeFlags( isPrivate: element.isPrivate, isDeprecated: element.isDeprecatedWithKind('use'), isAbstract: _isAbstract(element), isConst: _isConst(element), isFinal: _isFinal(element), isStatic: _isStatic(element), ), location: newLocation_fromElement(element), typeParameters: elementTypeParameters, aliasedType: aliasedType, parameters: elementParameters, returnType: elementReturnType, extendedType: extendedType, ); } /// Return a protocol [ElementKind] corresponding to the given /// [engine.ElementKind]. /// /// This does not take into account that an instance of [engine.ClassElement] /// can be an enum and an instance of [engine.FieldElement] can be an enum /// constant. Use [convertElementToElementKind] where possible. ElementKind convertElementKind(engine.ElementKind kind) { if (kind == engine.ElementKind.CLASS) { return ElementKind.CLASS; } if (kind == engine.ElementKind.COMPILATION_UNIT) { return ElementKind.COMPILATION_UNIT; } if (kind == engine.ElementKind.CONSTRUCTOR) { return ElementKind.CONSTRUCTOR; } if (kind == engine.ElementKind.ENUM) { return ElementKind.ENUM; } if (kind == engine.ElementKind.EXTENSION) { return ElementKind.EXTENSION; } if (kind == engine.ElementKind.EXTENSION_TYPE) { return ElementKind.EXTENSION_TYPE; } if (kind == engine.ElementKind.FIELD) { return ElementKind.FIELD; } if (kind == engine.ElementKind.FUNCTION) { return ElementKind.FUNCTION; } if (kind == engine.ElementKind.FUNCTION_TYPE_ALIAS) { return ElementKind.FUNCTION_TYPE_ALIAS; } if (kind == engine.ElementKind.GENERIC_FUNCTION_TYPE) { return ElementKind.FUNCTION_TYPE_ALIAS; } if (kind == engine.ElementKind.GETTER) { return ElementKind.GETTER; } if (kind == engine.ElementKind.LABEL) { return ElementKind.LABEL; } if (kind == engine.ElementKind.LIBRARY) { return ElementKind.LIBRARY; } if (kind == engine.ElementKind.LOCAL_VARIABLE) { return ElementKind.LOCAL_VARIABLE; } if (kind == engine.ElementKind.METHOD) { return ElementKind.METHOD; } if (kind == engine.ElementKind.MIXIN) { return ElementKind.MIXIN; } if (kind == engine.ElementKind.PARAMETER) { return ElementKind.PARAMETER; } if (kind == engine.ElementKind.PART) { return ElementKind.COMPILATION_UNIT; } if (kind == engine.ElementKind.PREFIX) { return ElementKind.PREFIX; } if (kind == engine.ElementKind.SETTER) { return ElementKind.SETTER; } if (kind == engine.ElementKind.TOP_LEVEL_VARIABLE) { return ElementKind.TOP_LEVEL_VARIABLE; } if (kind == engine.ElementKind.TYPE_ALIAS) { return ElementKind.TYPE_ALIAS; } if (kind == engine.ElementKind.TYPE_PARAMETER) { return ElementKind.TYPE_PARAMETER; } return ElementKind.UNKNOWN; } /// Return an [ElementKind] corresponding to the given [engine.Element]. ElementKind convertElementToElementKind(engine.Element element) { if (element is engine.EnumElement) { return ElementKind.ENUM; } else if (element is engine.MixinElement) { return ElementKind.MIXIN; } if (element is engine.FieldElement && element.isEnumConstant) { return ElementKind.ENUM_CONSTANT; } return convertElementKind(element.kind); } Element convertLibraryFragment(LibraryFragmentImpl fragment) { return Element( ElementKind.COMPILATION_UNIT, (fragment.source as FileSource).file.shortName, Element.makeFlags( isPrivate: fragment.isPrivate, isDeprecated: fragment.library.isDeprecatedWithKind('use'), ), location: newLocation_fromFragment(fragment), ); } String getElementDisplayName(engine.Element element) { if (element is engine.LibraryFragment) { var fragment = element as engine.LibraryFragment; return (fragment.source as FileSource).file.shortName; } else { return element.displayName; } } String getParametersListString(List parameters) { parameters.sort(_preferRequiredParams); var sb = StringBuffer(); var closeOptionalString = ''; for (var parameter in parameters) { if (sb.isNotEmpty) { sb.write(', '); } if (closeOptionalString.isEmpty) { if (parameter.isNamed) { sb.write('{'); closeOptionalString = '}'; } else if (parameter.isOptionalPositional) { sb.write('['); closeOptionalString = ']'; } } if (parameter.isRequiredNamed) { sb.write('required '); } else if (parameter.metadata.hasDeprecated) { sb.write('@required '); } parameter.appendToWithoutDelimiters(sb); } sb.write(closeOptionalString); return '($sb)'; } String? getParametersString(engine.Element element) { // TODO(scheglov): expose the corresponding feature from ExecutableElement List parameters; if (element is engine.ExecutableElement) { // valid getters don't have parameters if (element.kind == engine.ElementKind.GETTER && element.formalParameters.isEmpty) { return null; } parameters = element.formalParameters.toList(); } else if (element is engine.TypeAliasElement) { var aliasedType = element.aliasedType; if (aliasedType is FunctionType) { parameters = aliasedType.formalParameters.toList(); } else { return null; } } else { return null; } return getParametersListString(parameters); } String? _getTypeParametersString(engine.Element element) { List? typeParameters; if (element is engine.InterfaceElement) { typeParameters = element.typeParameters; } else if (element is engine.TypeAliasElement) { typeParameters = element.typeParameters; } if (typeParameters == null || typeParameters.isEmpty) { return null; } return '<${typeParameters.join(', ')}>'; } bool _isAbstract(engine.Element element) { if (element is engine.ClassElement) { return element.isAbstract; } if (element is engine.MethodElement) { return element.isAbstract; } if (element is engine.MixinElement) { return true; } return false; } bool _isConst(engine.Element element) { if (element is engine.ConstructorElement) { return element.isConst; } if (element is engine.VariableElement) { return element.isConst; } return false; } bool _isFinal(engine.Element element) { if (element is engine.VariableElement) { return element.isFinal; } return false; } bool _isStatic(engine.Element element) { if (element is engine.ExecutableElement) { return element.isStatic; } if (element is engine.PropertyInducingElement) { return element.isStatic; } return false; } /// Sort required named parameters before optional ones. int _preferRequiredParams( engine.FormalParameterElement e1, engine.FormalParameterElement e2, ) { var rank1 = (e1.isRequiredNamed || e1.metadata.hasRequired) ? 0 : !e1.isNamed ? -1 : 1; var rank2 = (e2.isRequiredNamed || e2.metadata.hasRequired) ? 0 : !e2.isNamed ? -1 : 1; return rank1 - rank2; }