blob: d2ab27518385a7f2874e3a35509277d19e42d023 [file]
// 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' hide ExtensionTypeDeclaration;
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/property_builder.dart';
import '../builder/type_builder.dart';
import '../codes/diagnostic.dart' as diag;
import '../fragment/constructor/declaration.dart';
import '../fragment/constructor/encoding.dart';
import '../fragment/extension/declaration.dart';
import '../fragment/extension_type/declaration.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 'nominal_parameter_name_space.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
? diag.unmatchedPatchClass.withArguments(
className: declaration.displayName,
)
: diag.unmatchedAugmentationClass.withArguments(
className: declaration.displayName,
);
case _DeclarationKind.Constructor:
case _DeclarationKind.Factory:
case _DeclarationKind.Method:
case _DeclarationKind.Property:
if (declaration.inLibrary) {
message = declaration.inPatch
? diag.unmatchedPatchLibraryMember.withArguments(
memberName: declaration.displayName,
)
: diag.unmatchedAugmentationLibraryMember.withArguments(
memberName: declaration.displayName,
);
} else {
message = declaration.inPatch
? diag.unmatchedPatchClassMember.withArguments(
memberName: declaration.displayName,
)
: diag.unmatchedAugmentationClassMember.withArguments(
memberName: declaration.displayName,
);
}
case _DeclarationKind.Mixin:
case _DeclarationKind.NamedMixinApplication:
case _DeclarationKind.Enum:
case _DeclarationKind.Extension:
case _DeclarationKind.ExtensionType:
// Coverage-ignore(suite): Not run.
case _DeclarationKind.Typedef:
// TODO(johnniwinther): Specialize more messages.
message = declaration.inPatch
? diag.unmatchedPatchDeclaration.withArguments(
declarationName: declaration.displayName,
)
: diag.unmatchedAugmentationDeclaration.withArguments(
declarationName: 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;
new({
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<PrimaryConstructorBodyFragment>? primaryConstructorBodies,
}) {
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,
primaryConstructorBodies: primaryConstructorBodies,
);
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():
_createClassBuilderFromFragments(fragment, augmentations);
case MixinFragment():
_createMixinBuilderFromFragments(fragment, augmentations);
case NamedMixinApplicationFragment():
_createNamedMixinApplicationBuilder(fragment);
case EnumFragment():
_createEnumBuilderFromFragments(fragment, augmentations);
case ExtensionFragment():
_createExtensionBuilderFromFragments(fragment, augmentations);
case ExtensionTypeFragment():
_createExtensionTypeBuilderFragments(fragment, augmentations);
case MethodFragment():
_createMethodBuilder(fragment, augmentations);
// Coverage-ignore(suite): Not run.
case ConstructorFragment():
case PrimaryConstructorFragment():
case PrimaryConstructorBodyFragment():
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);
}
}
}
/// Connects [augmentationTypeParameters] type parameters with the
/// [nominalParameters] declared in the introductory fragment.
///
/// If there is mismatch in number of type parameters an error is reported
/// using [typeParametersMismatchMessage] and
/// [typeParameterIntroductoryMessage] and synthetic type parameters
/// corresponding to the [nominalParameters] are created for the augmentation.
///
/// The type parameters, declared or synthesized, are added to
/// [augmentationNominalParameterNameSpace].
void _augmentTypeParameters({
required List<TypeParameterFragment>? augmentationTypeParameters,
required NominalParameterNameSpace augmentationNominalParameterNameSpace,
required List<SourceNominalParameterBuilder>? nominalParameters,
required String declarationName,
required UriOffsetLength introductionUriOffset,
required UriOffsetLength augmentationUriOffset,
required MessageCode typeParametersMismatchMessage,
required MessageCode typeParameterIntroductoryMessage,
}) {
int introductoryTypeParameterCount = nominalParameters?.length ?? 0;
int augmentationTypeParameterCount =
augmentationTypeParameters?.length ?? 0;
if (introductoryTypeParameterCount != augmentationTypeParameterCount) {
_problemReporting.addProblem2(
typeParametersMismatchMessage,
augmentationUriOffset,
context: [
typeParameterIntroductoryMessage.withLocation2(introductionUriOffset),
],
);
// Error recovery. Create fresh type parameters for the
// augmentation.
augmentationNominalParameterNameSpace.addTypeParameters(
_problemReporting,
_typeParameterFactory.createNominalParameterBuilders(
augmentationTypeParameters,
),
ownerName: declarationName,
allowNameConflict: false,
);
} else if (augmentationTypeParameters != null) {
for (int index = 0; index < introductoryTypeParameterCount; index++) {
SourceNominalParameterBuilder nominalParameterBuilder =
nominalParameters![index];
TypeParameterFragment typeParameterFragment =
augmentationTypeParameters[index];
nominalParameterBuilder.addAugmentingDeclaration(
new RegularNominalParameterDeclaration(typeParameterFragment),
);
typeParameterFragment.builder = nominalParameterBuilder;
}
augmentationNominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: declarationName,
allowNameConflict: false,
);
}
}
/// Creates the declaration objects for the [introductory] fragment and each
/// fragment in [augmentations], and uses these to create the builder object.
///
/// The name spaces of the [introductory] fragment and [augmentations] are
/// merged such that member fragments in augmentations are handled together
/// with the member fragments declared in the introductory fragment.
///
/// Type parameters are merged between the [introductory] fragment and the
/// [augmentations].
///
/// [reference] is the [Reference] used for the kernel node corresponding to
/// the builder object in a previous incremental compilation.
/// [createDeclaration] is used to create the declaration for a fragment.
/// [createBuilder] is used to create the builder object from the
///
/// [typeParametersMismatchMessage] and [typeParametersIntroductoryMessage]
/// are used for reporting type parameter mismatches in
/// [_augmentTypeParameters].
void _createDeclarationBuilder<
F extends DeclarationFragmentImpl,
D,
B extends DeclarationBuilder
>({
required F introductory,
required List<Fragment>? augmentations,
required Reference? reference,
required D Function(F) createDeclaration,
required B Function({
required DeclarationNameSpaceBuilder nameSpaceBuilder,
required List<SourceNominalParameterBuilder>? nominalParameters,
required D introductory,
required List<D> augmentations,
required Modifiers modifiers,
})
createBuilder,
required void Function(F fragment, B builder) setBuilder,
required MessageCode typeParametersMismatchMessage,
required MessageCode typeParametersIntroductoryMessage,
}) {
String name = introductory.name;
DeclarationNameSpaceBuilder nameSpaceBuilder = introductory
.toDeclarationNameSpaceBuilder();
D introductoryDeclaration = createDeclaration(introductory);
List<SourceNominalParameterBuilder>? nominalParameters =
_typeParameterFactory.createNominalParameterBuilders(
introductory.typeParameters,
);
introductory.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
nominalParameters,
ownerName: name,
allowNameConflict: false,
);
Modifiers modifiers = introductory.modifiers;
List<D> augmentationDeclarations = [];
if (augmentations != null) {
for (Fragment fragment in augmentations) {
F augmentation = fragment as F;
// TODO(johnniwinther): Check that other modifiers are consistent.
if (augmentation.modifiers.declaresConstConstructor) {
modifiers |= Modifiers.DeclaresConstConstructor;
}
augmentationDeclarations.add(createDeclaration(augmentation));
nameSpaceBuilder.includeFragments(
augmentation.toDeclarationNameSpaceBuilder(),
);
_augmentTypeParameters(
declarationName: name,
introductionUriOffset: introductory.uriOffset,
augmentationUriOffset: augmentation.uriOffset,
nominalParameters: nominalParameters,
augmentationNominalParameterNameSpace:
augmentation.nominalParameterNameSpace,
augmentationTypeParameters: augmentation.typeParameters,
typeParametersMismatchMessage: typeParametersMismatchMessage,
typeParameterIntroductoryMessage: typeParametersIntroductoryMessage,
);
}
}
B builder = createBuilder(
nameSpaceBuilder: nameSpaceBuilder,
nominalParameters: nominalParameters,
introductory: introductoryDeclaration,
augmentations: augmentationDeclarations,
modifiers: modifiers,
);
setBuilder(introductory, builder);
introductory.bodyScope.declarationBuilder = builder;
if (augmentations != null) {
for (Fragment fragment in augmentations) {
F augmentation = fragment as F;
setBuilder(augmentation, builder);
augmentation.bodyScope.declarationBuilder = builder;
}
augmentations.clear();
}
if (reference != null) {
_loader.referenceMap.registerNamedBuilder(reference, builder);
}
_builderRegistry.registerBuilder(
declaration: builder,
uriOffset: introductory.uriOffset,
inPatch: introductory.enclosingCompilationUnit.isPatch,
);
}
void _createClassBuilderFromFragments(
ClassFragment fragment,
List<Fragment>? augmentations,
) {
TypeBuilder? supertypeBuilder = fragment.supertype;
List<TypeBuilder>? mixedInTypeBuilders = fragment.mixins?.toList();
List<TypeBuilder>? interfaceBuilders = fragment.interfaces?.toList();
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
augmentation as ClassFragment;
TypeBuilder? augmentationSupertype = augmentation.supertype;
if (augmentationSupertype != null) {
if (supertypeBuilder != null) {
_problemReporting.addProblem(
diag.augmentationExtendsClauseAlreadyPresent,
augmentationSupertype.charOffset!,
noLength,
augmentationSupertype.fileUri,
context: [
diag.augmentationExtendsClassAlreadyPresentCause.withLocation(
supertypeBuilder.fileUri!,
supertypeBuilder.charOffset!,
noLength,
),
],
);
} else {
supertypeBuilder = augmentationSupertype;
}
}
List<TypeBuilder>? augmentationMixedInTypeBuilders =
augmentation.mixins;
if (augmentationMixedInTypeBuilders != null) {
(mixedInTypeBuilders ??= []).addAll(augmentationMixedInTypeBuilders);
}
List<TypeBuilder>? augmentationInterfaceBuilders =
augmentation.interfaces;
if (augmentationInterfaceBuilders != null) {
(interfaceBuilders ??= []).addAll(augmentationInterfaceBuilders);
}
}
}
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(
fragment.name,
);
_createDeclarationBuilder(
introductory: fragment,
augmentations: augmentations,
reference: indexedClass?.reference,
createDeclaration: RegularClassDeclaration.new,
createBuilder:
({
required nameSpaceBuilder,
required nominalParameters,
required augmentations,
required introductory,
required modifiers,
}) => new SourceClassBuilder(
modifiers: modifiers,
name: fragment.name,
typeParameters: nominalParameters,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: indexedClass,
introductory: introductory,
augmentations: augmentations,
supertypeBuilder: supertypeBuilder,
mixedInTypeBuilders: mixedInTypeBuilders,
interfaceBuilders: interfaceBuilders,
),
setBuilder: (fragment, builder) => fragment.builder = builder,
// TODO(johnniwinther): Use a distinct message for patch/augmentation
// and different kinds of declarations.
typeParametersMismatchMessage: diag.patchClassTypeParametersMismatch,
typeParametersIntroductoryMessage: diag.patchClassOrigin,
);
}
void _createConstructorBuilderFromDeclarations(
ConstructorDeclaration introductory,
List<ConstructorDeclaration> augmentations, {
required String name,
required UriOffsetLength uriOffset,
required bool isConst,
required bool inPatch,
}) {
List<ConstructorDeclaration> declarations = [introductory];
ConstructorDeclaration implementation = introductory;
if (augmentations.isNotEmpty) {
declarations.addAll(augmentations);
for (ConstructorDeclaration augmentation in augmentations) {
// TODO(johnniwinther): Support implementing an external constructor
// with an incomplete patch constructor like
//
// class C { external new(); }
// @patch class C { @patch new(); }
//
if (augmentation.isComplete) {
implementation = augmentation;
}
}
}
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!,
isClosureContextLoweringEnabled:
_loader.isClosureContextLoweringEnabled,
);
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,
declarations: declarations,
implementation: implementation,
isConst: isConst,
);
constructorReferences.registerReference(
_loader.referenceMap,
constructorBuilder,
);
for (ConstructorDeclaration declaration in declarations) {
declaration.createEncoding(
problemReporting: _problemReporting,
loader: _loader,
declarationBuilder: _declarationBuilder,
constructorBuilder: constructorBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
isImplementation: declaration == implementation,
);
}
_builderRegistry.registerBuilder(
declaration: constructorBuilder,
uriOffset: uriOffset,
inPatch: inPatch,
);
}
_Declaration? _createDeclarationFromFragment(
Fragment fragment, {
required bool inLibrary,
required List<Fragment> unnamedFragments,
required List<PrimaryConstructorBodyFragment>? primaryConstructorBodies,
}) {
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,
isAugment: fragment.modifiers.isAugment,
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,
isPotentiallyAugment: false,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
isConst: fragment.modifiers.isConst,
uriOffset: fragment.uriOffset,
);
case PrimaryConstructorFragment():
PrimaryConstructorBodyFragment? bodyFragment;
if (primaryConstructorBodies != null &&
primaryConstructorBodies.isNotEmpty) {
bodyFragment = primaryConstructorBodies.removeAt(0);
}
return new _GenerativeConstructorDeclaration(
new PrimaryConstructorDeclaration(fragment, bodyFragment),
name: fragment.name,
displayName: fragment.constructorName.fullName,
isAugment: fragment.modifiers.isAugment,
isPotentiallyAugment: true,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: inLibrary,
isConst: fragment.modifiers.isConst,
uriOffset: fragment.uriOffset,
);
case PrimaryConstructorBodyFragment():
// Coverage-ignore(suite): Not run.
throw new UnsupportedError("Unexpected primary constructor body.");
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: fragment.hasSetter
? _PropertyKind.Field
: _PropertyKind.FinalField,
isStatic: false,
inPatch: fragment.enclosingDeclaration.isPatch,
inLibrary: false,
uriOffset: fragment.uriOffset,
declarations: new _PropertyDeclarations(
field: declaration,
getter: declaration,
setter: fragment.hasSetter ? declaration : null,
),
);
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 _createEnumBuilderFromFragments(
EnumFragment fragment,
List<Fragment>? augmentations,
) {
List<TypeBuilder>? mixedInTypeBuilders = fragment.mixins?.toList();
List<TypeBuilder>? interfaceBuilders = fragment.interfaces?.toList();
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
augmentation as EnumFragment;
List<TypeBuilder>? augmentationMixedInTypeBuilders =
augmentation.mixins;
if (augmentationMixedInTypeBuilders != null) {
(mixedInTypeBuilders ??= []).addAll(augmentationMixedInTypeBuilders);
}
List<TypeBuilder>? augmentationInterfaceBuilders =
augmentation.interfaces;
if (augmentationInterfaceBuilders != null) {
(interfaceBuilders ??= []).addAll(augmentationInterfaceBuilders);
}
}
}
String name = fragment.name;
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(name);
List<EnumElementFragment> enumElements = [];
_createDeclarationBuilder(
introductory: fragment,
augmentations: augmentations,
reference: indexedClass?.reference,
createDeclaration: (EnumFragment fragment) {
enumElements.addAll(fragment.enumElements);
return new EnumDeclaration(fragment);
},
createBuilder:
({
required augmentations,
required introductory,
required modifiers,
required nameSpaceBuilder,
required nominalParameters,
}) => new SourceEnumBuilder(
name: name,
typeParameters: nominalParameters,
underscoreEnumTypeBuilder: _loader.target.underscoreEnumType,
mixedInTypeBuilders: mixedInTypeBuilders,
interfaceBuilders: interfaceBuilders,
enumElements: enumElements,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOffset,
endOffset: fragment.endOffset,
indexedClass: indexedClass,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
introductory: introductory,
augmentations: augmentations,
modifiers: modifiers,
),
setBuilder: (fragment, builder) => fragment.builder = builder,
// TODO(johnniwinther): Use a distinct message for patch/augmentation
// and different kinds of declarations.
typeParametersMismatchMessage: diag.patchClassTypeParametersMismatch,
typeParametersIntroductoryMessage: diag.patchClassOrigin,
);
if (!fragment.hasErroneousBody && enumElements.isEmpty) {
_problemReporting.addProblem2(
diag.enumDeclarationEmpty,
fragment.uriOffset,
);
}
}
void _createExtensionBuilderFromFragments(
ExtensionFragment fragment,
List<Fragment>? augmentations,
) {
Reference? reference;
if (!fragment.extensionName.isUnnamedExtension) {
reference = _indexedLibrary?.lookupExtension(fragment.name);
}
_createDeclarationBuilder(
introductory: fragment,
augmentations: augmentations,
reference: reference,
createDeclaration: ExtensionDeclaration.new,
createBuilder:
({
required DeclarationNameSpaceBuilder nameSpaceBuilder,
required List<SourceNominalParameterBuilder>? nominalParameters,
required ExtensionDeclaration introductory,
required List<ExtensionDeclaration> augmentations,
required Modifiers modifiers,
}) => new SourceExtensionBuilder(
enclosingLibraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOrExtensionOffset,
endOffset: fragment.endOffset,
modifiers: modifiers,
extensionName: fragment.extensionName,
typeParameters: nominalParameters,
nameSpaceBuilder: nameSpaceBuilder,
introductory: introductory,
augmentations: augmentations,
reference: reference,
onType: fragment.onType,
),
setBuilder: (fragment, builder) => fragment.builder = builder,
// TODO(johnniwinther): Use a distinct message for patch/augmentation
// and different kinds of declarations.
typeParametersMismatchMessage: diag.patchExtensionTypeParametersMismatch,
typeParametersIntroductoryMessage: diag.patchExtensionOrigin,
);
}
void _createExtensionTypeBuilderFragments(
ExtensionTypeFragment fragment,
List<Fragment>? augmentations,
) {
List<TypeBuilder>? interfaceBuilders = fragment.interfaces?.toList();
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
augmentation as ExtensionTypeFragment;
List<TypeBuilder>? augmentationInterfaceBuilders =
augmentation.interfaces;
if (augmentationInterfaceBuilders != null) {
(interfaceBuilders ??= []).addAll(augmentationInterfaceBuilders);
}
}
}
IndexedContainer? indexedContainer = _indexedLibrary
?.lookupIndexedExtensionTypeDeclaration(fragment.name);
List<PrimaryConstructorFieldFragment> primaryConstructorFields =
fragment.primaryConstructorFields;
PrimaryConstructorFieldFragment? representationFieldFragment;
if (primaryConstructorFields.isNotEmpty) {
representationFieldFragment = primaryConstructorFields.first;
}
_createDeclarationBuilder(
introductory: fragment,
augmentations: augmentations,
reference: indexedContainer?.reference,
createDeclaration: ExtensionTypeDeclaration.new,
createBuilder:
({
required DeclarationNameSpaceBuilder nameSpaceBuilder,
required List<SourceNominalParameterBuilder>? nominalParameters,
required ExtensionTypeDeclaration introductory,
required List<ExtensionTypeDeclaration> augmentations,
required Modifiers modifiers,
}) => new SourceExtensionTypeDeclarationBuilder(
name: fragment.name,
enclosingLibraryBuilder: _enclosingLibraryBuilder,
constructorReferences: fragment.constructorReferences,
fileUri: fragment.fileUri,
startOffset: fragment.startOffset,
nameOffset: fragment.nameOffset,
endOffset: fragment.endOffset,
modifiers: modifiers,
typeParameters: nominalParameters,
interfaceBuilders: interfaceBuilders,
nameSpaceBuilder: nameSpaceBuilder,
introductory: introductory,
augmentations: augmentations,
indexedContainer: indexedContainer,
representationFieldFragment: representationFieldFragment,
),
setBuilder: (fragment, builder) => fragment.builder = builder,
// TODO(johnniwinther): Use a distinct message for patch/augmentation
// and different kinds of declarations.
typeParametersMismatchMessage: diag.patchClassTypeParametersMismatch,
typeParametersIntroductoryMessage: diag.patchClassOrigin,
);
}
void _createFactoryBuilderFromDeclarations(
FactoryDeclaration introductory,
List<FactoryDeclaration> augmentations, {
required String name,
required bool isConst,
required UriOffsetLength uriOffset,
required bool inPatch,
}) {
List<FactoryDeclaration> declarations = [introductory];
FactoryDeclaration implementation = introductory;
if (augmentations.isNotEmpty) {
declarations.addAll(augmentations);
for (FactoryDeclaration augmentation in augmentations) {
if (augmentation.isComplete) {
implementation = augmentation;
}
}
}
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 = implementation.isRedirectingFactory;
SourceFactoryBuilder factoryBuilder = new SourceFactoryBuilder(
name: name,
libraryBuilder: _enclosingLibraryBuilder,
declarationBuilder: _declarationBuilder,
fileUri: uriOffset.fileUri,
fileOffset: uriOffset.fileOffset,
factoryReferences: factoryReferences,
nameScheme: nameScheme,
declarations: declarations,
implementation: implementation,
isConst: isConst,
);
if (isRedirectingFactory) {
(_enclosingLibraryBuilder.redirectingFactoryBuilders ??= []).add(
factoryBuilder,
);
}
for (FactoryDeclaration declaration in declarations) {
declaration.createEncoding(
problemReporting: _problemReporting,
declarationBuilder: _declarationBuilder,
factoryBuilder: factoryBuilder,
typeParameterFactory: _typeParameterFactory,
encodingStrategy: encodingStrategy,
isImplementation: declaration == implementation,
);
}
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;
NameScheme nameScheme = new NameScheme(
containerName: _containerName,
containerType: _containerType,
isInstanceMember: isInstanceMember,
libraryName: _indexedLibrary != null
? new LibraryName(_indexedLibrary.library.reference)
: _enclosingLibraryBuilder.libraryName,
);
MethodReferences methodReferences = new MethodReferences(
name,
nameScheme,
_indexedContainer ?? _indexedLibrary,
kind: kind,
);
Modifiers modifiers = fragment.modifiers;
MethodDeclaration introductoryDeclaration = new MethodDeclarationImpl(
fragment,
);
List<MethodDeclaration> declarations = [introductoryDeclaration];
MethodDeclaration implementation = introductoryDeclaration;
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [MethodFragment].
augmentation as MethodFragment;
MethodDeclaration augmentingDeclaration = new MethodDeclarationImpl(
augmentation,
);
declarations.add(augmentingDeclaration);
if (!augmentation.modifiers.isAbstract) {
implementation = augmentingDeclaration;
}
_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,
declarations: declarations,
implementation: implementation,
nameScheme: nameScheme,
references: methodReferences,
);
fragment.builder = methodBuilder;
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
// Promote [augmentation] to [MethodFragment].
augmentation as MethodFragment;
augmentation.builder = methodBuilder;
}
augmentations.clear();
}
for (MethodDeclaration declaration in declarations) {
declaration.createEncoding(
problemReporting: _problemReporting,
builder: methodBuilder,
encodingStrategy: encodingStrategy,
typeParameterFactory: _typeParameterFactory,
isImplementation: declaration == implementation,
);
}
methodReferences.registerReference(_loader.referenceMap, methodBuilder);
_builderRegistry.registerBuilder(
declaration: methodBuilder,
uriOffset: fragment.uriOffset,
inPatch:
fragment.enclosingDeclaration?.isPatch ??
fragment.enclosingCompilationUnit.isPatch,
);
}
void _createMixinBuilderFromFragments(
MixinFragment fragment,
List<Fragment>? augmentations,
) {
List<TypeBuilder>? interfaceBuilders = fragment.interfaces?.toList();
if (augmentations != null) {
for (Fragment augmentation in augmentations) {
augmentation as MixinFragment;
List<TypeBuilder>? augmentationInterfaceBuilders =
augmentation.interfaces;
if (augmentationInterfaceBuilders != null) {
(interfaceBuilders ??= []).addAll(augmentationInterfaceBuilders);
}
}
}
String name = fragment.name;
IndexedClass? indexedClass = _indexedLibrary?.lookupIndexedClass(name);
_createDeclarationBuilder(
introductory: fragment,
augmentations: augmentations,
reference: indexedClass?.reference,
createDeclaration: MixinDeclaration.new,
createBuilder:
({
required augmentations,
required introductory,
required modifiers,
required nameSpaceBuilder,
required nominalParameters,
}) => new SourceClassBuilder(
modifiers: modifiers,
name: name,
typeParameters: fragment.typeParameterBuilders,
typeParameterScope: fragment.typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: indexedClass,
introductory: introductory,
augmentations: augmentations,
supertypeBuilder: fragment.supertype,
mixedInTypeBuilders: fragment.mixins,
interfaceBuilders: interfaceBuilders,
),
setBuilder: (fragment, builder) => fragment.builder = builder,
// TODO(johnniwinther): Use a distinct message for patch/augmentation
// and different kinds of declarations.
typeParametersMismatchMessage: diag.patchClassTypeParametersMismatch,
typeParametersIntroductoryMessage: diag.patchClassOrigin,
);
}
void _createNamedMixinApplicationBuilder(
NamedMixinApplicationFragment fragment,
) {
List<TypeBuilder> mixins = fragment.mixins.toList();
TypeBuilder supertypeBuilder = fragment.supertype;
List<TypeBuilder>? interfaceBuilders = fragment.interfaces;
TypeBuilder mixin = mixins.removeLast();
ClassDeclaration classDeclaration = new NamedMixinApplication(fragment);
String name = fragment.name;
IndexedClass? referencesFromIndexedClass = _indexedLibrary
?.lookupIndexedClass(name);
_typeParameterFactory.createNominalParameterBuilders(
fragment.typeParameters,
);
fragment.nominalParameterNameSpace.addTypeParameters(
_problemReporting,
fragment.typeParameterBuilders,
ownerName: name,
allowNameConflict: false,
);
LookupScope typeParameterScope = TypeParameterScope.fromList(
fragment.enclosingScope,
fragment.typeParameterBuilders,
);
DeclarationNameSpaceBuilder nameSpaceBuilder =
new DeclarationNameSpaceBuilder.empty();
SourceClassBuilder classBuilder = new SourceClassBuilder(
modifiers: fragment.modifiers | Modifiers.NamedMixinApplication,
name: name,
typeParameters: fragment.typeParameterBuilders,
typeParameterScope: typeParameterScope,
nameSpaceBuilder: nameSpaceBuilder,
libraryBuilder: _enclosingLibraryBuilder,
fileUri: fragment.fileUri,
nameOffset: fragment.nameOffset,
indexedClass: referencesFromIndexedClass,
mixedInTypeBuilder: mixin,
introductory: classDeclaration,
supertypeBuilder: supertypeBuilder,
mixedInTypeBuilders: mixins,
interfaceBuilders: interfaceBuilders,
);
_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 _createPropertyBuilder({
required String name,
required UriOffsetLength uriOffset,
required List<FieldDeclaration> fieldDeclarations,
required FieldDeclaration? fieldImplementation,
required List<GetterDeclaration> getterDeclarations,
required GetterDeclaration? getterImplementation,
required List<SetterDeclaration> setterDeclarations,
required SetterDeclaration? setterImplementation,
required bool isStatic,
required bool inPatch,
}) {
bool isInstanceMember =
_containerType != ContainerType.Library && !isStatic;
bool fieldIsLateWithLowering = false;
if (fieldDeclarations.isNotEmpty) {
fieldIsLateWithLowering =
fieldDeclarations.first.isLate &&
(_loader.target.backendTarget.isLateFieldLoweringEnabled(
hasInitializer: fieldDeclarations.first.hasInitializer,
isFinal: fieldDeclarations.first.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,
fieldDeclarations: fieldDeclarations,
fieldImplementation: fieldImplementation,
getterDeclarations: getterDeclarations,
getterImplementation: getterImplementation,
setterDeclarations: setterDeclarations,
setterImplementation: setterImplementation,
isStatic: isStatic,
nameScheme: nameScheme,
references: references,
);
for (FieldDeclaration fieldDeclaration in fieldDeclarations) {
fieldDeclaration.createFieldEncoding(propertyBuilder);
}
for (GetterDeclaration getterDeclaration in getterDeclarations) {
getterDeclaration.createGetterEncoding(
problemReporting: _problemReporting,
builder: propertyBuilder,
encodingStrategy: propertyEncodingStrategy,
typeParameterFactory: _typeParameterFactory,
isImplementation: getterDeclaration == getterImplementation,
);
}
for (SetterDeclaration setterDeclaration in setterDeclarations) {
setterDeclaration.createSetterEncoding(
problemReporting: _problemReporting,
builder: propertyBuilder,
encodingStrategy: propertyEncodingStrategy,
typeParameterFactory: _typeParameterFactory,
isImplementation: setterDeclaration == setterImplementation,
);
}
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 {
new({
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(
diag.enumContainsValuesDeclaration,
declaration.uriOffset,
);
}
@override
void reportStaticInstanceConflict(
ProblemReporting problemReporting,
_PropertyDeclaration declaration,
) {
problemReporting.addProblem2(
diag.instanceAndSynthesizedStaticConflict.withArguments(
name: 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;
new(
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.
new(this._declaration);
@override
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration.isAugment || declaration.isPotentiallyAugment) {
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;
new(
this.kind, {
required this.displayName,
required this.isAugment,
required this.inPatch,
required this.inLibrary,
this.isStatic = true,
});
/// Returns `true` if this declaration can be augmenting without an explicit
/// modifier.
bool get isPotentiallyAugment => false;
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.
new(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(
diag.setterConflictsWithDeclaration.withArguments(setterName: name),
newUriOffset,
context: [
diag.setterConflictsWithDeclarationCause
.withArguments(setterName: name)
.withLocation2(existingUriOffset),
],
);
return;
}
break;
case _ExistingKind.ExplicitSetter:
if (!newIsSetter) {
problemReporting.addProblem2(
diag.declarationConflictsWithSetter.withArguments(setterName: name),
newUriOffset,
context: <LocatedMessage>[
diag.declarationConflictsWithSetterCause
.withArguments(setterName: name)
.withLocation2(existingUriOffset),
],
);
return;
}
break;
case _ExistingKind.ImplicitSetter:
problemReporting.addProblem2(
diag.conflictsWithImplicitSetter.withArguments(fieldName: name),
newUriOffset,
context: [
diag.conflictsWithImplicitSetterCause
.withArguments(fieldName: name)
.withLocation2(existingUriOffset),
],
);
return;
}
problemReporting.addProblem2(
diag.duplicatedDeclaration.withArguments(name: name),
newUriOffset,
context: <LocatedMessage>[
diag.duplicatedDeclarationCause
.withArguments(name: name)
.withLocation2(existingUriOffset),
],
);
}
}
enum _ExistingKind { Getable, ExplicitSetter, ImplicitSetter }
class _FactoryConstructorDeclaration extends _ConstructorDeclaration
with _DeclarationReportingMixin {
final String _name;
final FactoryDeclaration _declaration;
new(
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(
diag.memberConflictsWithFactory.withArguments(factoryName: displayName),
nonConstructorDeclaration.uriOffset,
context: [
diag.memberConflictsWithFactoryCause
.withArguments(factoryName: displayName)
.withLocation2(uriOffset),
],
);
}
@override
_PreBuilder _createPreBuilder() =>
new _FactoryConstructorPreBuilder(_name, this);
}
class _FactoryConstructorPreBuilder
extends _ConstructorPreBuilder<_FactoryConstructorDeclaration> {
final String _name;
new(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 {
new({
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;
@override
final bool isPotentiallyAugment;
new(
this._declaration, {
required String name,
required super.displayName,
required super.isAugment,
required this.isPotentiallyAugment,
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(
diag.memberConflictsWithConstructor.withArguments(
constructorName: displayName,
),
nonConstructorDeclaration.uriOffset,
context: [
diag.memberConflictsWithConstructorCause
.withArguments(constructorName: displayName)
.withLocation2(uriOffset),
],
);
}
@override
_PreBuilder _createPreBuilder() =>
new _GenerativeConstructorPreBuilder(_name, this);
}
class _GenerativeConstructorPreBuilder
extends _ConstructorPreBuilder<_GenerativeConstructorDeclaration> {
final String _name;
new(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 {
new({
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 {
new(
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(
diag.constructorConflictsWithMember.withArguments(
memberName: displayName,
),
constructorDeclaration.uriOffset,
context: [
diag.constructorConflictsWithMemberCause
.withArguments(memberName: 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(
diag.factoryConflictsWithMember.withArguments(memberName: displayName),
constructorDeclaration.uriOffset,
context: [
diag.factoryConflictsWithMemberCause
.withArguments(memberName: 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;
new({
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(
diag.instanceConflictsWithStatic.withArguments(
propertyName: displayName,
),
declaration.uriOffset,
context: [
diag.instanceConflictsWithStaticCause
.withArguments(propertyName: displayName)
.withLocation2(uriOffset),
],
);
} else {
problemReporting.addProblem2(
diag.staticConflictsWithInstance.withArguments(
propertyName: displayName,
),
declaration.uriOffset,
context: [
diag.staticConflictsWithInstanceCause
.withArguments(propertyName: displayName)
.withLocation2(uriOffset),
],
);
}
}
}
class _PropertyDeclarations {
final FieldDeclaration? field;
final GetterDeclaration? getter;
final SetterDeclaration? setter;
new({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? _introductoryGetterDeclaration;
_PropertyDeclaration? _introductorySetterDeclaration;
FieldDeclaration? _fieldImplementation;
List<FieldDeclaration> _fieldDeclarations = [];
GetterDeclaration? _getterImplementation;
List<GetterDeclaration> _getterDeclarations = [];
SetterDeclaration? _setterImplementation;
List<SetterDeclaration> _setterDeclarations = [];
// TODO(johnniwinther): Report error if [field] is augmenting.
new forField(_PropertyDeclaration field)
: isStatic = field.isStatic,
inPatch = field.inPatch,
name = field.displayName,
uriOffset = field.uriOffset,
_introductoryGetterDeclaration = field,
_introductorySetterDeclaration = 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) ==
(_introductoryGetterDeclaration!.propertyKind == _PropertyKind.Field),
"Unexpected setter declaration from field ${field}.",
);
_absorbDeclarations(field.declarations);
}
// TODO(johnniwinther): Report error if [getter] is augmenting.
new forGetter(_PropertyDeclaration getter)
: isStatic = getter.isStatic,
inPatch = getter.inPatch,
name = getter.displayName,
uriOffset = getter.uriOffset,
_introductoryGetterDeclaration = 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}.",
);
_absorbDeclarations(getter.declarations);
}
// TODO(johnniwinther): Report error if [setter] is augmenting.
new forSetter(_PropertyDeclaration setter)
: isStatic = setter.isStatic,
inPatch = setter.inPatch,
name = setter.displayName,
uriOffset = setter.uriOffset,
_introductorySetterDeclaration = 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}.",
);
_absorbDeclarations(setter.declarations);
}
void _absorbDeclarations(_PropertyDeclarations declarations) {
FieldDeclaration? fieldDeclaration = declarations.field;
if (fieldDeclaration != null) {
_fieldDeclarations.add(fieldDeclaration);
if (_fieldImplementation == null ||
!fieldDeclaration.fieldQuality.impliesAbstract) {
_fieldImplementation = fieldDeclaration;
}
}
GetterDeclaration? getterDeclaration = declarations.getter;
if (getterDeclaration != null) {
_getterDeclarations.add(getterDeclaration);
if (_getterImplementation == null ||
!getterDeclaration.getterQuality.impliesAbstract) {
_getterImplementation = getterDeclaration;
}
}
SetterDeclaration? setterDeclaration = declarations.setter;
if (setterDeclaration != null) {
_setterDeclarations.add(setterDeclaration);
if (_setterImplementation == null ||
!setterDeclaration.setterQuality.impliesAbstract) {
_setterImplementation = setterDeclaration;
}
}
}
@override
bool absorbFragment(
ProblemReporting problemReporting,
_Declaration declaration,
) {
if (declaration is! _PropertyDeclaration) {
if (_introductoryGetterDeclaration != null) {
// Example:
//
// int get foo => 42;
// void foo() {}
//
_introductoryGetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
} else {
assert(_introductorySetterDeclaration != null);
// Example:
//
// void set foo(_) {}
// void foo() {}
//
_introductorySetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
}
return false;
}
_PropertyKind? propertyKind = declaration.propertyKind;
switch (propertyKind) {
case _PropertyKind.Getter:
if (_introductoryGetterDeclaration == 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;
// }
//
_introductorySetterDeclaration!.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}.",
);
_introductoryGetterDeclaration = declaration;
GetterDeclaration getterDeclaration = declarations.getter!;
_getterDeclarations.add(getterDeclaration);
assert(
_getterImplementation == null,
"Unexpected existing getter implementation "
"$_getterImplementation.",
);
_getterImplementation = getterDeclaration;
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}.",
);
_absorbDeclarations(declarations);
return true;
} else {
// Example:
//
// int get foo => 42;
// int get foo => 87;
//
_introductoryGetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
case _PropertyKind.Setter:
if (_introductorySetterDeclaration == 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(_) {}
// }
//
_introductoryGetterDeclaration!.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}.",
);
_introductorySetterDeclaration = declaration;
_absorbDeclarations(declarations);
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}.",
);
_absorbDeclarations(declarations);
return true;
} else {
// Examples:
//
// int? foo;
// void set foo(_) {}
//
// and
//
// void set foo(_) {}
// void set foo(_) {}
//
_introductorySetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
case _PropertyKind.Field:
if (_introductoryGetterDeclaration == null) {
// Example:
//
// void set foo(_) {}
// int? foo;
//
assert(
_introductoryGetterDeclaration == null &&
_introductorySetterDeclaration != null,
);
// We have an explicit setter.
_introductorySetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
} else if (_introductorySetterDeclaration != 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(
_introductoryGetterDeclaration != null &&
_introductorySetterDeclaration != null,
);
// We have both getter and setter
if (declaration.isAugment) {
if (_introductoryGetterDeclaration!.propertyKind ==
declaration.propertyKind) {
// Example:
//
// int foo = 42;
// augment int foo = 87;
//
_PropertyDeclarations declarations = declaration.declarations;
_absorbDeclarations(declarations);
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;
//
_introductoryGetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
} else {
// Examples:
//
// int get foo => 42;
// int? foo;
//
// final int bar = 42;
// int? bar;
//
assert(
_introductoryGetterDeclaration != null &&
_introductorySetterDeclaration == null,
);
_introductoryGetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
case _PropertyKind.FinalField:
if (_introductoryGetterDeclaration == null) {
// Example:
//
// void set foo(_) {}
// final int foo = 42;
//
assert(
_introductoryGetterDeclaration == null &&
_introductorySetterDeclaration != 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;
// }
//
_introductorySetterDeclaration!.reportStaticInstanceConflict(
problemReporting,
declaration,
);
return false;
} else {
_PropertyDeclarations declarations = declaration.declarations;
assert(
declarations.setter == null,
"Unexpected setter declaration from field "
"${declaration}.",
);
_introductoryGetterDeclaration = declaration;
_absorbDeclarations(declarations);
return true;
}
} else {
// Examples:
//
// final int foo = 42;
// final int foo = 87;
//
// int get bar => 42;
// final int bar = 87;
//
if (declaration.isAugment) {
if (_introductoryGetterDeclaration!.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}.",
);
_absorbDeclarations(declarations);
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;
//
_introductoryGetterDeclaration!.reportDuplicateDeclaration(
problemReporting,
declaration,
);
return false;
}
}
}
}
@override
void checkFragment(
ProblemReporting problemReporting,
_Declaration constructorDeclaration,
) {
// Check conflict with constructor.
if (isStatic) {
if (_introductoryGetterDeclaration != null) {
// Examples:
//
// class A {
// static int get foo => 42;
// A.foo();
// }
//
// and
//
// class A {
// static int get foo => 42;
// factory A.foo() => throw '';
// }
//
_introductoryGetterDeclaration!.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 '';
// }
//
_introductorySetterDeclaration!.reportConstructorConflict(
problemReporting,
constructorDeclaration,
);
}
}
}
@override
void createBuilders(BuilderFactory builderFactory) {
builderFactory._createPropertyBuilder(
name: name,
inPatch: inPatch,
isStatic: isStatic,
uriOffset: uriOffset,
fieldDeclarations: _fieldDeclarations,
fieldImplementation: _fieldImplementation,
getterDeclarations: _getterDeclarations,
getterImplementation: _getterImplementation,
setterDeclarations: _setterDeclarations,
setterImplementation: _setterImplementation,
);
}
}
class _SetterDeclaration extends _PropertyDeclaration
with _DeclarationReportingMixin {
new({
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 {
new(
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;
new(
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;
}