blob: 4b05c759a830503087c98f012b0879f384ce2efe [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/expressions.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/parser.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/proto.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/references.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/scope.dart' as shared;
import 'package:_fe_analyzer_shared/src/metadata/type_annotations.dart'
as shared;
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:kernel/ast.dart';
import '../../base/loader.dart';
import '../../base/scope.dart';
import '../../builder/builder.dart';
import '../../builder/declaration_builders.dart';
import '../../builder/dynamic_type_declaration_builder.dart';
import '../../builder/future_or_type_declaration_builder.dart';
import '../../builder/member_builder.dart';
import '../../builder/method_builder.dart';
import '../../builder/never_type_declaration_builder.dart';
import '../../builder/null_type_declaration_builder.dart';
import '../../builder/prefix_builder.dart';
import '../../builder/property_builder.dart';
import '../../source/source_property_builder.dart';
// Coverage-ignore(suite): Not run.
final Uri dummyUri = Uri.parse('dummy:uri');
// Coverage-ignore(suite): Not run.
bool _isDartLibrary(Uri importUri, Uri fileUri) {
return importUri.isScheme("dart") || fileUri.isScheme("org-dartlang-sdk");
}
// Coverage-ignore(suite): Not run.
/// Creates a [shared.Expression] for the annotation at [atToken].
///
/// If [delayLookupForTesting] is `true`, identifiers are not looked up in their
/// corresponding scopes. This means that the return expression will contain
/// [shared.UnresolvedIdentifier] nodes, as if the identifier wasn't in scope.
/// A subsequent call to [shared.Expression.resolve] will perform the lookup
/// a create the resolved expression. This is used in testing to mimic the
/// scenario in which the declaration is added to the scope via macros.
shared.Expression parseAnnotation(
Loader loader,
Token atToken,
Uri importUri,
Uri fileUri,
LookupScope scope, {
bool delayLookupForTesting = false,
}) {
return shared.parseAnnotation(
atToken,
fileUri,
new AnnotationScope(scope),
new References(loader),
isDartLibrary: _isDartLibrary(importUri, fileUri),
delayLookupForTesting: delayLookupForTesting,
);
}
// Coverage-ignore(suite): Not run.
/// Creates a [shared.Expression] for the initializer at [initializerToken].
///
/// If [delayLookupForTesting] is `true`, identifiers are not looked up in their
/// corresponding scopes. This means that the return expression will contain
/// [shared.UnresolvedIdentifier] nodes, as if the identifier wasn't in scope.
/// A subsequent call to [shared.Expression.resolve] will perform the lookup
/// a create the resolved expression. This is used in testing to mimic the
/// scenario in which the declaration is added to the scope via macros.
shared.Expression parseFieldInitializer(
Loader loader,
Token initializerToken,
Uri importUri,
Uri fileUri,
LookupScope scope, {
bool delayLookupForTesting = false,
}) {
return shared.parseExpression(
initializerToken,
fileUri,
new AnnotationScope(scope),
new References(loader),
isDartLibrary: _isDartLibrary(importUri, fileUri),
delayLookupForTesting: delayLookupForTesting,
);
}
// Coverage-ignore(suite): Not run.
/// Returns the [shared.Expression] for the constant initializer of [reference].
shared.Expression? getFieldInitializer(shared.FieldReference reference) {
if (reference is PropertyReference) {
PropertyBuilder element = reference.builder;
if (element is SourcePropertyBuilder) {
return element.initializerExpression;
}
} else {
assert(
false,
"Unexpected field reference $reference (${reference.runtimeType})",
);
}
return null;
}
// Coverage-ignore(suite): Not run.
shared.Proto builderToProto(Builder builder, String name) {
if (builder is PropertyBuilder) {
return new shared.FieldProto(new PropertyReference(builder));
} else if (builder is MethodBuilder) {
return new shared.FunctionProto(new MethodReference(builder));
} else if (builder is PrefixBuilder) {
return new shared.PrefixProto(name, new PrefixScope(builder));
} else if (builder is ClassBuilder) {
if (builder.isEnum) {
shared.EnumReference enumReference = new EnumReference(builder);
return new shared.EnumProto(
enumReference,
new EnumScope(builder, enumReference),
);
} else if (builder.isMixinDeclaration) {
shared.MixinReference mixinReference = new MixinReference(builder);
return new shared.MixinProto(
mixinReference,
new MixinScope(builder, mixinReference),
);
} else {
shared.ClassReference classReference = new ClassReference(builder);
return new shared.ClassProto(
classReference,
new ClassScope(builder, classReference),
);
}
} else if (builder is DynamicTypeDeclarationBuilder) {
return new shared.DynamicProto(new TypeReference(builder));
} else if (builder is TypeAliasBuilder) {
shared.TypedefReference typedefReference = new TypedefReference(builder);
return new shared.TypedefProto(
typedefReference,
new TypedefScope(builder, typedefReference),
);
} else if (builder is ExtensionBuilder) {
shared.ExtensionReference extensionReference = new ExtensionReference(
builder,
);
return new shared.ExtensionProto(
extensionReference,
new ExtensionScope(builder, extensionReference),
);
} else if (builder is ExtensionTypeDeclarationBuilder) {
shared.ExtensionTypeReference extensionReference =
new ExtensionTypeReference(builder);
return new shared.ExtensionTypeProto(
extensionReference,
new ExtensionTypeScope(builder, extensionReference),
);
} else {
// TODO(johnniwinther): Support extension types.
throw new UnsupportedError("Unsupported builder $builder for $name");
}
}
// Coverage-ignore(suite): Not run.
class References implements shared.References {
final Loader loader;
late final DynamicTypeDeclarationBuilder dynamicDeclaration =
new DynamicTypeDeclarationBuilder(
const DynamicType(),
loader.coreLibrary,
-1,
);
late final NeverTypeDeclarationBuilder neverDeclaration =
new NeverTypeDeclarationBuilder(
const NeverType.nonNullable(),
loader.coreLibrary,
-1,
);
late final NullTypeDeclarationBuilder nullDeclaration =
new NullTypeDeclarationBuilder(const NullType(), loader.coreLibrary, -1);
late final FutureOrTypeDeclarationBuilder futureOrDeclaration =
new FutureOrTypeDeclarationBuilder(
new FutureOrType(const DynamicType(), Nullability.nonNullable),
loader.coreLibrary,
-1,
);
@override
late final shared.TypeReference dynamicReference = new TypeReference(
dynamicDeclaration,
);
@override
shared.TypeReference get voidReference => const VoidTypeReference();
References(this.loader);
}
// Coverage-ignore(suite): Not run.
class AnnotationScope implements shared.Scope {
final LookupScope scope;
AnnotationScope(this.scope);
@override
shared.Proto lookup(String name) {
Builder? builder = scope.lookup(name)?.getable;
if (builder == null) {
return new shared.UnresolvedIdentifier(this, name);
} else {
return builderToProto(builder, name);
}
}
}
// Coverage-ignore(suite): Not run.
final class ClassScope extends shared.BaseClassScope {
final ClassBuilder builder;
@override
final shared.ClassReference classReference;
ClassScope(this.builder, this.classReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
MemberBuilder? constructor = builder.nameSpace
.lookupConstructor(name)
?.getable;
if (constructor != null) {
return createConstructorProto(
typeArguments,
new ConstructorReference(constructor),
);
}
Builder? member = builder.lookupLocalMember(name)?.getable;
return createMemberProto(typeArguments, name, member, builderToProto);
}
}
// Coverage-ignore(suite): Not run.
final class EnumScope extends shared.BaseEnumScope {
final ClassBuilder builder;
@override
final shared.EnumReference enumReference;
EnumScope(this.builder, this.enumReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
Builder? member = builder.lookupLocalMember(name)?.getable;
return createMemberProto(typeArguments, name, member, builderToProto);
}
}
// Coverage-ignore(suite): Not run.
final class MixinScope extends shared.BaseMixinScope {
final ClassBuilder builder;
@override
final shared.MixinReference mixinReference;
MixinScope(this.builder, this.mixinReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
Builder? member = builder.lookupLocalMember(name)?.getable;
return createMemberProto(typeArguments, name, member, builderToProto);
}
}
// Coverage-ignore(suite): Not run.
final class ExtensionScope extends shared.BaseExtensionScope {
final ExtensionBuilder builder;
@override
final shared.ExtensionReference extensionReference;
ExtensionScope(this.builder, this.extensionReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
Builder? member = builder.lookupLocalMember(name)?.getable;
return createMemberProto(typeArguments, name, member, builderToProto);
}
}
// Coverage-ignore(suite): Not run.
final class ExtensionTypeScope extends shared.BaseExtensionTypeScope {
final ExtensionTypeDeclarationBuilder builder;
@override
final shared.ExtensionTypeReference extensionTypeReference;
ExtensionTypeScope(this.builder, this.extensionTypeReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
MemberBuilder? constructor = builder.nameSpace
.lookupConstructor(name)
?.getable;
if (constructor != null) {
return createConstructorProto(
typeArguments,
new ConstructorReference(constructor),
);
}
Builder? member = builder.lookupLocalMember(name)?.getable;
return createMemberProto(typeArguments, name, member, builderToProto);
}
}
// Coverage-ignore(suite): Not run.
final class TypedefScope extends shared.BaseTypedefScope {
final TypeAliasBuilder builder;
@override
final shared.TypedefReference typedefReference;
TypedefScope(this.builder, this.typedefReference);
@override
shared.Proto lookup(
String name, [
List<shared.TypeAnnotation>? typeArguments,
]) {
TypeDeclarationBuilder? typeDeclaration = builder.unaliasDeclaration(null);
if (typeDeclaration is ClassBuilder) {
MemberBuilder? constructor = typeDeclaration.nameSpace
.lookupConstructor(name)
?.getable;
if (constructor != null) {
return createConstructorProto(
typeArguments,
new ConstructorReference(constructor),
);
}
}
return createMemberProto(typeArguments, name);
}
}
// Coverage-ignore(suite): Not run.
class TypeReference extends shared.TypeReference {
final TypeDeclarationBuilder builder;
TypeReference(this.builder);
@override
String get name => builder.name;
}
class VoidTypeReference extends shared.TypeReference {
const VoidTypeReference();
@override
// Coverage-ignore(suite): Not run.
String get name => 'void';
}
// Coverage-ignore(suite): Not run.
class PrefixScope implements shared.Scope {
final PrefixBuilder prefixBuilder;
PrefixScope(this.prefixBuilder);
@override
shared.Proto lookup(String name) {
Builder? builder = prefixBuilder.lookup(name)?.getable;
if (builder == null) {
return new shared.UnresolvedIdentifier(this, name);
} else {
return builderToProto(builder, name);
}
}
}
// Coverage-ignore(suite): Not run.
class PropertyReference extends shared.FieldReference {
final PropertyBuilder builder;
PropertyReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class MethodReference extends shared.FunctionReference {
final MethodBuilder builder;
MethodReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class ConstructorReference extends shared.ConstructorReference {
final MemberBuilder builder;
ConstructorReference(this.builder);
@override
String get name => builder.name.isEmpty ? 'new' : builder.name;
}
// Coverage-ignore(suite): Not run.
class ClassReference extends shared.ClassReference {
final ClassBuilder builder;
ClassReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class EnumReference extends shared.EnumReference {
final ClassBuilder builder;
EnumReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class MixinReference extends shared.MixinReference {
final ClassBuilder builder;
MixinReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class ExtensionReference extends shared.ExtensionReference {
final ExtensionBuilder builder;
ExtensionReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class ExtensionTypeReference extends shared.ExtensionTypeReference {
final ExtensionTypeDeclarationBuilder builder;
ExtensionTypeReference(this.builder);
@override
String get name => builder.name;
}
// Coverage-ignore(suite): Not run.
class TypedefReference extends shared.TypedefReference {
final TypeAliasBuilder builder;
TypedefReference(this.builder);
@override
String get name => builder.name;
}