blob: fa7f1ecced3c3e9de4d326f29fbeb6d94a195a94 [file] [log] [blame]
// Copyright (c) 2024, 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:_fe_analyzer_shared/src/metadata/ast.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/parser.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/scope.dart' as shared;
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/scope.dart';
/// Creates a [shared.Expression] for the [annotation].
shared.Expression parseAnnotation(ElementAnnotationImpl annotation) {
var compilationUnit = annotation.compilationUnit;
var annotationImpl = annotation.annotationAst;
var uri = compilationUnit.source.uri;
var scope = _Scope(compilationUnit);
var references = _References();
// The token stream might have been detached, so we ensure an EOF while
// parsing the annotation.
var endTokenNext = annotationImpl.endToken.next;
annotationImpl.endToken.next ??= Token.eof(-1);
var expression = shared.parseAnnotation(
annotationImpl.atSign, uri, scope, references,
isDartLibrary: uri.isScheme("dart") || uri.isScheme("org-dartlang-sdk"));
annotationImpl.endToken.next = endTokenNext;
return expression;
}
shared.Proto _elementToProto(Element element, String name) {
if (element is ClassElement) {
var reference = _ClassReference(element);
return shared.ClassProto(reference, _ClassScope(element, reference));
} else if (element is PropertyAccessorElement) {
VariableElement? variableElement = element.variable2;
if (variableElement != null) {
return shared.FieldProto(_VariableReference(variableElement));
}
} else if (element is FunctionElement) {
return shared.FunctionProto(_FunctionReference(element));
} else if (element is MethodElement) {
return shared.FunctionProto(_FunctionReference(element));
} else if (element is VariableElement) {
return shared.FieldProto(_VariableReference(element));
} else if (element is PrefixElement) {
return shared.PrefixProto(name, _PrefixScope(element));
} else if (element.kind == ElementKind.DYNAMIC) {
return shared.DynamicProto(const _DynamicReference());
} else if (element is TypeAliasElement) {
var reference = _TypedefReference(element);
return shared.TypedefProto(reference, _TypedefScope(element, reference));
} else if (element is ExtensionElement) {
var reference = _ExtensionReference(element);
return shared.ExtensionProto(
reference, _ExtensionScope(element, reference));
}
// TODO(johnniwinther): Support extension types.
throw UnsupportedError(
"Unsupported element $element (${element.runtimeType}) for '$name'.");
}
class _ClassReference extends shared.ClassReference {
final ClassElement _element;
_ClassReference(this._element);
@override
String get name => _element.name;
}
final class _ClassScope extends shared.BaseClassScope {
final ClassElement _classElement;
@override
final _ClassReference classReference;
_ClassScope(this._classElement, this.classReference);
@override
shared.Proto lookup(String name,
[List<shared.TypeAnnotation>? typeArguments]) {
var constructor = _classElement.getNamedConstructor(name);
if (constructor != null) {
return createConstructorProto(
typeArguments, _ConstructorReference(constructor));
}
Element? member = _classElement.augmented.getField(name);
member ??= _classElement.augmented.getMethod(name);
return createMemberProto(typeArguments, name, member, _elementToProto);
}
}
class _ConstructorReference extends shared.ConstructorReference {
final ConstructorElement _element;
_ConstructorReference(this._element);
@override
String get name => _element.name.isEmpty ? 'new' : _element.name;
}
class _DynamicReference extends shared.TypeReference {
const _DynamicReference();
@override
String get name => 'dynamic';
}
class _ExtensionReference extends shared.ExtensionReference {
final ExtensionElement _element;
_ExtensionReference(this._element);
@override
String get name => _element.name!;
}
final class _ExtensionScope extends shared.BaseExtensionScope {
final ExtensionElement _extensionElement;
@override
final _ExtensionReference extensionReference;
_ExtensionScope(this._extensionElement, this.extensionReference);
@override
shared.Proto lookup(String name,
[List<shared.TypeAnnotation>? typeArguments]) {
Element? member = _extensionElement.augmented.getField(name);
member ??= _extensionElement.augmented.getMethod(name);
return createMemberProto(typeArguments, name, member, _elementToProto);
}
}
class _FunctionReference extends shared.FunctionReference {
final ExecutableElement _element;
_FunctionReference(this._element);
@override
String get name => _element.name;
}
class _PrefixScope implements shared.Scope {
final PrefixElement _prefixElement;
_PrefixScope(this._prefixElement);
@override
shared.Proto lookup(String name) {
ScopeLookupResult result = _prefixElement.scope.lookup(name);
Element? getter = result.getter;
if (getter == null) {
return shared.UnresolvedIdentifier(this, name);
} else {
return _elementToProto(getter, name);
}
}
}
class _References implements shared.References {
@override
shared.TypeReference get dynamicReference => const _DynamicReference();
@override
shared.TypeReference get voidReference => const _VoidReference();
}
class _Scope implements shared.Scope {
final LibraryFragmentScope _libraryFragmentScope;
_Scope(CompilationUnitElementImpl compilationUnit)
: _libraryFragmentScope = LibraryFragmentScope(compilationUnit);
@override
shared.Proto lookup(String name) {
ScopeLookupResult result = _libraryFragmentScope.lookup(name);
Element? getter = result.getter;
if (getter == null) {
return shared.UnresolvedIdentifier(this, name);
} else {
return _elementToProto(getter, name);
}
}
}
class _TypedefReference implements shared.TypedefReference {
final TypeAliasElement _element;
_TypedefReference(this._element);
@override
String get name => _element.name;
}
final class _TypedefScope extends shared.BaseTypedefScope {
final TypeAliasElement _typeAliasElement;
@override
final shared.TypedefReference typedefReference;
_TypedefScope(this._typeAliasElement, this.typedefReference);
@override
shared.Proto lookup(String name,
[List<shared.TypeAnnotation>? typeArguments]) {
DartType aliasedType = _typeAliasElement.aliasedType;
if (aliasedType is InterfaceType) {
var constructor = aliasedType.element.getNamedConstructor(name);
if (constructor != null) {
return createConstructorProto(
typeArguments, _ConstructorReference(constructor));
}
}
return createMemberProto(typeArguments, name);
}
}
class _VariableReference extends shared.FieldReference {
final VariableElement _element;
_VariableReference(this._element);
@override
String get name => _element.name;
}
class _VoidReference extends shared.TypeReference {
const _VoidReference();
@override
String get name => 'void';
}