blob: f920517edb76dd3df67676a9f07f34df97baf60f [file] [log] [blame]
// Copyright (c) 2025, 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 'package:kernel/reference_from_index.dart';
import 'package:kernel/src/bounds_checks.dart' show VarianceCalculationValue;
import '../base/messages.dart';
import '../base/modifiers.dart';
import '../base/name_space.dart';
import '../base/scope.dart';
import '../base/uri_offset.dart';
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/type_builder.dart';
import '../fragment/constructor/declaration.dart';
import '../fragment/constructor/encoding.dart';
import '../fragment/factory/declaration.dart';
import '../fragment/factory/encoding.dart';
import '../fragment/field/declaration.dart';
import '../fragment/fragment.dart';
import '../fragment/getter/declaration.dart';
import '../fragment/method/declaration.dart';
import '../fragment/method/encoding.dart';
import '../fragment/setter/declaration.dart';
import 'name_scheme.dart';
import 'name_space_builder.dart';
import 'source_class_builder.dart';
import 'source_constructor_builder.dart';
import 'source_enum_builder.dart';
import 'source_extension_builder.dart';
import 'source_extension_type_declaration_builder.dart';
import 'source_factory_builder.dart';
import 'source_library_builder.dart';
import 'source_loader.dart';
import 'source_method_builder.dart';
import 'source_property_builder.dart';
import 'source_type_alias_builder.dart';
import 'source_type_parameter_builder.dart';
import 'type_parameter_factory.dart';
/// Reports an error if [declaration] is augmenting.
///
/// This is called when the first [_PreBuilder] is created, meaning that the
/// augmentation didn't correspond to an introductory declaration.
void _checkAugmentation(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration.isAugment) {
Message message;
switch (declaration.kind) {
case _DeclarationKind.Class:
message = declaration.inPatch
? codeUnmatchedPatchClass.withArgumentsOld(declaration.displayName)
:
// Coverage-ignore(suite): Not run.
codeUnmatchedAugmentationClass.withArgumentsOld(
declaration.displayName,
);
case _DeclarationKind.Constructor:
case _DeclarationKind.Factory:
case _DeclarationKind.Method:
case _DeclarationKind.Property:
if (declaration.inLibrary) {
message = declaration.inPatch
? codeUnmatchedPatchLibraryMember.withArgumentsOld(
declaration.displayName,
)
:
// Coverage-ignore(suite): Not run.
codeUnmatchedAugmentationLibraryMember.withArgumentsOld(
declaration.displayName,
);
} else {
message = declaration.inPatch
? codeUnmatchedPatchClassMember.withArgumentsOld(
declaration.displayName,
)
:
// Coverage-ignore(suite): Not run.
codeUnmatchedAugmentationClassMember.withArgumentsOld(
declaration.displayName,
);
}
case _DeclarationKind.Mixin:
case _DeclarationKind.NamedMixinApplication:
case _DeclarationKind.Enum:
case _DeclarationKind.Extension:
// Coverage-ignore(suite): Not run.
case _DeclarationKind.ExtensionType:
// Coverage-ignore(suite): Not run.
case _DeclarationKind.Typedef:
// TODO(johnniwinther): Specialize more messages.
message = declaration.inPatch
? codeUnmatchedPatchDeclaration.withArgumentsOld(
declaration.displayName,
)
:
// Coverage-ignore(suite): Not run.
codeUnmatchedAugmentationDeclaration.withArgumentsOld(
declaration.displayName,
);
}
problemReporting.addProblem2(message, declaration.uriOffset);
}
}
class BuilderFactory {
final ProblemReporting _problemReporting;
final SourceLoader _loader;
final BuilderRegistry _builderRegistry;
final SourceLibraryBuilder _enclosingLibraryBuilder;
final DeclarationBuilder? _declarationBuilder;
final TypeParameterFactory _typeParameterFactory;
final Map<SourceClassBuilder, TypeBuilder> _mixinApplications;
final IndexedLibrary? _indexedLibrary;
final ContainerType _containerType;
final IndexedContainer? _indexedContainer;
final ContainerName? _containerName;
final bool _inLibrary;
BuilderFactory({
required ProblemReporting problemReporting,
required SourceLoader loader,
required BuilderRegistry builderRegistry,
required SourceLibraryBuilder enclosingLibraryBuilder,
DeclarationBuilder? declarationBuilder,
required TypeParameterFactory typeParameterFactory,
required Map<SourceClassBuilder, TypeBuilder> mixinApplications,
required IndexedLibrary? indexedLibrary,
required ContainerType containerType,
IndexedContainer? indexedContainer,
ContainerName? containerName,
}) : _containerName = containerName,
_indexedContainer = indexedContainer,
_containerType = containerType,
_indexedLibrary = indexedLibrary,
_mixinApplications = mixinApplications,
_typeParameterFactory = typeParameterFactory,
_declarationBuilder = declarationBuilder,
_enclosingLibraryBuilder = enclosingLibraryBuilder,
_builderRegistry = builderRegistry,
_loader = loader,
_problemReporting = problemReporting,
_inLibrary = declarationBuilder == null;
void computeBuildersByName(
String name, {
List<Fragment>? fragments,
SyntheticDeclaration? syntheticDeclaration,
}) {
List<_PreBuilder> nonConstructorPreBuilders = [];
List<_PreBuilder> constructorPreBuilders = [];
List<Fragment> unnamedFragments = [];
if (syntheticDeclaration != null) {
syntheticDeclaration.createDeclaration().registerPreBuilder(
_problemReporting,
nonConstructorPreBuilders,
constructorPreBuilders,
);
}
if (fragments != null) {
for (int i = 0; i < fragments.length; i++) {
Fragment fragment = fragments[i];
_Declaration? declaration = _createDeclarationFromFragment(
fragment,
inLibrary: _inLibrary,
unnamedFragments: unnamedFragments,
);
declaration?.registerPreBuilder(
_problemReporting,
nonConstructorPreBuilders,
constructorPreBuilders,
);
}
}
for (int i = 0; i < nonConstructorPreBuilders.length; i++) {
_PreBuilder preBuilder = nonConstructorPreBuilders[i];
preBuilder.createBuilders(this);
}
for (int i = 0; i < constructorPreBuilders.length; i++) {
_PreBuilder preBuilder = constructorPreBuilders[i];
preBuilder.createBuilders(this);
}
for (int i = 0; i < unnamedFragments.length; i++) {
Fragment fragment = unnamedFragments[i];
_createBuilder(fragment);
}
}
void _createBuilder(Fragment fragment, {List<Fragment>? augmentations}) {
switch (fragment) {
case TypedefFragment():
_createTypedefBuilder(fragment);
case ClassFragment():
_createClassBuilder(fragment, augmentations);
case MixinFragment():
_createMixinBuilder(fragment);
case NamedMixinApplicationFragment():
_createNamedMixinApplicationBuilder(fragment);
case EnumFragment():
_createEnumBuilder(fragment);
case ExtensionFragment():
_createExtensionBuilder(fragment, augmentations);
case ExtensionTypeFragment():
_createExtensionTypeBuilder(fragment);
case MethodFragment():
_createMethodBuilder(fragment, augmentations);
// Coverage-ignore(suite): Not run.
case ConstructorFragment():
case PrimaryConstructorFragment():
case FactoryFragment():
case FieldFragment():
case PrimaryConstructorFieldFragment():
case GetterFragment():
case SetterFragment():
case EnumElementFragment():
throw new UnsupportedError('Unexpected fragment $fragment.');
}
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
// Coverage-ignore-block(suite): Not run.
_createBuilder(augmentation);
}
}
}
void _createClassBuilder(
ClassFragment fragment,
List<Fragment>? augmentations,
) {
String name = fragment.name;
DeclarationNameSpaceBuilder nameSpaceBuilder = fragment
.toDeclarationNameSpaceBuilder();
ClassDeclaration introductoryDeclaration = new RegularClassDeclaration(
fragment,
);
List<SourceNominalParameterBuilder>? nominalParameters =
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: fragment.name,
allowNameConflict: false,
);
Modifiers modifiers = fragment.modifiers;
List<ClassDeclaration> augmentationDeclarations = [];
if (augmentations != null) {
int introductoryTypeParameterCount = fragment.typeParameters?.length ?? 0;
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [ClassFragment].
augmentation as ClassFragment;
// TODO(johnniwinther): Check that other modifiers are consistent.
if (augmentation.modifiers.declaresConstConstructor) {
modifiers |= Modifiers.DeclaresConstConstructor;
}
augmentationDeclarations.add(new RegularClassDeclaration(augmentation));
nameSpaceBuilder.includeBuilders(
augmentation.toDeclarationNameSpaceBuilder(),
);
int augmentationTypeParameterCount =
augmentation.typeParameters?.length ?? 0;
if (introductoryTypeParameterCount != augmentationTypeParameterCount) {
_problemReporting.addProblem(
codePatchClassTypeParametersMismatch,
augmentation.nameOffset,
name.length,
augmentation.fileUri,
context: [
codePatchClassOrigin.withLocation(
fragment.fileUri,
fragment.nameOffset,
name.length,
),
],
);
// Error recovery. Create fresh type parameters for the
// augmentation.
augmentation.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
_typeParameterFactory.createNominalParameterBuilders(
augmentation.typeParameters,
),
ownerName: augmentation.name,
allowNameConflict: false,
);
} else if (augmentation.typeParameters != null) {
for (int index = 0; index < introductoryTypeParameterCount; index++) {
SourceNominalParameterBuilder nominalParameterBuilder =
nominalParameters![index];
TypeParameterFragment typeParameterFragment =
augmentation.typeParameters![index];
nominalParameterBuilder.addAugmentingDeclaration(
new RegularNominalParameterDeclaration(typeParameterFragment),
);
typeParameterFragment.builder = nominalParameterBuilder;
}
augmentation.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: augmentation.name,
allowNameConflict: false,
);
}
}
}
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(name);
SourceClassBuilder classBuilder = new SourceClassBuilder(
modifiers: modifiers,
name: name,
typeParameters: fragment.typeParameters?.builders,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: indexedClass,
introductory: introductoryDeclaration,
augmentations: augmentationDeclarations,
);
fragment.builder = classBuilder;
fragment.bodyScope.declarationBuilder = classBuilder;
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
augmentation as ClassFragment;
augmentation.builder = classBuilder;
augmentation.bodyScope.declarationBuilder = classBuilder;
}
augmentations.clear();
}
if (indexedClass != null) {
_loader.referenceMap.registerNamedBuilder(
indexedClass.reference,
classBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: classBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createConstructorBuilderFromDeclarations(
ConstructorDeclaration constructorDeclaration,
List<ConstructorDeclaration> augmentationDeclarations, {
required String name,
required UriOffsetLength uriOffset,
required bool isConst,
required bool inPatch,
}) {
NameScheme nameScheme = new NameScheme(
isInstanceMember: false,
containerName: _containerName,
containerType: _containerType,
libraryName: _indexedLibrary != null
? new LibraryName(_indexedLibrary.library.reference)
: _enclosingLibraryBuilder.libraryName,
);
ConstructorEncodingStrategy encodingStrategy =
new ConstructorEncodingStrategy(_declarationBuilder!);
ConstructorReferences constructorReferences = new ConstructorReferences(
name: name,
nameScheme: nameScheme,
indexedContainer: _indexedContainer,
loader: _loader,
declarationBuilder: _declarationBuilder,
);
SourceConstructorBuilder constructorBuilder = new SourceConstructorBuilder(
name: name,
libraryBuilder: _enclosingLibraryBuilder,
declarationBuilder: _declarationBuilder,
fileUri: uriOffset.fileUri,
fileOffset: uriOffset.fileOffset,
constructorReferences: constructorReferences,
nameScheme: nameScheme,
introductory: constructorDeclaration,
augmentations: augmentationDeclarations,
isConst: isConst,
);
constructorReferences.registerReference(
_loader.referenceMap,
constructorBuilder,
);
constructorDeclaration.createEncoding(
problemReporting: _problemReporting,
loader: _loader,
declarationBuilder: _declarationBuilder,
constructorBuilder: constructorBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
);
for (ConstructorDeclaration augmentation in augmentationDeclarations) {
augmentation.createEncoding(
problemReporting: _problemReporting,
loader: _loader,
declarationBuilder: _declarationBuilder,
constructorBuilder: constructorBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
);
}
_builderRegistry.registerBuilder(
declaration: constructorBuilder,
uriOffset: uriOffset,
inPatch: inPatch,
);
}
_Declaration? _createDeclarationFromFragment(
Fragment fragment, {
required bool inLibrary,
required List<Fragment> unnamedFragments,
}) {
switch (fragment) {
case ClassFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.Class,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case EnumFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.Enum,
fragment,
displayName: fragment.name,
// TODO(johnniwinther): Support enum augmentations.
isAugment: false,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case ExtensionTypeFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.ExtensionType,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case MethodFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.Method,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
isStatic: inLibrary || fragment.modifiers.isStatic,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
inLibrary: inLibrary,
);
case MixinFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.Mixin,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case NamedMixinApplicationFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.NamedMixinApplication,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case TypedefFragment():
return new _StandardFragmentDeclaration(
_DeclarationKind.Typedef,
fragment,
displayName: fragment.name,
// TODO(johnniwinther): Support typedef augmentations.
isAugment: false,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
case ExtensionFragment():
if (!fragment.isUnnamed) {
return new _StandardFragmentDeclaration(
_DeclarationKind.Extension,
fragment,
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingCompilationUnit.isPatch,
inLibrary: true,
);
} else {
unnamedFragments.add(fragment);
return null;
}
case FactoryFragment():
return new _FactoryConstructorDeclaration(
new FactoryDeclarationImpl(fragment),
name: fragment.name,
displayName: fragment.constructorName.fullName,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
isConst: fragment.modifiers.isConst,
uriOffset: fragment.uriOffset,
);
case ConstructorFragment():
return new _GenerativeConstructorDeclaration(
new RegularConstructorDeclaration(fragment),
name: fragment.name,
displayName: fragment.constructorName.fullName,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
isConst: fragment.modifiers.isConst,
uriOffset: fragment.uriOffset,
);
case PrimaryConstructorFragment():
return new _GenerativeConstructorDeclaration(
new PrimaryConstructorDeclaration(fragment),
name: fragment.name,
displayName: fragment.constructorName.fullName,
isAugment: fragment.modifiers.isAugment,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
isConst: fragment.modifiers.isConst,
uriOffset: fragment.uriOffset,
);
case FieldFragment():
RegularFieldDeclaration declaration = new RegularFieldDeclaration(
fragment,
);
return new _FieldDeclaration(
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
propertyKind: fragment.hasSetter
? _PropertyKind.Field
: _PropertyKind.FinalField,
isStatic: inLibrary || fragment.modifiers.isStatic,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
inLibrary: inLibrary,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
field: declaration,
getter: declaration,
setter: fragment.hasSetter ? declaration : null,
),
);
case PrimaryConstructorFieldFragment():
PrimaryConstructorFieldDeclaration declaration =
new PrimaryConstructorFieldDeclaration(fragment);
return new _FieldDeclaration(
displayName: fragment.name,
isAugment: false,
propertyKind: _PropertyKind.FinalField,
isStatic: false,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: false,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
field: declaration,
getter: declaration,
),
);
case GetterFragment():
return new _GetterDeclaration(
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
propertyKind: _PropertyKind.Getter,
isStatic: inLibrary || fragment.modifiers.isStatic,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
inLibrary: inLibrary,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
getter: new RegularGetterDeclaration(fragment),
),
);
case SetterFragment():
return new _SetterDeclaration(
displayName: fragment.name,
isAugment: fragment.modifiers.isAugment,
propertyKind: _PropertyKind.Setter,
isStatic: inLibrary || fragment.modifiers.isStatic,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
inLibrary: inLibrary,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
setter: new RegularSetterDeclaration(fragment),
),
);
case EnumElementFragment():
EnumElementDeclaration declaration = new EnumElementDeclaration(
fragment,
);
return new _FieldDeclaration(
displayName: fragment.name,
isAugment: false,
propertyKind: _PropertyKind.FinalField,
isStatic: true,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
field: declaration,
getter: declaration,
),
);
}
}
void _createEnumBuilder(EnumFragment fragment) {
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(
fragment.name,
);
List<SourceNominalParameterBuilder>? typeParameters = _typeParameterFactory
.createNominalParameterBuilders(fragment.typeParameters);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
typeParameters,
ownerName: fragment.name,
allowNameConflict: false,
);
SourceEnumBuilder enumBuilder = new SourceEnumBuilder(
name: fragment.name,
typeParameters: typeParameters,
underscoreEnumTypeBuilder: _loader.target.underscoreEnumType,
interfaceBuilders: fragment.interfaces,
enumElements: fragment.enumElements,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOffset,
endOffset: fragment.endOffset,
indexedClass: indexedClass,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
classDeclaration: new EnumDeclaration(
fragment,
_loader.target.underscoreEnumType,
),
);
fragment.builder = enumBuilder;
fragment.bodyScope.declarationBuilder = enumBuilder;
if (indexedClass != null) {
_loader.referenceMap.registerNamedBuilder(
indexedClass.reference,
enumBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: enumBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createExtensionBuilder(
ExtensionFragment fragment,
List<Fragment>? augmentations,
) {
DeclarationNameSpaceBuilder nameSpaceBuilder = fragment
.toDeclarationNameSpaceBuilder();
List<SourceNominalParameterBuilder>? nominalParameters =
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: fragment.name,
allowNameConflict: false,
);
List<ExtensionFragment> augmentationFragments = [];
if (augmentations != null) {
int introductoryTypeParameterCount = fragment.typeParameters?.length ?? 0;
int nameLength = fragment.isUnnamed ? noLength : fragment.name.length;
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [ExtensionFragment].
augmentation as ExtensionFragment;
augmentationFragments.add(augmentation);
nameSpaceBuilder.includeBuilders(
augmentation.toDeclarationNameSpaceBuilder(),
);
int augmentationTypeParameterCount =
augmentation.typeParameters?.length ?? 0;
if (introductoryTypeParameterCount != augmentationTypeParameterCount) {
_problemReporting.addProblem(
codePatchExtensionTypeParametersMismatch,
augmentation.nameOrExtensionOffset,
nameLength,
augmentation.fileUri,
context: [
codePatchExtensionOrigin.withLocation(
fragment.fileUri,
fragment.nameOrExtensionOffset,
nameLength,
),
],
);
// Error recovery. Create fresh type parameters for the
// augmentation.
augmentation.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
_typeParameterFactory.createNominalParameterBuilders(
augmentation.typeParameters,
),
ownerName: augmentation.name,
allowNameConflict: false,
);
} else if (augmentation.typeParameters != null) {
for (int index = 0; index < introductoryTypeParameterCount; index++) {
SourceNominalParameterBuilder nominalParameterBuilder =
nominalParameters![index];
TypeParameterFragment typeParameterFragment =
augmentation.typeParameters![index];
nominalParameterBuilder.addAugmentingDeclaration(
new RegularNominalParameterDeclaration(typeParameterFragment),
);
typeParameterFragment.builder = nominalParameterBuilder;
}
augmentation.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: augmentation.name,
allowNameConflict: false,
);
}
}
augmentations.clear();
}
Reference? reference;
if (!fragment.extensionName.isUnnamedExtension) {
reference = _indexedLibrary?.lookupExtension(fragment.name);
}
SourceExtensionBuilder extensionBuilder = new SourceExtensionBuilder(
enclosingLibraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOrExtensionOffset,
endOffset: fragment.endOffset,
introductory: fragment,
augmentations: augmentationFragments,
nameSpaceBuilder: nameSpaceBuilder,
reference: reference,
);
if (reference != null) {
_loader.referenceMap.registerNamedBuilder(reference, extensionBuilder);
}
_builderRegistry.registerBuilder(
declaration: extensionBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createExtensionTypeBuilder(ExtensionTypeFragment fragment) {
IndexedContainer? indexedContainer = _indexedLibrary
?.lookupIndexedExtensionTypeDeclaration(fragment.name);
List<PrimaryConstructorFieldFragment> primaryConstructorFields =
fragment.primaryConstructorFields;
PrimaryConstructorFieldFragment? representationFieldFragment;
if (primaryConstructorFields.isNotEmpty) {
representationFieldFragment = primaryConstructorFields.first;
}
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
fragment.typeParameters?.builders,
ownerName: fragment.name,
allowNameConflict: false,
);
SourceExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder =
new SourceExtensionTypeDeclarationBuilder(
name: fragment.name,
enclosingLibraryBuilder: _enclosingLibraryBuilder,
constructorReferences: fragment.constructorReferences,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOffset,
endOffset: fragment.endOffset,
fragment: fragment,
indexedContainer: indexedContainer,
representationFieldFragment: representationFieldFragment,
);
if (indexedContainer?.reference != null) {
_loader.referenceMap.registerNamedBuilder(
indexedContainer!.reference,
extensionTypeDeclarationBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: extensionTypeDeclarationBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createFactoryBuilderFromDeclarations(
FactoryDeclaration introductory,
List<FactoryDeclaration> augmentations, {
required String name,
required bool isConst,
required UriOffsetLength uriOffset,
required bool inPatch,
}) {
FactoryEncodingStrategy encodingStrategy = new FactoryEncodingStrategy(
_declarationBuilder!,
);
NameScheme nameScheme = new NameScheme(
containerName: _containerName,
containerType: _containerType,
isInstanceMember: false,
libraryName: _indexedLibrary != null
? new LibraryName(_indexedLibrary.library.reference)
: _enclosingLibraryBuilder.libraryName,
);
FactoryReferences factoryReferences = new FactoryReferences(
name: name,
nameScheme: nameScheme,
indexedContainer: _indexedContainer,
loader: _loader,
declarationBuilder: _declarationBuilder,
);
bool isRedirectingFactory = introductory.isRedirectingFactory;
for (FactoryDeclaration augmentation in augmentations) {
if (augmentation.isRedirectingFactory) {
isRedirectingFactory = true;
}
}
SourceFactoryBuilder factoryBuilder = new SourceFactoryBuilder(
name: name,
libraryBuilder: _enclosingLibraryBuilder,
declarationBuilder: _declarationBuilder,
fileUri: uriOffset.fileUri,
fileOffset: uriOffset.fileOffset,
factoryReferences: factoryReferences,
nameScheme: nameScheme,
introductory: introductory,
augmentations: augmentations,
isConst: isConst,
);
if (isRedirectingFactory) {
(_enclosingLibraryBuilder.redirectingFactoryBuilders ??= []).add(
factoryBuilder,
);
}
introductory.createEncoding(
problemReporting: _problemReporting,
declarationBuilder: _declarationBuilder,
factoryBuilder: factoryBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
);
for (FactoryDeclaration augmentation in augmentations) {
augmentation.createEncoding(
problemReporting: _problemReporting,
declarationBuilder: _declarationBuilder,
factoryBuilder: factoryBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
);
}
factoryReferences.registerReference(_loader.referenceMap, factoryBuilder);
_builderRegistry.registerBuilder(
declaration: factoryBuilder,
uriOffset: uriOffset,
inPatch: inPatch,
);
}
void _createMethodBuilder(
MethodFragment fragment,
List<Fragment>? augmentations,
) {
String name = fragment.name;
final bool isInstanceMember =
_containerType != ContainerType.Library && !fragment.modifiers.isStatic;
_typeParameterFactory.createNominalParameterBuilders(
fragment.declaredTypeParameters,
);
MethodEncodingStrategy encodingStrategy = new MethodEncodingStrategy(
_declarationBuilder,
isInstanceMember: isInstanceMember,
);
ProcedureKind kind = fragment.isOperator
? ProcedureKind.Operator
: ProcedureKind.Method;
final bool isExtensionMember = _containerType == ContainerType.Extension;
final bool isExtensionTypeMember =
_containerType == ContainerType.ExtensionType;
NameScheme nameScheme = new NameScheme(
containerName: _containerName,
containerType: _containerType,
isInstanceMember: isInstanceMember,
libraryName: _indexedLibrary != null
? new LibraryName(_indexedLibrary.library.reference)
: _enclosingLibraryBuilder.libraryName,
);
Reference? procedureReference;
Reference? tearOffReference;
IndexedContainer? indexedContainer = _indexedContainer ?? _indexedLibrary;
if (indexedContainer != null) {
Name nameToLookup = nameScheme.getProcedureMemberName(kind, name).name;
procedureReference = indexedContainer.lookupGetterReference(nameToLookup);
if ((isExtensionMember || isExtensionTypeMember) &&
kind == ProcedureKind.Method) {
tearOffReference = indexedContainer.lookupGetterReference(
nameScheme.getProcedureMemberName(ProcedureKind.Getter, name).name,
);
}
}
Modifiers modifiers = fragment.modifiers;
MethodDeclaration introductoryDeclaration = new MethodDeclarationImpl(
fragment,
);
List<MethodDeclaration> augmentationDeclarations = [];
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [MethodFragment].
augmentation as MethodFragment;
augmentationDeclarations.add(new MethodDeclarationImpl(augmentation));
_typeParameterFactory.createNominalParameterBuilders(
augmentation.declaredTypeParameters,
);
if (!(augmentation.modifiers.isAbstract ||
augmentation.modifiers.isExternal)) {
modifiers -= Modifiers.Abstract;
modifiers -= Modifiers.External;
}
}
}
SourceMethodBuilder methodBuilder = new SourceMethodBuilder(
fileUri: fragment.fileUri,
fileOffset: fragment.nameOffset,
name: name,
libraryBuilder: _enclosingLibraryBuilder,
declarationBuilder: _declarationBuilder,
isStatic: modifiers.isStatic,
modifiers: modifiers,
introductory: introductoryDeclaration,
augmentations: augmentationDeclarations,
nameScheme: nameScheme,
reference: procedureReference,
tearOffReference: tearOffReference,
);
fragment.builder = methodBuilder;
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [MethodFragment].
augmentation as MethodFragment;
augmentation.builder = methodBuilder;
}
augmentations.clear();
}
introductoryDeclaration.createEncoding(
_problemReporting,
methodBuilder,
encodingStrategy,
_typeParameterFactory,
);
for (MethodDeclaration augmentation in augmentationDeclarations) {
augmentation.createEncoding(
_problemReporting,
methodBuilder,
encodingStrategy,
_typeParameterFactory,
);
}
if (procedureReference != null) {
_loader.referenceMap.registerNamedBuilder(
procedureReference,
methodBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: methodBuilder,
uriOffset: fragment.uriOffset,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
);
}
void _createMixinBuilder(MixinFragment fragment) {
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(
fragment.name,
);
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
List<SourceNominalParameterBuilder>? typeParameters =
fragment.typeParameters?.builders;
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
typeParameters,
ownerName: fragment.name,
allowNameConflict: false,
);
SourceClassBuilder mixinBuilder = new SourceClassBuilder(
modifiers: fragment.modifiers,
name: fragment.name,
typeParameters: typeParameters,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: indexedClass,
introductory: new MixinDeclaration(fragment),
);
fragment.builder = mixinBuilder;
fragment.bodyScope.declarationBuilder = mixinBuilder;
if (indexedClass != null) {
_loader.referenceMap.registerNamedBuilder(
indexedClass.reference,
mixinBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: mixinBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createNamedMixinApplicationBuilder(
NamedMixinApplicationFragment fragment,
) {
List<TypeBuilder> mixins = fragment.mixins.toList();
TypeBuilder mixin = mixins.removeLast();
ClassDeclaration classDeclaration = new NamedMixinApplication(
fragment,
mixins,
);
String name = fragment.name;
IndexedClass? referencesFromIndexedClass = _indexedLibrary
?.lookupIndexedClass(name);
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
fragment.typeParameters?.builders,
ownerName: name,
allowNameConflict: false,
);
LookupScope typeParameterScope = TypeParameterScope.fromList(
fragment.enclosingScope,
fragment.typeParameters?.builders,
);
DeclarationNameSpaceBuilder nameSpaceBuilder =
new DeclarationNameSpaceBuilder.empty();
SourceClassBuilder classBuilder = new SourceClassBuilder(
modifiers: fragment.modifiers | Modifiers.NamedMixinApplication,
name: name,
typeParameters: fragment.typeParameters?.builders,
typeParameterScope: typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: referencesFromIndexedClass,
mixedInTypeBuilder: mixin,
introductory: classDeclaration,
);
_mixinApplications[classBuilder] = mixin;
fragment.builder = classBuilder;
if (referencesFromIndexedClass != null) {
_loader.referenceMap.registerNamedBuilder(
referencesFromIndexedClass.reference,
classBuilder,
);
}
_builderRegistry.registerBuilder(
declaration: classBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
void _createProperty({
required String name,
required UriOffsetLength uriOffset,
FieldDeclaration? fieldDeclaration,
GetterDeclaration? getterDeclaration,
List<GetterDeclaration>? getterAugmentationDeclarations,
SetterDeclaration? setterDeclaration,
List<SetterDeclaration>? setterAugmentationDeclarations,
required bool isStatic,
required bool inPatch,
}) {
_createPropertyBuilder(
name: name,
uriOffset: uriOffset,
fieldDeclaration: fieldDeclaration,
getterDeclaration: getterDeclaration,
getterAugmentations: getterAugmentationDeclarations ?? const [],
setterDeclaration: setterDeclaration,
setterAugmentations: setterAugmentationDeclarations ?? const [],
isStatic: isStatic,
inPatch: inPatch,
);
}
void _createPropertyBuilder({
required String name,
required UriOffsetLength uriOffset,
required FieldDeclaration? fieldDeclaration,
required GetterDeclaration? getterDeclaration,
required List<GetterDeclaration> getterAugmentations,
required SetterDeclaration? setterDeclaration,
required List<SetterDeclaration> setterAugmentations,
required bool isStatic,
required bool inPatch,
}) {
bool isInstanceMember =
_containerType != ContainerType.Library && !isStatic;
bool fieldIsLateWithLowering = false;
if (fieldDeclaration != null) {
fieldIsLateWithLowering =
fieldDeclaration.isLate &&
(_loader.target.backendTarget.isLateFieldLoweringEnabled(
hasInitializer: fieldDeclaration.hasInitializer,
isFinal: fieldDeclaration.isFinal,
isStatic: !isInstanceMember,
) ||
(_loader.target.backendTarget.useStaticFieldLowering &&
!isInstanceMember));
}
PropertyEncodingStrategy propertyEncodingStrategy =
new PropertyEncodingStrategy(
_declarationBuilder,
isInstanceMember: isInstanceMember,
);
NameScheme nameScheme = new NameScheme(
isInstanceMember: isInstanceMember,
containerName: _containerName,
containerType: _containerType,
libraryName: _indexedLibrary != null
? new LibraryName(_indexedLibrary.reference)
: _enclosingLibraryBuilder.libraryName,
);
IndexedContainer? indexedContainer = _indexedContainer ?? _indexedLibrary;
PropertyReferences references = new PropertyReferences(
name,
nameScheme,
indexedContainer,
fieldIsLateWithLowering: fieldIsLateWithLowering,
);
SourcePropertyBuilder propertyBuilder = new SourcePropertyBuilder(
fileUri: uriOffset.fileUri,
fileOffset: uriOffset.fileOffset,
name: name,
libraryBuilder: _enclosingLibraryBuilder,
declarationBuilder: _declarationBuilder,
fieldDeclaration: fieldDeclaration,
getterDeclaration: getterDeclaration,
getterAugmentations: getterAugmentations,
setterDeclaration: setterDeclaration,
setterAugmentations: setterAugmentations,
isStatic: isStatic,
nameScheme: nameScheme,
references: references,
);
fieldDeclaration?.createFieldEncoding(propertyBuilder);
getterDeclaration?.createGetterEncoding(
_problemReporting,
propertyBuilder,
propertyEncodingStrategy,
_typeParameterFactory,
);
for (GetterDeclaration augmentation in getterAugmentations) {
augmentation.createGetterEncoding(
_problemReporting,
propertyBuilder,
propertyEncodingStrategy,
_typeParameterFactory,
);
}
setterDeclaration?.createSetterEncoding(
_problemReporting,
propertyBuilder,
propertyEncodingStrategy,
_typeParameterFactory,
);
for (SetterDeclaration augmentation in setterAugmentations) {
augmentation.createSetterEncoding(
_problemReporting,
propertyBuilder,
propertyEncodingStrategy,
_typeParameterFactory,
);
}
references.registerReference(_loader.referenceMap, propertyBuilder);
_builderRegistry.registerBuilder(
declaration: propertyBuilder,
uriOffset: uriOffset,
inPatch: inPatch,
);
}
void _createTypedefBuilder(TypedefFragment fragment) {
List<SourceNominalParameterBuilder>? nominalParameters =
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
if (nominalParameters != null) {
for (SourceNominalParameterBuilder typeParameter in nominalParameters) {
typeParameter.varianceCalculationValue =
VarianceCalculationValue.pending;
}
}
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: fragment.name,
allowNameConflict: true,
);
Reference? reference = _indexedLibrary?.lookupTypedef(fragment.name);
SourceTypeAliasBuilder typedefBuilder = new SourceTypeAliasBuilder(
name: fragment.name,
enclosingLibraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
fileOffset: fragment.nameOffset,
fragment: fragment,
reference: reference,
);
if (reference != null) {
_loader.referenceMap.registerNamedBuilder(reference, typedefBuilder);
}
_builderRegistry.registerBuilder(
declaration: typedefBuilder,
uriOffset: fragment.uriOffset,
inPatch: fragment.enclosingCompilationUnit.isPatch,
);
}
}
abstract class BuilderRegistry {
void registerBuilder({
required NamedBuilder declaration,
required UriOffsetLength uriOffset,
required bool inPatch,
});
}
class EnumValuesDeclaration extends _PropertyDeclaration
implements SyntheticDeclaration {
EnumValuesDeclaration({
required String name,
required UriOffsetLength uriOffset,
required FieldDeclaration field,
required GetterDeclaration getter,
}) : super(
propertyKind: _PropertyKind.FinalField,
displayName: name,
isAugment: false,
inPatch: false,
inLibrary: false,
uriOffset: uriOffset,
declarations: new _PropertyDeclarations(field: field, getter: getter),
);
@override
_Declaration createDeclaration() {
return this;
}
@override
void reportDuplicateDeclaration(
ProblemReporting problemReporting,
_Declaration declaration,
) {
problemReporting.addProblem2(
codeEnumContainsValuesDeclaration,
declaration.uriOffset,
);
}
@override
void reportStaticInstanceConflict(
ProblemReporting problemReporting,
_PropertyDeclaration declaration,
) {
problemReporting.addProblem2(
codeInstanceAndSynthesizedStaticConflict.withArgumentsOld(displayName),
declaration.uriOffset,
);
}
@override
_PreBuilder _createPreBuilder() {
return new _PropertyPreBuilder.forField(this);
}
}
abstract class SyntheticDeclaration {
_Declaration createDeclaration();
}
sealed class _ConstructorDeclaration extends _Declaration {
final bool isConst;
@override
final UriOffsetLength uriOffset;
_ConstructorDeclaration(
super.kind, {
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required this.isConst,
required this.uriOffset,
});
@override
void registerPreBuilder(
ProblemReporting problemReporting,
List<_PreBuilder> nonConstructorPreBuilders,
List<_PreBuilder> constructorPreBuilders,
) {
_addPreBuilder(
problemReporting,
constructorPreBuilders,
nonConstructorPreBuilders,
);
}
}
/// [_PreBuilder] for generative and factory constructors.
sealed class _ConstructorPreBuilder<T extends _ConstructorDeclaration>
extends _PreBuilder {
final T _declaration;
final List<T> _augmentations = [];
// TODO(johnniwinther): Report error if [fragment] is augmenting.
_ConstructorPreBuilder(this._declaration);
@override
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration.isAugment) {
if (declaration is T && declaration.kind == _declaration.kind) {
// Example:
//
// class A {
// A();
// augment A();
// }
//
_augmentations.add(declaration);
return true;
} else {
// Example:
//
// class A {
// A();
// augment void A() {}
// }
//
// TODO(johnniwinther): Report augmentation conflict.
return false;
}
} else {
// Example:
//
// class A {
// A();
// A();
// }
//
_declaration.reportDuplicateDeclaration(problemReporting, declaration);
return false;
}
}
@override
void checkFragment(
ProblemReporting problemReporting,
_Declaration nonConstructorDeclaration,
) {
// Check conflict with non-constructor.
if (nonConstructorDeclaration.isStatic) {
// Examples:
//
// class A {
// A.foo();
// static void foo() {}
// }
//
// and
//
// class A {
// factory A.foo() => throw '';
// static void foo() {}
// }
//
_declaration.reportConstructorConflict(
problemReporting,
nonConstructorDeclaration,
);
}
}
}
abstract class _Declaration {
final _DeclarationKind kind;
final String displayName;
final bool isAugment;
final bool inPatch;
final bool inLibrary;
final bool isStatic;
_Declaration(
this.kind, {
required this.displayName,
required this.isAugment,
required this.inPatch,
required this.inLibrary,
this.isStatic = true,
});
UriOffsetLength get uriOffset;
void registerPreBuilder(
ProblemReporting problemReporting,
List<_PreBuilder> nonConstructorPreBuilders,
List<_PreBuilder> constructorPreBuilders,
);
void reportConstructorConflict(
ProblemReporting problemReporting,
_Declaration declaration,
);
/// Reports that [declaration] conflicts with this declaration.
void reportDuplicateDeclaration(
ProblemReporting problemReporting,
_Declaration declaration,
);
/// Adds this declaration to [thesePreBuilders] and checks it against the
/// [otherPreBuilders].
///
/// If this declaration can be absorbed into an existing declaration in
/// [thesePreBuilders], it is added to the corresponding [_PreBuilder].
/// Otherwise a new [_PreBuilder] is created and added to [thesePreBuilders].
void _addPreBuilder(
ProblemReporting problemReporting,
List<_PreBuilder> thesePreBuilders,
List<_PreBuilder> otherPreBuilders,
) {
for (_PreBuilder existingPreBuilder in thesePreBuilders) {
if (existingPreBuilder.absorbFragment(problemReporting, this)) {
return;
}
}
_checkAugmentation(problemReporting, this);
thesePreBuilders.add(_createPreBuilder());
if (otherPreBuilders.isNotEmpty) {
otherPreBuilders.first.checkFragment(problemReporting, this);
}
}
/// Creates the [_PreBuilder] for this [_Declaration].
///
/// This is called for the declarations that aren't absorbed into a
/// pre-existing declaration.
_PreBuilder _createPreBuilder();
}
enum _DeclarationKind {
Constructor,
Factory,
Class,
Mixin,
NamedMixinApplication,
Enum,
Extension,
ExtensionType,
Typedef,
Method,
Property,
}
/// [_PreBuilder] for non-constructor, non-property declarations.
class _DeclarationPreBuilder extends _PreBuilder {
final _StandardDeclaration _declaration;
final List<_StandardDeclaration> _augmentations = [];
// TODO(johnniwinther): Report error if [fragment] is augmenting.
_DeclarationPreBuilder(this._declaration);
@override
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration.isAugment) {
if (declaration.kind == _declaration.kind) {
// Example:
//
// class Foo {}
// augment class Foo {}
//
_augmentations.add(declaration as _StandardDeclaration);
return true;
} else {
// Example:
//
// class Foo {}
// augment extension Foo {}
//
// TODO(johnniwinther): Report augmentation conflict.
return false;
}
} else {
// Examples:
//
// class Foo {}
// set Foo(_) {}
//
// and
//
// class Foo {}
// class Foo {}
//
_declaration.reportDuplicateDeclaration(problemReporting, declaration);
return false;
}
}
@override
void checkFragment(
ProblemReporting problemReporting,
_Declaration constructorDeclaration,
) {
// Check conflict with constructor.
if (_declaration.isStatic) {
// Examples:
//
// class A {
// static void foo() {}
// A.foo();
// }
//
// and
//
// class A {
// static void foo() {}
// factory A.foo() => throw '';
// }
//
_declaration.reportConstructorConflict(
problemReporting,
constructorDeclaration,
);
}
}
@override
void createBuilders(BuilderFactory builderFactory) {
builderFactory._createBuilder(
_declaration._fragment,
augmentations: _augmentations.map((f) => f._fragment).toList(),
);
}
}
mixin _DeclarationReportingMixin implements _Declaration {
@override
void reportDuplicateDeclaration(
ProblemReporting problemReporting,
_Declaration declaration,
) {
// TODO(johnniwinther): Mark [declaration] as a duplicate so we don't
// report duplicates on duplicates.
_reportDuplicateDeclaration(
problemReporting,
name: displayName,
existingUriOffset: uriOffset,
newUriOffset: declaration.uriOffset,
existingKind: _getExistingKindForDuplicate(declaration),
newIsSetter:
declaration is _PropertyDeclaration &&
declaration.propertyKind == _PropertyKind.Setter,
);
}
_ExistingKind _getExistingKindForDuplicate(_Declaration declaration) =>
_ExistingKind.Getable;
void _reportDuplicateDeclaration(
ProblemReporting problemReporting, {
required String name,
required UriOffsetLength existingUriOffset,
required UriOffsetLength newUriOffset,
required _ExistingKind existingKind,
required bool newIsSetter,
}) {
switch (existingKind) {
case _ExistingKind.Getable:
if (newIsSetter) {
problemReporting.addProblem2(
codeSetterConflictsWithDeclaration.withArgumentsOld(name),
newUriOffset,
context: [
codeSetterConflictsWithDeclarationCause
.withArgumentsOld(name)
.withLocation2(existingUriOffset),
],
);
return;
}
break;
case _ExistingKind.ExplicitSetter:
if (!newIsSetter) {
problemReporting.addProblem2(
codeDeclarationConflictsWithSetter.withArgumentsOld(name),
newUriOffset,
context: <LocatedMessage>[
codeDeclarationConflictsWithSetterCause
.withArgumentsOld(name)
.withLocation2(existingUriOffset),
],
);
return;
}
break;
case _ExistingKind.ImplicitSetter:
problemReporting.addProblem2(
codeConflictsWithImplicitSetter.withArgumentsOld(name),
newUriOffset,
context: [
codeConflictsWithImplicitSetterCause
.withArgumentsOld(name)
.withLocation2(existingUriOffset),
],
);
return;
}
problemReporting.addProblem2(
codeDuplicatedDeclaration.withArgumentsOld(name),
newUriOffset,
context: <LocatedMessage>[
codeDuplicatedDeclarationCause
.withArgumentsOld(name)
.withLocation2(existingUriOffset),
],
);
}
}
enum _ExistingKind { Getable, ExplicitSetter, ImplicitSetter }
class _FactoryConstructorDeclaration extends _ConstructorDeclaration
with _DeclarationReportingMixin {
final String _name;
final FactoryDeclaration _declaration;
_FactoryConstructorDeclaration(
this._declaration, {
required String name,
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required super.isConst,
required super.uriOffset,
}) : _name = name,
super(_DeclarationKind.Factory);
@override
void reportConstructorConflict(
ProblemReporting problemReporting,
_Declaration nonConstructorDeclaration,
) {
// Example:
//
// class A {
// factory A.foo() => throw '';
// static void foo() {}
// }
//
problemReporting.addProblem2(
codeMemberConflictsWithFactory.withArgumentsOld(displayName),
nonConstructorDeclaration.uriOffset,
context: [
codeMemberConflictsWithFactoryCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
}
@override
_PreBuilder _createPreBuilder() =>
new _FactoryConstructorPreBuilder(_name, this);
}
class _FactoryConstructorPreBuilder
extends _ConstructorPreBuilder<_FactoryConstructorDeclaration> {
final String _name;
_FactoryConstructorPreBuilder(this._name, super._declaration);
@override
void createBuilders(BuilderFactory builderFactory) {
builderFactory._createFactoryBuilderFromDeclarations(
_declaration._declaration,
_augmentations.map((a) => a._declaration).toList(),
name: _name,
uriOffset: _declaration.uriOffset,
isConst: _declaration.isConst,
inPatch: _declaration.inPatch,
);
}
}
class _FieldDeclaration extends _PropertyDeclaration
with _DeclarationReportingMixin {
_FieldDeclaration({
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required super.propertyKind,
required super.declarations,
required super.uriOffset,
super.isStatic,
});
@override
_PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forField(this);
@override
_ExistingKind _getExistingKindForDuplicate(_Declaration declaration) {
bool newIsSetter =
declaration is _PropertyDeclaration &&
declaration.propertyKind == _PropertyKind.Setter;
return newIsSetter ? _ExistingKind.ImplicitSetter : _ExistingKind.Getable;
}
}
mixin _FragmentDeclarationMixin implements _Declaration {
@override
UriOffsetLength get uriOffset => _fragment.uriOffset;
Fragment get _fragment;
@override
String toString() => _fragment.toString();
}
class _GenerativeConstructorDeclaration extends _ConstructorDeclaration
with _DeclarationReportingMixin {
final String _name;
final ConstructorDeclaration _declaration;
_GenerativeConstructorDeclaration(
this._declaration, {
required String name,
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required super.isConst,
required super.uriOffset,
}) : _name = name,
super(_DeclarationKind.Constructor);
@override
void reportConstructorConflict(
ProblemReporting problemReporting,
_Declaration nonConstructorDeclaration,
) {
// Example:
//
// class A {
// A.foo();
// static void foo() {}
// }
//
problemReporting.addProblem2(
codeMemberConflictsWithConstructor.withArgumentsOld(displayName),
nonConstructorDeclaration.uriOffset,
context: [
codeMemberConflictsWithConstructorCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
}
@override
_PreBuilder _createPreBuilder() =>
new _GenerativeConstructorPreBuilder(_name, this);
}
class _GenerativeConstructorPreBuilder
extends _ConstructorPreBuilder<_GenerativeConstructorDeclaration> {
final String _name;
_GenerativeConstructorPreBuilder(this._name, super._declaration);
@override
void createBuilders(BuilderFactory builderFactory) {
builderFactory._createConstructorBuilderFromDeclarations(
_declaration._declaration,
_augmentations.map((a) => a._declaration).toList(),
name: _name,
uriOffset: _declaration.uriOffset,
isConst: _declaration.isConst,
inPatch: _declaration.inPatch,
);
}
}
class _GetterDeclaration extends _PropertyDeclaration
with _DeclarationReportingMixin {
_GetterDeclaration({
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required super.propertyKind,
required super.declarations,
required super.uriOffset,
super.isStatic,
});
@override
_PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forGetter(this);
}
abstract class _NonConstructorDeclaration extends _Declaration {
_NonConstructorDeclaration(
super.kind, {
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
super.isStatic,
});
@override
void registerPreBuilder(
ProblemReporting problemReporting,
List<_PreBuilder> nonConstructorPreBuilders,
List<_PreBuilder> constructorPreBuilders,
) {
_addPreBuilder(
problemReporting,
nonConstructorPreBuilders,
constructorPreBuilders,
);
}
@override
void reportConstructorConflict(
ProblemReporting problemReporting,
_Declaration constructorDeclaration,
) {
if (constructorDeclaration.kind == _DeclarationKind.Constructor) {
// Example:
//
// class A {
// static int get foo => 42;
// A.foo();
// }
//
problemReporting.addProblem2(
codeConstructorConflictsWithMember.withArgumentsOld(displayName),
constructorDeclaration.uriOffset,
context: [
codeConstructorConflictsWithMemberCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
} else {
assert(
constructorDeclaration.kind == _DeclarationKind.Factory,
"Unexpected constructor kind $constructorDeclaration",
);
// Example:
//
// class A {
// static int get foo => 42;
// factory A.foo() => throw '';
// }
//
problemReporting.addProblem2(
codeFactoryConflictsWithMember.withArgumentsOld(displayName),
constructorDeclaration.uriOffset,
context: [
codeFactoryConflictsWithMemberCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
}
}
}
/// A [_PreBuilder] is a precursor to a [Builder] with subclasses for
/// properties, constructors, and other declarations.
sealed class _PreBuilder {
/// Tries to include [declaration] in this [_PreBuilder].
///
/// If [declaration] can be absorbed, `true` is returned. Otherwise an error
/// is reported and `false` is returned.
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
);
/// Checks with [declaration] conflicts with this [_PreBuilder].
///
/// This is called between constructors and non-constructors which do not
/// occupy the same name space but can only co-exist if the non-constructor
/// is not static.
void checkFragment(
ProblemReporting problemReporting,
_Declaration declaration,
);
/// Creates [Builder]s for the fragments absorbed into this [_PreBuilder],
/// using [BuilderFactory] to create a [Builder] for a single [Fragment].
///
/// If `conflictingSetter` is `true`, the created [Builder] must be marked
/// as a conflicting setter. This is needed to ensure that we don't create
/// conflicting AST nodes: Normally we only create [Builder]s for
/// non-duplicate declarations, but because setters are store in a separate
/// map the [NameSpace], they are not directly marked as duplicate if they
/// do not conflict with other setters.
void createBuilders(BuilderFactory builderFactory);
}
abstract class _PropertyDeclaration extends _NonConstructorDeclaration {
final _PropertyKind propertyKind;
final _PropertyDeclarations declarations;
@override
final UriOffsetLength uriOffset;
_PropertyDeclaration({
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required this.propertyKind,
required this.declarations,
required this.uriOffset,
super.isStatic,
}) : super(_DeclarationKind.Property);
void reportStaticInstanceConflict(
ProblemReporting problemReporting,
_PropertyDeclaration declaration,
) {
if (isStatic) {
problemReporting.addProblem2(
codeInstanceConflictsWithStatic.withArgumentsOld(displayName),
declaration.uriOffset,
context: [
codeInstanceConflictsWithStaticCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
} else {
problemReporting.addProblem2(
codeStaticConflictsWithInstance.withArgumentsOld(displayName),
declaration.uriOffset,
context: [
codeStaticConflictsWithInstanceCause
.withArgumentsOld(displayName)
.withLocation2(uriOffset),
],
);
}
}
}
class _PropertyDeclarations {
final FieldDeclaration? field;
final GetterDeclaration? getter;
final SetterDeclaration? setter;
_PropertyDeclarations({this.field, this.getter, this.setter});
}
enum _PropertyKind { Getter, Setter, Field, FinalField }
/// [_PreBuilder] for properties, i.e. fields, getters and setters.
class _PropertyPreBuilder extends _PreBuilder {
final bool inPatch;
final String name;
final UriOffsetLength uriOffset;
final bool isStatic;
_PropertyDeclaration? _getterDeclaration;
_PropertyDeclaration? _setterDeclaration;
List<GetterDeclaration> _getterAugmentations = [];
List<SetterDeclaration> _setterAugmentations = [];
// TODO(johnniwinther): Report error if [field] is augmenting.
_PropertyPreBuilder.forField(_PropertyDeclaration field)
: isStatic = field.isStatic,
inPatch = field.inPatch,
name = field.displayName,
uriOffset = field.uriOffset,
_getterDeclaration = field,
_setterDeclaration = field.propertyKind == _PropertyKind.Field
? field
: null {
_PropertyDeclarations declarations = field.declarations;
assert(
declarations.field != null,
"Unexpected field declaration from field ${field}.",
);
assert(
declarations.getter != null,
"Unexpected getter declaration from field ${field}.",
);
assert(
(declarations.setter != null) ==
(_getterDeclaration!.propertyKind == _PropertyKind.Field),
"Unexpected setter declaration from field ${field}.",
);
}
// TODO(johnniwinther): Report error if [getter] is augmenting.
_PropertyPreBuilder.forGetter(_PropertyDeclaration getter)
: isStatic = getter.isStatic,
inPatch = getter.inPatch,
name = getter.displayName,
uriOffset = getter.uriOffset,
_getterDeclaration = getter {
_PropertyDeclarations declarations = getter.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from getter ${getter}.",
);
assert(
declarations.getter != null,
"Unexpected getter declaration from getter ${getter}.",
);
assert(
declarations.setter == null,
"Unexpected setter declaration from getter ${getter}.",
);
}
// TODO(johnniwinther): Report error if [setter] is augmenting.
_PropertyPreBuilder.forSetter(_PropertyDeclaration setter)
: isStatic = setter.isStatic,
inPatch = setter.inPatch,
name = setter.displayName,
uriOffset = setter.uriOffset,
_setterDeclaration = setter {
_PropertyDeclarations declarations = setter.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from setter ${setter}.",
);
assert(
declarations.getter == null,
"Unexpected getter declaration from setter ${setter}.",
);
assert(
declarations.setter != null,
"Unexpected setter declaration from setter ${setter}.",
);
}
@override
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration is! _PropertyDeclaration) {
if (_getterDeclaration != null) {
// Example:
//
// int get foo => 42;
// void foo() {}
//
_getterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
} else {
assert(_setterDeclaration != null);
// Example:
//
// void set foo(_) {}
// void foo() {}
//
_setterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
}
return false;
}
_PropertyKind? propertyKind = declaration.propertyKind;
switch (propertyKind) {
case _PropertyKind.Getter:
if (_getterDeclaration == null) {
// Example:
//
// void set foo(_) {}
// int get foo => 42;
//
if (declaration.isAugment) {
// Example:
//
// void set foo(_) {}
// augment int get foo => 42;
//
// TODO(johnniwinther): Report error.
}
if (declaration.isStatic != isStatic) {
// Examples:
//
// class A {
// void set foo(_) {}
// static int get foo => 42;
// }
//
// and
//
// class A {
// static void set foo(_) {}
// int get foo => 42;
// }
//
_setterDeclaration!.reportStaticInstanceConflict(
problemReporting,
declaration,
);
return false;
} else {
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from getter "
"${declaration}.",
);
assert(
declarations.setter == null,
"Unexpected setter declaration from getter "
"${declaration}.",
);
_getterDeclaration = declaration;
return true;
}
} else {
if (declaration.isAugment) {
// Example:
//
// int get foo => 42;
// augment int get foo => 87;
//
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from getter "
"${declaration}.",
);
assert(
declarations.setter == null,
"Unexpected setter declaration from getter "
"${declaration}.",
);
_getterAugmentations.add(declarations.getter!);
return true;
} else {
// Example:
//
// int get foo => 42;
// int get foo => 87;
//
_getterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
case _PropertyKind.Setter:
if (_setterDeclaration == null) {
// Examples:
//
// int get foo => 42;
// void set foo(_) {}
//
// final int bar = 42;
// void set bar(_) {}
//
if (declaration.isAugment) {
// Example:
//
// int get foo => 42;
// augment void set foo(_) {}
//
// TODO(johnniwinther): Report error.
}
if (declaration.isStatic != isStatic) {
// Examples:
//
// class A {
// int get foo => 42;
// static void set foo(_) {}
// }
//
// and
//
// class A {
// static int get foo => 42;
// void set foo(_) {}
// }
//
_getterDeclaration!.reportStaticInstanceConflict(
problemReporting,
declaration,
);
return false;
} else {
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from setter "
"${declaration}.",
);
assert(
declarations.getter == null,
"Unexpected getter declaration from setter "
"${declaration}.",
);
_setterDeclaration = declaration;
return true;
}
} else {
if (declaration.isAugment) {
// Example:
//
// void set foo(_) {}
// augment void set foo(_) {}
//
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.field == null,
"Unexpected field declaration from setter "
"${declaration}.",
);
assert(
declarations.getter == null,
"Unexpected getter declaration from setter "
"${declaration}.",
);
_setterAugmentations.add(declarations.setter!);
return true;
} else {
// Examples:
//
// int? foo;
// void set foo(_) {}
//
// and
//
// void set foo(_) {}
// void set foo(_) {}
//
_setterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
case _PropertyKind.Field:
if (_getterDeclaration == null) {
// Example:
//
// void set foo(_) {}
// int? foo;
//
assert(_getterDeclaration == null && _setterDeclaration != null);
// We have an explicit setter.
_setterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
} else if (_setterDeclaration != null) {
// Examples:
//
// int? foo;
// int? foo;
//
// int get bar => 42;
// void set bar(_) {}
// int bar = 87;
//
// final int baz = 42;
// void set baz(_) {}
// int baz = 87;
//
assert(_getterDeclaration != null && _setterDeclaration != null);
// We have both getter and setter
if (declaration.isAugment) {
// Coverage-ignore-block(suite): Not run.
if (_getterDeclaration!.propertyKind == declaration.propertyKind) {
// Example:
//
// int foo = 42;
// augment int foo = 87;
//
_PropertyDeclarations declarations = declaration.declarations;
// TODO(johnniwinther): Handle field augmentation.
_getterAugmentations.add(declarations.getter!);
_setterAugmentations.add(declarations.setter!);
return true;
} else {
// Example:
//
// final int foo = 42;
// void set foo(_) {}
// augment int foo = 87;
//
// TODO(johnniwinther): Report error.
// TODO(johnniwinther): Should the augment be absorbed in this
// case, as an erroneous augmentation?
return false;
}
} else {
// Examples:
//
// int? foo;
// int? foo;
//
// int? get bar => null;
// void set bar(_) {}
// int? bar;
//
_getterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
} else {
// Examples:
//
// int get foo => 42;
// int? foo;
//
// final int bar = 42;
// int? bar;
//
assert(_getterDeclaration != null && _setterDeclaration == null);
_getterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
case _PropertyKind.FinalField:
if (_getterDeclaration == null) {
// Example:
//
// void set foo(_) {}
// final int foo = 42;
//
assert(_getterDeclaration == null && _setterDeclaration != null);
// We have an explicit setter.
if (declaration.isAugment) {
// Example:
//
// void set foo(_) {}
// augment final int foo = 42;
//
// TODO(johnniwinther): Report error.
}
if (declaration.isStatic != isStatic) {
// Coverage-ignore-block(suite): Not run.
// Examples:
//
// class A {
// void set foo(_) {}
// static final int foo = 42;
// }
//
// and
//
// class A {
// static void set foo(_) {}
// final int foo = 42;
// }
//
_setterDeclaration!.reportStaticInstanceConflict(
problemReporting,
declaration,
);
return false;
} else {
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.setter == null,
"Unexpected setter declaration from field "
"${declaration}.",
);
_getterDeclaration = declaration;
return true;
}
} else {
// Examples:
//
// final int foo = 42;
// final int foo = 87;
//
// int get bar => 42;
// final int bar = 87;
//
if (declaration.isAugment) {
// Coverage-ignore-block(suite): Not run.
if (_getterDeclaration!.propertyKind == declaration.propertyKind) {
// Example:
//
// final int foo = 42;
// augment final int foo = 87;
//
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.setter == null,
"Unexpected setter declaration from final field "
"${declaration}.",
);
// TODO(johnniwinther): Handle field augmentation.
_getterAugmentations.add(declarations.getter!);
return true;
} else {
// Example:
//
// int foo = 42;
// augment final int foo = 87;
//
// TODO(johnniwinther): Report error.
// TODO(johnniwinther): Should the augment be absorbed in this
// case, as an erroneous augmentation?
return false;
}
} else {
// Examples:
//
// final int foo = 42;
// final int foo = 87;
//
// int get bar => 42;
// final int bar = 87;
//
_getterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
}
}
@override
void checkFragment(
ProblemReporting problemReporting,
_Declaration constructorDeclaration,
) {
// Check conflict with constructor.
if (isStatic) {
if (_getterDeclaration != null) {
// Examples:
//
// class A {
// static int get foo => 42;
// A.foo();
// }
//
// and
//
// class A {
// static int get foo => 42;
// factory A.foo() => throw '';
// }
//
_getterDeclaration!.reportConstructorConflict(
problemReporting,
constructorDeclaration,
);
} else {
// Coverage-ignore-block(suite): Not run.
// Examples:
//
// class A {
// static void set foo(_) {}
// A.foo();
// }
//
// and
//
// class A {
// static void set foo(_) {}
// factory A.foo() => throw '';
// }
//
_setterDeclaration!.reportConstructorConflict(
problemReporting,
constructorDeclaration,
);
}
}
}
@override
void createBuilders(BuilderFactory builderFactory) {
builderFactory._createProperty(
name: name,
inPatch: inPatch,
isStatic: isStatic,
uriOffset: uriOffset,
fieldDeclaration: _getterDeclaration?.declarations.field,
getterDeclaration: _getterDeclaration?.declarations.getter,
getterAugmentationDeclarations: _getterAugmentations,
setterDeclaration: _setterDeclaration?.declarations.setter,
setterAugmentationDeclarations: _setterAugmentations,
);
}
}
class _SetterDeclaration extends _PropertyDeclaration
with _DeclarationReportingMixin {
_SetterDeclaration({
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
required super.propertyKind,
required super.declarations,
required super.uriOffset,
super.isStatic,
});
@override
_PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forSetter(this);
@override
_ExistingKind _getExistingKindForDuplicate(_Declaration declaration) {
return _ExistingKind.ExplicitSetter;
}
}
abstract class _StandardDeclaration extends _NonConstructorDeclaration {
_StandardDeclaration(
super.kind, {
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
super.isStatic,
});
// TODO(johnniwinther): Remove this.
Fragment get _fragment;
}
class _StandardFragmentDeclaration extends _StandardDeclaration
with
_DeclarationReportingMixin,
_FragmentDeclarationMixin,
_StandardFragmentDeclarationMixin {
@override
final Fragment _fragment;
_StandardFragmentDeclaration(
super.kind,
this._fragment, {
required super.displayName,
required super.isAugment,
required super.inPatch,
required super.inLibrary,
super.isStatic,
});
@override
_PreBuilder _createPreBuilder() => new _DeclarationPreBuilder(this);
}
mixin _StandardFragmentDeclarationMixin implements _StandardDeclaration {
@override
Fragment get _fragment;
}