blob: 6d36b4a571792c29965eb29f8362a29df4d52e5a [file] [log] [blame]
// Copyright (c) 2019, 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:kernel/ast.dart';
import '../base/common.dart';
import '../base/name_space.dart';
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/library_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/type_builder.dart';
import '../codes/cfe_codes.dart'
show
messagePatchDeclarationMismatch,
messagePatchDeclarationOrigin,
noLength;
import '../kernel/body_builder_context.dart';
import '../base/problems.dart';
import '../base/scope.dart';
import 'name_scheme.dart';
import 'source_builder_mixins.dart';
import 'source_library_builder.dart';
import 'source_member_builder.dart';
import 'type_parameter_scope_builder.dart';
class SourceExtensionBuilder extends ExtensionBuilderImpl
with SourceDeclarationBuilderMixin {
final Extension _extension;
SourceExtensionBuilder? _origin;
SourceExtensionBuilder? augmentationForTesting;
MergedClassMemberScope? _mergedScope;
final DeclarationNameSpaceBuilder _nameSpaceBuilder;
late final LookupScope _scope;
late final DeclarationNameSpace _nameSpace;
late final ConstructorScope _constructorScope;
@override
final List<NominalVariableBuilder>? typeParameters;
@override
final LookupScope typeParameterScope;
@override
final TypeBuilder onType;
final ExtensionName extensionName;
SourceExtensionBuilder(
{required List<MetadataBuilder>? metadata,
required int modifiers,
required this.extensionName,
required this.typeParameters,
required this.onType,
required this.typeParameterScope,
required DeclarationNameSpaceBuilder nameSpaceBuilder,
required SourceLibraryBuilder enclosingLibraryBuilder,
required Uri fileUri,
required int startOffset,
required int nameOffset,
required int endOffset,
required Reference? reference})
: _extension = new Extension(
name: extensionName.name,
fileUri: fileUri,
typeParameters: NominalVariableBuilder.typeParametersFromBuilders(
typeParameters),
reference: reference)
..isUnnamedExtension = extensionName.isUnnamedExtension
..fileOffset = nameOffset,
_nameSpaceBuilder = nameSpaceBuilder,
super(metadata, modifiers, extensionName.name, enclosingLibraryBuilder,
fileUri, nameOffset) {
extensionName.attachExtension(_extension);
}
@override
LookupScope get scope => _scope;
@override
DeclarationNameSpace get nameSpace => _nameSpace;
@override
// Coverage-ignore(suite): Not run.
ConstructorScope get constructorScope => _constructorScope;
@override
void buildScopes(LibraryBuilder coreLibrary) {
_nameSpace = _nameSpaceBuilder.buildNameSpace(
loader: libraryBuilder.loader,
problemReporting: libraryBuilder,
enclosingLibraryBuilder: libraryBuilder,
declarationBuilder: this,
includeConstructors: false);
_scope = new NameSpaceLookupScope(
_nameSpace, ScopeKind.declaration, "extension ${extensionName.name}",
parent: typeParameterScope);
_constructorScope =
new DeclarationNameSpaceConstructorScope(name, _nameSpace);
}
@override
SourceLibraryBuilder get libraryBuilder =>
super.libraryBuilder as SourceLibraryBuilder;
bool get isUnnamedExtension => extensionName.isUnnamedExtension;
@override
SourceExtensionBuilder get origin => _origin ?? this;
// Coverage-ignore(suite): Not run.
// TODO(johnniwinther): Add merged scope for extensions.
MergedClassMemberScope get mergedScope => _mergedScope ??= isAugmenting
? origin.mergedScope
: throw new UnimplementedError("SourceExtensionBuilder.mergedScope");
@override
Extension get extension => isAugmenting
?
// Coverage-ignore(suite): Not run.
origin._extension
: _extension;
@override
BodyBuilderContext createBodyBuilderContext(
{required bool inOutlineBuildingPhase,
required bool inMetadata,
required bool inConstFields}) {
return new ExtensionBodyBuilderContext(this,
inOutlineBuildingPhase: inOutlineBuildingPhase,
inMetadata: inMetadata,
inConstFields: inConstFields);
}
@override
Annotatable get annotatable => extension;
/// Builds the [Extension] for this extension build and inserts the members
/// into the [Library] of [libraryBuilder].
///
/// [addMembersToLibrary] is `true` if the extension members should be added
/// to the library. This is `false` if the extension is in conflict with
/// another library member. In this case, the extension member should not be
/// added to the library to avoid name clashes with other members in the
/// library.
Extension build(LibraryBuilder coreLibrary,
{required bool addMembersToLibrary}) {
_extension.onType = onType.build(libraryBuilder, TypeUse.extensionOnType);
buildInternal(coreLibrary, addMembersToLibrary: addMembersToLibrary);
return _extension;
}
@override
// Coverage-ignore(suite): Not run.
void addMemberInternal(SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind, Member member, Member? tearOff) {
unhandled("${memberBuilder.runtimeType}:${memberKind}", "addMemberInternal",
memberBuilder.charOffset, memberBuilder.fileUri);
}
@override
void addMemberDescriptorInternal(
SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind,
Reference memberReference,
Reference? tearOffReference) {
String name = memberBuilder.name;
ExtensionMemberKind kind;
switch (memberKind) {
case BuiltMemberKind.Constructor:
case BuiltMemberKind.RedirectingFactory:
case BuiltMemberKind.Factory:
case BuiltMemberKind.Field:
case BuiltMemberKind.Method:
case BuiltMemberKind.ExtensionTypeConstructor:
case BuiltMemberKind.ExtensionTypeMethod:
case BuiltMemberKind.ExtensionTypeGetter:
case BuiltMemberKind.ExtensionTypeSetter:
case BuiltMemberKind.ExtensionTypeOperator:
case BuiltMemberKind.ExtensionTypeFactory:
case BuiltMemberKind.ExtensionTypeRedirectingFactory:
case BuiltMemberKind.ExtensionTypeRepresentationField:
// Coverage-ignore(suite): Not run.
unhandled(
"${memberBuilder.runtimeType}:${memberKind}",
"addMemberDescriptorInternal",
memberBuilder.charOffset,
memberBuilder.fileUri);
case BuiltMemberKind.ExtensionField:
case BuiltMemberKind.LateIsSetField:
kind = ExtensionMemberKind.Field;
break;
case BuiltMemberKind.ExtensionMethod:
kind = ExtensionMemberKind.Method;
break;
case BuiltMemberKind.ExtensionGetter:
case BuiltMemberKind.LateGetter:
kind = ExtensionMemberKind.Getter;
break;
case BuiltMemberKind.ExtensionSetter:
case BuiltMemberKind.LateSetter:
kind = ExtensionMemberKind.Setter;
break;
case BuiltMemberKind.ExtensionOperator:
kind = ExtensionMemberKind.Operator;
break;
}
extension.memberDescriptors.add(new ExtensionMemberDescriptor(
name: new Name(name, libraryBuilder.library),
memberReference: memberReference,
tearOffReference: tearOffReference,
isStatic: memberBuilder.isStatic,
kind: kind));
}
@override
// Coverage-ignore(suite): Not run.
void applyAugmentation(Builder augmentation) {
if (augmentation is SourceExtensionBuilder) {
augmentation._origin = this;
if (retainDataForTesting) {
augmentationForTesting = augmentation;
}
// TODO(johnniwinther): Check that type parameters and on-type match
// with origin declaration.
nameSpace.forEachLocalMember((String name, Builder member) {
Builder? memberAugmentation =
augmentation.nameSpace.lookupLocalMember(name, setter: false);
if (memberAugmentation != null) {
member.applyAugmentation(memberAugmentation);
}
});
nameSpace.forEachLocalSetter((String name, Builder member) {
Builder? memberAugmentation =
augmentation.nameSpace.lookupLocalMember(name, setter: true);
if (memberAugmentation != null) {
member.applyAugmentation(memberAugmentation);
}
});
} else {
libraryBuilder.addProblem(messagePatchDeclarationMismatch,
augmentation.charOffset, noLength, augmentation.fileUri, context: [
messagePatchDeclarationOrigin.withLocation(
fileUri, charOffset, noLength)
]);
}
}
}