| // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart'; |
| import 'package:kernel/ast.dart'; |
| import 'package:kernel/reference_from_index.dart'; |
| import 'package:kernel/src/bounds_checks.dart' show VarianceCalculationValue; |
| |
| import '../base/lookup_result.dart'; |
| import '../base/messages.dart'; |
| import '../base/modifiers.dart'; |
| import '../base/name_space.dart'; |
| import '../base/problems.dart'; |
| import '../base/scope.dart'; |
| import '../base/uri_offset.dart'; |
| import '../builder/builder.dart'; |
| import '../builder/constructor_builder.dart'; |
| import '../builder/declaration_builders.dart'; |
| import '../builder/factory_builder.dart'; |
| import '../builder/formal_parameter_builder.dart'; |
| import '../builder/function_builder.dart'; |
| import '../builder/member_builder.dart'; |
| import '../builder/named_type_builder.dart'; |
| import '../builder/nullability_builder.dart'; |
| import '../builder/prefix_builder.dart'; |
| import '../builder/type_builder.dart'; |
| import '../fragment/constructor/declaration.dart'; |
| import '../fragment/factory/declaration.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 'builder_factory.dart'; |
| import 'name_scheme.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_member_builder.dart'; |
| import 'source_method_builder.dart'; |
| import 'source_property_builder.dart'; |
| import 'source_type_alias_builder.dart'; |
| import 'source_type_parameter_builder.dart'; |
| |
| enum _PropertyKind { |
| Getter, |
| Setter, |
| Field, |
| FinalField, |
| } |
| |
| enum _DeclarationKind { |
| Constructor, |
| Factory, |
| Class, |
| Mixin, |
| NamedMixinApplication, |
| Enum, |
| Extension, |
| ExtensionType, |
| Typedef, |
| Method, |
| Property, |
| } |
| |
| abstract class _Declaration { |
| final _DeclarationKind kind; |
| final Fragment _fragment; |
| final String name; |
| final bool isAugment; |
| final bool inPatch; |
| final bool inLibrary; |
| final bool isStatic; |
| |
| _Declaration(this.kind, this._fragment, |
| {required this.name, |
| required this.isAugment, |
| required this.inPatch, |
| required this.inLibrary, |
| this.isStatic = true}); |
| |
| UriOffsetLength get uriOffset; |
| |
| /// 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(); |
| |
| void registerPreBuilder( |
| ProblemReporting problemReporting, |
| List<_PreBuilder> nonConstructorPreBuilders, |
| List<_PreBuilder> constructorPreBuilders); |
| } |
| |
| mixin _FragmentDeclarationMixin implements _Declaration { |
| @override |
| Fragment get _fragment; |
| |
| @override |
| UriOffsetLength get uriOffset => _fragment.uriOffset; |
| |
| @override |
| String toString() => _fragment.toString(); |
| } |
| |
| abstract class _NonConstructorDeclaration extends _Declaration { |
| _NonConstructorDeclaration(super.kind, super.fragment, |
| {required super.name, |
| 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); |
| } |
| } |
| |
| mixin _PropertyFragmentDeclarationMixin implements _PropertyDeclaration { |
| @override |
| Fragment get _fragment; |
| |
| @override |
| _PropertyDeclarations createDeclarations() { |
| Fragment fragment = _fragment; |
| switch (fragment) { |
| case FieldFragment(): |
| RegularFieldDeclaration declaration = |
| new RegularFieldDeclaration(fragment); |
| return new _PropertyDeclarations( |
| field: declaration, |
| getter: declaration, |
| setter: fragment.hasSetter ? declaration : null); |
| case PrimaryConstructorFieldFragment(): |
| PrimaryConstructorFieldDeclaration declaration = |
| new PrimaryConstructorFieldDeclaration(fragment); |
| return new _PropertyDeclarations( |
| field: declaration, getter: declaration); |
| case EnumElementFragment(): |
| EnumElementDeclaration declaration = |
| new EnumElementDeclaration(fragment); |
| return new _PropertyDeclarations( |
| field: declaration, getter: declaration); |
| case GetterFragment(): |
| return new _PropertyDeclarations( |
| getter: new RegularGetterDeclaration(fragment)); |
| case SetterFragment(): |
| return new _PropertyDeclarations( |
| setter: new RegularSetterDeclaration(fragment)); |
| // Coverage-ignore(suite): Not run. |
| default: |
| throw new UnsupportedError("Unexpected property fragment $fragment"); |
| } |
| } |
| } |
| |
| abstract class _PropertyDeclaration extends _NonConstructorDeclaration { |
| final _PropertyKind propertyKind; |
| |
| _PropertyDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| required this.propertyKind, |
| super.isStatic}); |
| |
| _PropertyDeclarations createDeclarations(); |
| } |
| |
| class _FieldDeclaration extends _PropertyDeclaration |
| with _FragmentDeclarationMixin, _PropertyFragmentDeclarationMixin { |
| _FieldDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| required super.propertyKind, |
| super.isStatic}); |
| |
| @override |
| _PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forField(this); |
| } |
| |
| class _GetterDeclaration extends _PropertyDeclaration |
| with _FragmentDeclarationMixin, _PropertyFragmentDeclarationMixin { |
| _GetterDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| required super.propertyKind, |
| super.isStatic}); |
| |
| @override |
| _PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forGetter(this); |
| } |
| |
| class _SetterDeclaration extends _PropertyDeclaration |
| with _FragmentDeclarationMixin, _PropertyFragmentDeclarationMixin { |
| _SetterDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| required super.propertyKind, |
| super.isStatic}); |
| |
| @override |
| _PreBuilder _createPreBuilder() => new _PropertyPreBuilder.forSetter(this); |
| } |
| |
| mixin _StandardFragmentDeclarationMixin implements _StandardDeclaration { |
| @override |
| Fragment get _fragment; |
| } |
| |
| abstract class _StandardDeclaration extends _NonConstructorDeclaration { |
| _StandardDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| super.isStatic}); |
| |
| @override |
| _PreBuilder _createPreBuilder() => new _DeclarationPreBuilder(this); |
| } |
| |
| class _StandardFragmentDeclaration extends _StandardDeclaration |
| with _FragmentDeclarationMixin, _StandardFragmentDeclarationMixin { |
| _StandardFragmentDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary, |
| super.isStatic}); |
| } |
| |
| mixin _ConstructorFragmentDeclarationMixin implements _ConstructorDeclaration { |
| @override |
| Fragment get _fragment; |
| } |
| |
| abstract class _ConstructorDeclaration extends _Declaration { |
| _ConstructorDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary}); |
| |
| @override |
| _PreBuilder _createPreBuilder() => new _ConstructorPreBuilder(this); |
| |
| @override |
| void registerPreBuilder( |
| ProblemReporting problemReporting, |
| List<_PreBuilder> nonConstructorPreBuilders, |
| List<_PreBuilder> constructorPreBuilders) { |
| _addPreBuilder( |
| problemReporting, constructorPreBuilders, nonConstructorPreBuilders); |
| } |
| } |
| |
| class _ConstructorFragmentDeclaration extends _ConstructorDeclaration |
| with _FragmentDeclarationMixin, _ConstructorFragmentDeclarationMixin { |
| _ConstructorFragmentDeclaration(super.kind, super.fragment, |
| {required super.name, |
| required super.isAugment, |
| required super.inPatch, |
| required super.inLibrary}); |
| } |
| |
| typedef _CreateBuilderFunction = void Function(Fragment, |
| {List<Fragment>? augmentations}); |
| |
| typedef _CreatePropertyFunction = void Function( |
| {required String name, |
| required UriOffsetLength uriOffset, |
| FieldDeclaration? fieldDeclaration, |
| GetterDeclaration? getterDeclaration, |
| List<GetterDeclaration>? getterAugmentationDeclarations, |
| SetterDeclaration? setterDeclaration, |
| List<SetterDeclaration>? setterAugmentationDeclarations, |
| required bool isStatic, |
| required bool inPatch}); |
| |
| /// 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 [createBuilder] 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(_CreateBuilderFunction createBuilder, |
| _CreatePropertyFunction createProperty); |
| } |
| |
| /// [_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; |
| FieldDeclaration? _field; |
| GetterDeclaration? _getter; |
| _PropertyKind? _getterPropertyKind; |
| SetterDeclaration? _setter; |
| _PropertyKind? _setterPropertyKind; |
| List<GetterDeclaration> _getterAugmentations = []; |
| List<SetterDeclaration> _setterAugmentations = []; |
| |
| // TODO(johnniwinther): Report error if [getter] is augmenting. |
| _PropertyPreBuilder.forGetter(_PropertyDeclaration getter) |
| : isStatic = getter.isStatic, |
| inPatch = getter.inPatch, |
| name = getter.name, |
| uriOffset = getter.uriOffset, |
| _getterPropertyKind = getter.propertyKind { |
| _PropertyDeclarations declarations = getter.createDeclarations(); |
| 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}."); |
| _getter = declarations.getter; |
| } |
| |
| // TODO(johnniwinther): Report error if [setter] is augmenting. |
| _PropertyPreBuilder.forSetter(_PropertyDeclaration setter) |
| : isStatic = setter.isStatic, |
| inPatch = setter.inPatch, |
| name = setter.name, |
| uriOffset = setter.uriOffset, |
| _setterPropertyKind = setter.propertyKind { |
| _PropertyDeclarations declarations = setter.createDeclarations(); |
| 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}."); |
| _setter = declarations.setter; |
| } |
| |
| // TODO(johnniwinther): Report error if [field] is augmenting. |
| _PropertyPreBuilder.forField(_PropertyDeclaration field) |
| : isStatic = field.isStatic, |
| inPatch = field.inPatch, |
| name = field.name, |
| uriOffset = field.uriOffset, |
| _getterPropertyKind = field.propertyKind { |
| _PropertyDeclarations declarations = field.createDeclarations(); |
| assert(declarations.field != null, |
| "Unexpected field declaration from field ${field}."); |
| assert(declarations.getter != null, |
| "Unexpected getter declaration from field ${field}."); |
| assert( |
| (declarations.setter != null) == |
| (_getterPropertyKind == _PropertyKind.Field), |
| "Unexpected setter declaration from field ${field}."); |
| _field = declarations.field; |
| _getter = declarations.getter; |
| _setter = declarations.setter; |
| |
| if (_getterPropertyKind == _PropertyKind.Field) { |
| _setterPropertyKind = field.propertyKind; |
| } |
| } |
| |
| @override |
| bool absorbFragment( |
| ProblemReporting problemReporting, _Declaration declaration) { |
| if (declaration is! _PropertyDeclaration) { |
| if (_getter != null) { |
| // Example: |
| // |
| // int get foo => 42; |
| // void foo() {} |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| } else { |
| assert(_setter != null); |
| // Example: |
| // |
| // void set foo(_) {} |
| // void foo() {} |
| // |
| problemReporting.addProblem2( |
| templateDeclarationConflictsWithSetter.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDeclarationConflictsWithSetterCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| } |
| return false; |
| } |
| _PropertyKind? propertyKind = declaration.propertyKind; |
| |
| switch (propertyKind) { |
| case _PropertyKind.Getter: |
| if (_getter == 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) { |
| if (declaration.isStatic) { |
| // Coverage-ignore-block(suite): Not run. |
| // Example: |
| // |
| // class A { |
| // void set foo(_) {} |
| // static int get foo => 42; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateStaticConflictsWithInstance.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateStaticConflictsWithInstanceCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| } else { |
| // Example: |
| // |
| // class A { |
| // static void set foo(_) {} |
| // int get foo => 42; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateInstanceConflictsWithStatic.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateInstanceConflictsWithStaticCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| } |
| return false; |
| } else { |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| assert( |
| declarations.field == null, |
| "Unexpected field declaration from getter " |
| "${declaration}."); |
| assert( |
| declarations.setter == null, |
| "Unexpected setter declaration from getter " |
| "${declaration}."); |
| _getter = declarations.getter; |
| assert(_getterPropertyKind == null, |
| "Unexpected setter property kind for $_setter"); |
| _getterPropertyKind == propertyKind; |
| return true; |
| } |
| } else { |
| if (declaration.isAugment) { |
| // Example: |
| // |
| // int get foo => 42; |
| // augment int get foo => 87; |
| // |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| 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; |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| return false; |
| } |
| } |
| case _PropertyKind.Setter: |
| if (_setter == 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) { |
| if (declaration.isStatic) { |
| // Example: |
| // |
| // class A { |
| // int get foo => 42; |
| // static void set foo(_) {} |
| // } |
| // |
| problemReporting.addProblem2( |
| templateStaticConflictsWithInstance.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateStaticConflictsWithInstanceCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| return false; |
| } else { |
| // Example: |
| // |
| // class A { |
| // static int get foo => 42; |
| // void set foo(_) {} |
| // } |
| // |
| problemReporting.addProblem2( |
| templateInstanceConflictsWithStatic.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateInstanceConflictsWithStaticCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| return false; |
| } |
| } else { |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| assert( |
| declarations.field == null, |
| "Unexpected field declaration from setter " |
| "${declaration}."); |
| assert( |
| declarations.getter == null, |
| "Unexpected getter declaration from setter " |
| "${declaration}."); |
| _setter = declarations.setter; |
| assert(_setterPropertyKind == null, |
| "Unexpected setter property kind for $_getter"); |
| _setterPropertyKind == propertyKind; |
| return true; |
| } |
| } else { |
| if (declaration.isAugment) { |
| // Example: |
| // |
| // void set foo(_) {} |
| // augment void set foo(_) {} |
| // |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| 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 { |
| if (_setterPropertyKind == _PropertyKind.Field) { |
| // Example: |
| // |
| // int? foo; |
| // void set foo(_) {} |
| // |
| problemReporting.addProblem2( |
| templateConflictsWithImplicitSetter.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateConflictsWithImplicitSetterCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| return false; |
| } else { |
| // Example: |
| // |
| // void set foo(_) {} |
| // void set foo(_) {} |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| return false; |
| } |
| } |
| } |
| case _PropertyKind.Field: |
| if (_getter == null) { |
| // Example: |
| // |
| // void set foo(_) {} |
| // int? foo; |
| // |
| assert(_getter == null && _setter != null); |
| // We have an explicit setter. |
| problemReporting.addProblem2( |
| templateConflictsWithSetter.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateConflictsWithSetterCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| return false; |
| } else if (_setter != 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(_getter != null && _setter != null); |
| // We have both getter and setter |
| if (declaration.isAugment) { |
| // Coverage-ignore-block(suite): Not run. |
| if (_getterPropertyKind == declaration.propertyKind) { |
| // Example: |
| // |
| // int foo = 42; |
| // augment int foo = 87; |
| // |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| // 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; |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| |
| return false; |
| } |
| } else { |
| // Examples: |
| // |
| // int get foo => 42; |
| // int? foo; |
| // |
| // final int bar = 42; |
| // int? bar; |
| // |
| assert(_getter != null && _setter == null); |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| return false; |
| } |
| case _PropertyKind.FinalField: |
| if (_getter == null) { |
| // Example: |
| // |
| // void set foo(_) {} |
| // final int foo = 42; |
| // |
| assert(_getter == null && _setter != 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. |
| if (declaration.isStatic) { |
| // Example: |
| // |
| // class A { |
| // void set foo(_) {} |
| // static final int foo = 42; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateStaticConflictsWithInstance.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateStaticConflictsWithInstanceCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| return false; |
| } else { |
| // Example: |
| // |
| // class A { |
| // static void set foo(_) {} |
| // final int foo = 42; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateInstanceConflictsWithStatic.withArguments(name), |
| declaration.uriOffset, |
| context: [ |
| templateInstanceConflictsWithStaticCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| return false; |
| } |
| } else { |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| assert( |
| declarations.setter == null, |
| "Unexpected setter declaration from field " |
| "${declaration}."); |
| _field = declarations.field; |
| _getter = declarations.getter; |
| assert( |
| _getterPropertyKind == null, |
| "Unexpected getter property kind $_getterPropertyKind for " |
| "$_setter."); |
| _getterPropertyKind = propertyKind; |
| 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 (_getterPropertyKind == declaration.propertyKind) { |
| // Example: |
| // |
| // final int foo = 42; |
| // augment final int foo = 87; |
| // |
| _PropertyDeclarations declarations = |
| declaration.createDeclarations(); |
| 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; |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| return false; |
| } |
| } |
| } |
| } |
| |
| @override |
| void checkFragment( |
| ProblemReporting problemReporting, _Declaration constructorDeclaration) { |
| // Check conflict with constructor. |
| if (isStatic) { |
| if (_getter != null) { |
| if (constructorDeclaration.kind == _DeclarationKind.Constructor) { |
| // Example: |
| // |
| // class A { |
| // static int get foo => 42; |
| // A.foo(); |
| // } |
| // |
| problemReporting.addProblem2( |
| templateConstructorConflictsWithMember.withArguments(name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateConstructorConflictsWithMemberCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| } else { |
| // Coverage-ignore-block(suite): Not run. |
| assert(constructorDeclaration.kind == _DeclarationKind.Factory, |
| "Unexpected constructor kind $constructorDeclaration"); |
| // Example: |
| // |
| // class A { |
| // static int get foo => 42; |
| // factory A.foo() => throw ''; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateFactoryConflictsWithMember.withArguments(name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateFactoryConflictsWithMemberCause |
| .withArguments(name) |
| .withLocation2(_getter!.uriOffset) |
| ]); |
| } |
| } else { |
| // Coverage-ignore-block(suite): Not run. |
| if (constructorDeclaration.kind == _DeclarationKind.Constructor) { |
| // Example: |
| // |
| // class A { |
| // static void set foo(_) {} |
| // A.foo(); |
| // } |
| // |
| problemReporting.addProblem2( |
| templateConstructorConflictsWithMember.withArguments(name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateConstructorConflictsWithMemberCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| } else { |
| assert(constructorDeclaration.kind == _DeclarationKind.Factory, |
| "Unexpected constructor kind $constructorDeclaration"); |
| // Example: |
| // |
| // class A { |
| // static void set foo(_) {} |
| // factory A.foo() => throw ''; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateFactoryConflictsWithMember.withArguments(name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateFactoryConflictsWithMemberCause |
| .withArguments(name) |
| .withLocation2(_setter!.uriOffset) |
| ]); |
| } |
| } |
| } |
| } |
| |
| @override |
| void createBuilders(_CreateBuilderFunction createBuilder, |
| _CreatePropertyFunction createProperty) { |
| createProperty( |
| name: name, |
| inPatch: inPatch, |
| isStatic: isStatic, |
| uriOffset: uriOffset, |
| fieldDeclaration: _field, |
| getterDeclaration: _getter, |
| getterAugmentationDeclarations: _getterAugmentations, |
| setterDeclaration: _setter, |
| setterAugmentationDeclarations: _setterAugmentations); |
| } |
| } |
| |
| /// [_PreBuilder] for generative and factory constructors. |
| class _ConstructorPreBuilder extends _PreBuilder { |
| final _ConstructorDeclaration _declaration; |
| final List<_ConstructorDeclaration> _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 _ConstructorDeclaration && |
| 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(); |
| // } |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(declaration.name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| return false; |
| } |
| } |
| |
| @override |
| void checkFragment(ProblemReporting problemReporting, |
| _Declaration nonConstructorDeclaration) { |
| // Check conflict with non-constructor. |
| if (nonConstructorDeclaration.isStatic) { |
| // Coverage-ignore-block(suite): Not run. |
| if (_declaration.kind == _DeclarationKind.Constructor) { |
| // Example: |
| // |
| // class A { |
| // A.foo(); |
| // static void foo() {} |
| // } |
| // |
| problemReporting.addProblem2( |
| templateMemberConflictsWithConstructor |
| .withArguments(_declaration.name), |
| nonConstructorDeclaration.uriOffset, |
| context: [ |
| templateMemberConflictsWithConstructorCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } else { |
| assert(_declaration.kind == _DeclarationKind.Factory, |
| "Unexpected constructor kind $_declaration"); |
| // Example: |
| // |
| // class A { |
| // factory A.foo() => throw ''; |
| // static void foo() {} |
| // } |
| // |
| problemReporting.addProblem2( |
| templateMemberConflictsWithFactory.withArguments(_declaration.name), |
| nonConstructorDeclaration.uriOffset, |
| context: [ |
| templateMemberConflictsWithFactoryCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } |
| } |
| } |
| |
| @override |
| void createBuilders(_CreateBuilderFunction createBuilder, |
| _CreatePropertyFunction createProperty) { |
| createBuilder(_declaration._fragment, |
| augmentations: _augmentations.map((f) => f._fragment).toList()); |
| } |
| } |
| |
| /// [_PreBuilder] for non-constructor, non-property declarations. |
| class _DeclarationPreBuilder extends _PreBuilder { |
| final _Declaration _declaration; |
| final List<_Declaration> _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); |
| return true; |
| } else { |
| // Example: |
| // |
| // class Foo {} |
| // augment extension Foo {} |
| // |
| // TODO(johnniwinther): Report augmentation conflict. |
| return false; |
| } |
| } else { |
| if (declaration is _PropertyDeclaration && |
| declaration.propertyKind == _PropertyKind.Setter) { |
| // Example: |
| // |
| // class Foo {} |
| // set Foo(_) {} |
| // |
| problemReporting.addProblem2( |
| templateSetterConflictsWithDeclaration |
| .withArguments(_declaration.name), |
| declaration.uriOffset, |
| context: [ |
| templateSetterConflictsWithDeclarationCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } else { |
| // Example: |
| // |
| // class Foo {} |
| // class Foo {} |
| // |
| problemReporting.addProblem2( |
| templateDuplicatedDeclaration.withArguments(declaration.name), |
| declaration.uriOffset, |
| context: <LocatedMessage>[ |
| templateDuplicatedDeclarationCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } |
| return false; |
| } |
| } |
| |
| @override |
| void checkFragment( |
| ProblemReporting problemReporting, _Declaration constructorDeclaration) { |
| // Check conflict with constructor. |
| if (_declaration.isStatic) { |
| if (constructorDeclaration.kind == _DeclarationKind.Constructor) { |
| // Example: |
| // |
| // class A { |
| // static void foo() {} |
| // A.foo(); |
| // } |
| // |
| problemReporting.addProblem2( |
| templateConstructorConflictsWithMember |
| .withArguments(_declaration.name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateConstructorConflictsWithMemberCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } else { |
| assert(constructorDeclaration.kind == _DeclarationKind.Factory, |
| "Unexpected constructor kind $constructorDeclaration"); |
| // Example: |
| // |
| // class A { |
| // static void foo() {} |
| // factory A.foo() => throw ''; |
| // } |
| // |
| problemReporting.addProblem2( |
| templateFactoryConflictsWithMember.withArguments(_declaration.name), |
| constructorDeclaration.uriOffset, |
| context: [ |
| templateFactoryConflictsWithMemberCause |
| .withArguments(_declaration.name) |
| .withLocation2(_declaration.uriOffset) |
| ]); |
| } |
| } |
| } |
| |
| @override |
| void createBuilders(_CreateBuilderFunction createBuilder, |
| _CreatePropertyFunction createProperty) { |
| createBuilder(_declaration._fragment, |
| augmentations: _augmentations.map((f) => f._fragment).toList()); |
| } |
| } |
| |
| /// Reports an error if [fragmentName] 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 fragmentName) { |
| if (fragmentName.isAugment) { |
| Message message; |
| switch (fragmentName._fragment) { |
| case ClassFragment(): |
| message = fragmentName.inPatch |
| ? templateUnmatchedPatchClass.withArguments(fragmentName.name) |
| : |
| // Coverage-ignore(suite): Not run. |
| templateUnmatchedAugmentationClass.withArguments(fragmentName.name); |
| case ConstructorFragment(): |
| case FactoryFragment(): |
| case FieldFragment(): |
| case GetterFragment(): |
| case MethodFragment(): |
| case PrimaryConstructorFragment(): |
| case SetterFragment(): |
| case PrimaryConstructorFieldFragment(): |
| if (fragmentName.inLibrary) { |
| message = fragmentName.inPatch |
| ? templateUnmatchedPatchLibraryMember |
| .withArguments(fragmentName.name) |
| : |
| // Coverage-ignore(suite): Not run. |
| templateUnmatchedAugmentationLibraryMember |
| .withArguments(fragmentName.name); |
| } else { |
| message = fragmentName.inPatch |
| ? templateUnmatchedPatchClassMember |
| .withArguments(fragmentName.name) |
| : |
| // Coverage-ignore(suite): Not run. |
| templateUnmatchedAugmentationClassMember |
| .withArguments(fragmentName.name); |
| } |
| case EnumFragment(): |
| case EnumElementFragment(): |
| case ExtensionFragment(): |
| // Coverage-ignore(suite): Not run. |
| case ExtensionTypeFragment(): |
| // Coverage-ignore(suite): Not run. |
| case MixinFragment(): |
| // Coverage-ignore(suite): Not run. |
| case NamedMixinApplicationFragment(): |
| // Coverage-ignore(suite): Not run. |
| case TypedefFragment(): |
| // TODO(johnniwinther): Specialize more messages. |
| message = fragmentName.inPatch |
| ? templateUnmatchedPatchDeclaration.withArguments(fragmentName.name) |
| : |
| // Coverage-ignore(suite): Not run. |
| templateUnmatchedAugmentationDeclaration |
| .withArguments(fragmentName.name); |
| } |
| problemReporting.addProblem2(message, fragmentName.uriOffset); |
| } |
| } |
| |
| void _computeBuildersFromFragments(String name, List<Fragment> fragments, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required Map<SourceClassBuilder, TypeBuilder> mixinApplications, |
| required List<_AddBuilder> builders, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| IndexedContainer? indexedContainer, |
| ContainerName? containerName}) { |
| List<_PreBuilder> nonConstructorPreBuilders = []; |
| List<_PreBuilder> constructorPreBuilders = []; |
| List<Fragment> unnamedFragments = []; |
| |
| for (Fragment fragment in fragments) { |
| _Declaration? fragmentName; |
| switch (fragment) { |
| case ClassFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Class, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case EnumFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Enum, fragment, |
| name: fragment.name, |
| // TODO(johnniwinther): Support enum augmentations. |
| isAugment: false, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case ExtensionTypeFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.ExtensionType, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case MethodFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Method, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| isStatic: declarationBuilder == null || fragment.modifiers.isStatic, |
| inPatch: fragment.enclosingDeclaration?.isPatch ?? |
| fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case MixinFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Mixin, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case NamedMixinApplicationFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.NamedMixinApplication, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case TypedefFragment(): |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Typedef, fragment, |
| name: fragment.name, |
| // TODO(johnniwinther): Support typedef augmentations. |
| isAugment: false, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| case ExtensionFragment(): |
| if (!fragment.isUnnamed) { |
| fragmentName = new _StandardFragmentDeclaration( |
| _DeclarationKind.Extension, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: true, |
| ); |
| } else { |
| unnamedFragments.add(fragment); |
| } |
| case FactoryFragment(): |
| fragmentName = new _ConstructorFragmentDeclaration( |
| _DeclarationKind.Factory, |
| fragment, |
| name: fragment.constructorName.fullName, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingDeclaration.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case ConstructorFragment(): |
| fragmentName = new _ConstructorFragmentDeclaration( |
| _DeclarationKind.Constructor, |
| fragment, |
| name: fragment.constructorName.fullName, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingDeclaration.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case PrimaryConstructorFragment(): |
| fragmentName = new _ConstructorFragmentDeclaration( |
| _DeclarationKind.Constructor, |
| fragment, |
| name: fragment.constructorName.fullName, |
| isAugment: fragment.modifiers.isAugment, |
| inPatch: fragment.enclosingDeclaration.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case FieldFragment(): |
| fragmentName = new _FieldDeclaration( |
| _DeclarationKind.Property, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| propertyKind: fragment.hasSetter |
| ? _PropertyKind.Field |
| : _PropertyKind.FinalField, |
| isStatic: declarationBuilder == null || fragment.modifiers.isStatic, |
| inPatch: fragment.enclosingDeclaration?.isPatch ?? |
| fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case PrimaryConstructorFieldFragment(): |
| fragmentName = new _FieldDeclaration( |
| _DeclarationKind.Property, |
| fragment, |
| name: fragment.name, |
| isAugment: false, |
| propertyKind: _PropertyKind.FinalField, |
| isStatic: false, |
| inPatch: fragment.enclosingDeclaration.isPatch, |
| inLibrary: false, |
| ); |
| case GetterFragment(): |
| fragmentName = new _GetterDeclaration( |
| _DeclarationKind.Property, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| propertyKind: _PropertyKind.Getter, |
| isStatic: declarationBuilder == null || fragment.modifiers.isStatic, |
| inPatch: fragment.enclosingDeclaration?.isPatch ?? |
| fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case SetterFragment(): |
| fragmentName = new _SetterDeclaration( |
| _DeclarationKind.Property, |
| fragment, |
| name: fragment.name, |
| isAugment: fragment.modifiers.isAugment, |
| propertyKind: _PropertyKind.Setter, |
| isStatic: declarationBuilder == null || fragment.modifiers.isStatic, |
| inPatch: fragment.enclosingDeclaration?.isPatch ?? |
| fragment.enclosingCompilationUnit.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| case EnumElementFragment(): |
| fragmentName = new _FieldDeclaration( |
| _DeclarationKind.Property, |
| fragment, |
| name: fragment.name, |
| isAugment: false, |
| propertyKind: _PropertyKind.FinalField, |
| isStatic: true, |
| inPatch: fragment.enclosingDeclaration.isPatch, |
| inLibrary: declarationBuilder == null, |
| ); |
| } |
| |
| fragmentName?.registerPreBuilder( |
| problemReporting, nonConstructorPreBuilders, constructorPreBuilders); |
| } |
| |
| void createBuilder(Fragment fragment, |
| {bool conflictingSetter = false, List<Fragment>? augmentations}) { |
| switch (fragment) { |
| case TypedefFragment(): |
| builders.add(_createTypedefBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case ClassFragment(): |
| builders.add(_createClassBuilder(fragment, augmentations, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case MixinFragment(): |
| builders.add(_createMixinBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case NamedMixinApplicationFragment(): |
| builders.add(_createNamedMixinApplicationBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| mixinApplications: mixinApplications, |
| indexedLibrary: indexedLibrary)); |
| case EnumFragment(): |
| builders.add(_createEnumBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case ExtensionFragment(): |
| builders.add(_createExtensionBuilder(fragment, augmentations, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case ExtensionTypeFragment(): |
| builders.add(_createExtensionTypeBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary)); |
| case MethodFragment(): |
| builders.add(_createMethodBuilder(fragment, augmentations, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName)); |
| case ConstructorFragment(): |
| builders.add(_createConstructorBuilder(fragment, augmentations, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName)); |
| case PrimaryConstructorFragment(): |
| builders.add(_createPrimaryConstructorBuilder(fragment, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName)); |
| case FactoryFragment(): |
| builders.add(_createFactoryBuilder(fragment, augmentations, |
| problemReporting: problemReporting, |
| loader: loader, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName)); |
| // Coverage-ignore(suite): Not run. |
| 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 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}) { |
| builders.add(_createPropertyBuilder( |
| problemReporting: problemReporting, |
| loader: loader, |
| name: name, |
| uriOffset: uriOffset, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| fieldDeclaration: fieldDeclaration, |
| getterDeclaration: getterDeclaration, |
| getterAugmentations: getterAugmentationDeclarations ?? const [], |
| setterDeclaration: setterDeclaration, |
| setterAugmentations: setterAugmentationDeclarations ?? const [], |
| containerName: containerName, |
| containerType: containerType, |
| indexedLibrary: indexedLibrary, |
| indexedContainer: indexedContainer, |
| isStatic: isStatic, |
| inPatch: inPatch)); |
| } |
| |
| for (_PreBuilder preBuilder in nonConstructorPreBuilders) { |
| preBuilder.createBuilders(createBuilder, createProperty); |
| } |
| for (_PreBuilder preBuilder in constructorPreBuilders) { |
| preBuilder.createBuilders(createBuilder, createProperty); |
| } |
| for (Fragment fragment in unnamedFragments) { |
| createBuilder(fragment); |
| } |
| } |
| |
| class LibraryNameSpaceBuilder { |
| List<Fragment> _fragments = []; |
| |
| void addFragment(Fragment fragment) { |
| _fragments.add(fragment); |
| } |
| |
| void includeBuilders(LibraryNameSpaceBuilder other) { |
| _fragments.addAll(other._fragments); |
| } |
| |
| bool _allowInjectedPublicMember( |
| SourceLibraryBuilder enclosingLibraryBuilder, Builder newBuilder) { |
| return enclosingLibraryBuilder.importUri.isScheme("dart") && |
| enclosingLibraryBuilder.importUri.path.startsWith("_"); |
| } |
| |
| MutableNameSpace toNameSpace({ |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required IndexedLibrary? indexedLibrary, |
| required ProblemReporting problemReporting, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required Map<SourceClassBuilder, TypeBuilder> mixinApplications, |
| required List<NamedBuilder> memberBuilders, |
| }) { |
| Map<String, LookupResult> content = {}; |
| Set<ExtensionBuilder> extensions = {}; |
| |
| void _addBuilder(_AddBuilder addBuilder) { |
| String name = addBuilder.name; |
| NamedBuilder declaration = addBuilder.declaration; |
| UriOffsetLength uriOffset = addBuilder.uriOffset; |
| |
| assert(declaration.next == null, |
| "Unexpected declaration.next ${declaration.next} on $declaration"); |
| |
| memberBuilders.add(declaration); |
| |
| if (declaration is SourceExtensionBuilder && |
| declaration.isUnnamedExtension) { |
| extensions.add(declaration); |
| return; |
| } |
| |
| if (declaration is MemberBuilder || |
| declaration is TypeDeclarationBuilder) { |
| // Expected. |
| } else { |
| // Coverage-ignore-block(suite): Not run. |
| // Prefix builders are added when computing the import scope. |
| assert(declaration is! PrefixBuilder, |
| "Unexpected prefix builder $declaration."); |
| unhandled("${declaration.runtimeType}", "addBuilder", |
| uriOffset.fileOffset, uriOffset.fileUri); |
| } |
| |
| assert( |
| !(declaration is FunctionBuilder && |
| // Coverage-ignore(suite): Not run. |
| (declaration is ConstructorBuilder || |
| declaration is FactoryBuilder)), |
| "Unexpected constructor in library: $declaration."); |
| |
| if (addBuilder.inPatch && |
| !name.startsWith('_') && |
| !_allowInjectedPublicMember(enclosingLibraryBuilder, declaration)) { |
| problemReporting.addProblem2( |
| templatePatchInjectionFailed.withArguments( |
| name, enclosingLibraryBuilder.importUri), |
| uriOffset); |
| } |
| |
| LookupResult? existingResult = content[name]; |
| NamedBuilder? existing = |
| existingResult?.getable ?? existingResult?.setable; |
| |
| assert( |
| existing != declaration, "Unexpected existing declaration $existing"); |
| |
| if (declaration.next != null && |
| // Coverage-ignore(suite): Not run. |
| declaration.next != existing) { |
| unexpected( |
| "${declaration.next!.fileUri}@${declaration.next!.fileOffset}", |
| "${existing?.fileUri}@${existing?.fileOffset}", |
| declaration.fileOffset, |
| declaration.fileUri); |
| } |
| declaration.next = existing; |
| if (declaration is SourceExtensionBuilder && !declaration.isDuplicate) { |
| // We add the extension declaration to the extension scope only if its |
| // name is unique. Only the first of duplicate extensions is accessible |
| // by name or by resolution and the remaining are dropped for the |
| // output. |
| extensions.add(declaration); |
| } |
| content[name] = declaration as LookupResult; |
| } |
| |
| Map<String, List<Fragment>> fragmentsByName = {}; |
| for (Fragment fragment in _fragments) { |
| (fragmentsByName[fragment.name] ??= []).add(fragment); |
| } |
| |
| for (MapEntry<String, List<Fragment>> entry in fragmentsByName.entries) { |
| List<_AddBuilder> addBuilders = []; |
| _computeBuildersFromFragments(entry.key, entry.value, |
| loader: enclosingLibraryBuilder.loader, |
| problemReporting: problemReporting, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| mixinApplications: mixinApplications, |
| builders: addBuilders, |
| indexedLibrary: indexedLibrary, |
| containerType: ContainerType.Library); |
| for (_AddBuilder addBuilder in addBuilders) { |
| _addBuilder(addBuilder); |
| } |
| } |
| return new SourceLibraryNameSpace(content: content, extensions: extensions); |
| } |
| } |
| |
| class NominalParameterScope extends AbstractTypeParameterScope { |
| final NominalParameterNameSpace _nameSpace; |
| |
| NominalParameterScope(super._parent, this._nameSpace); |
| |
| @override |
| TypeParameterBuilder? getTypeParameter(String name) => |
| _nameSpace.getTypeParameter(name); |
| } |
| |
| class NominalParameterNameSpace { |
| Map<String, SourceNominalParameterBuilder> _typeParametersByName = {}; |
| |
| SourceNominalParameterBuilder? getTypeParameter(String name) => |
| _typeParametersByName[name]; |
| |
| void addTypeParameters(ProblemReporting _problemReporting, |
| List<SourceNominalParameterBuilder>? typeParameters, |
| {required String? ownerName, required bool allowNameConflict}) { |
| if (typeParameters == null || typeParameters.isEmpty) return; |
| for (SourceNominalParameterBuilder tv in typeParameters) { |
| SourceNominalParameterBuilder? existing = _typeParametersByName[tv.name]; |
| if (tv.isWildcard) continue; |
| if (existing != null) { |
| if (existing.kind == TypeParameterKind.extensionSynthesized) { |
| // The type parameter from the extension is shadowed by the type |
| // parameter from the member. Rename the shadowed type parameter. |
| existing.parameter.name = '#${existing.name}'; |
| _typeParametersByName[tv.name] = tv; |
| } else { |
| _problemReporting.addProblem(messageTypeParameterDuplicatedName, |
| tv.fileOffset, tv.name.length, tv.fileUri, |
| context: [ |
| templateTypeParameterDuplicatedNameCause |
| .withArguments(tv.name) |
| .withLocation(existing.fileUri, existing.fileOffset, |
| existing.name.length) |
| ]); |
| } |
| } else { |
| _typeParametersByName[tv.name] = tv; |
| // Only classes and extension types and type parameters can't have the |
| // same name. See |
| // [#29555](https://github.com/dart-lang/sdk/issues/29555) and |
| // [#54602](https://github.com/dart-lang/sdk/issues/54602). |
| if (tv.name == ownerName && !allowNameConflict) { |
| _problemReporting.addProblem(messageTypeParameterSameNameAsEnclosing, |
| tv.fileOffset, tv.name.length, tv.fileUri); |
| } |
| } |
| } |
| } |
| } |
| |
| enum DeclarationFragmentKind { |
| classDeclaration, |
| mixinDeclaration, |
| enumDeclaration, |
| extensionDeclaration, |
| extensionTypeDeclaration, |
| } |
| |
| abstract class DeclarationFragmentImpl implements DeclarationFragment { |
| final Uri fileUri; |
| |
| /// The scope in which the declaration is declared. |
| /// |
| /// This is the scope of the enclosing compilation unit and it's used for |
| /// resolving metadata on the declaration. |
| final LookupScope enclosingScope; |
| |
| final LookupScope typeParameterScope; |
| final DeclarationBuilderScope bodyScope; |
| final List<Fragment> _fragments = []; |
| |
| @override |
| final List<TypeParameterFragment>? typeParameters; |
| |
| final NominalParameterNameSpace nominalParameterNameSpace; |
| |
| final LibraryFragment enclosingCompilationUnit; |
| |
| DeclarationFragmentImpl({ |
| required this.fileUri, |
| required this.typeParameters, |
| required this.enclosingScope, |
| required this.typeParameterScope, |
| required NominalParameterNameSpace nominalParameterNameSpace, |
| required this.enclosingCompilationUnit, |
| }) : nominalParameterNameSpace = nominalParameterNameSpace, |
| bodyScope = new DeclarationBuilderScope(typeParameterScope); |
| |
| String get name; |
| |
| DeclarationFragmentKind get kind; |
| |
| bool declaresConstConstructor = false; |
| |
| DeclarationBuilder get builder; |
| |
| UriOffsetLength get uriOffset; |
| |
| void addPrimaryConstructorField(PrimaryConstructorFieldFragment fragment) { |
| throw new UnsupportedError( |
| "Unexpected primary constructor field in $this."); |
| } |
| |
| void addEnumElement(EnumElementFragment fragment) { |
| throw new UnsupportedError("Unexpected enum element in $this."); |
| } |
| |
| void addFragment(Fragment fragment) { |
| _fragments.add(fragment); |
| } |
| |
| DeclarationNameSpaceBuilder toDeclarationNameSpaceBuilder() { |
| return new DeclarationNameSpaceBuilder._( |
| name, nominalParameterNameSpace, _fragments); |
| } |
| } |
| |
| class _AddBuilder { |
| final String name; |
| final NamedBuilder declaration; |
| final UriOffsetLength uriOffset; |
| final bool inPatch; |
| |
| _AddBuilder(this.name, this.declaration, this.uriOffset, |
| {required this.inPatch}); |
| } |
| |
| class DeclarationNameSpaceBuilder { |
| final String _name; |
| final NominalParameterNameSpace? _nominalParameterNameSpace; |
| final List<Fragment> _fragments; |
| |
| DeclarationNameSpaceBuilder.empty() |
| : _name = '', |
| _nominalParameterNameSpace = null, |
| _fragments = const []; |
| |
| DeclarationNameSpaceBuilder._( |
| this._name, this._nominalParameterNameSpace, this._fragments); |
| |
| void includeBuilders(DeclarationNameSpaceBuilder other) { |
| _fragments.addAll(other._fragments); |
| other._fragments.clear(); |
| } |
| |
| bool _allowInjectedPublicMember( |
| SourceLibraryBuilder enclosingLibraryBuilder, Builder newBuilder) { |
| if (enclosingLibraryBuilder.importUri.isScheme("dart") && |
| enclosingLibraryBuilder.importUri.path.startsWith("_")) { |
| return true; |
| } |
| if (newBuilder.isStatic) { |
| return _name.startsWith('_'); |
| } |
| // TODO(johnniwinther): Restrict the use of injected public class members. |
| return true; |
| } |
| |
| void checkTypeParameterConflict(ProblemReporting _problemReporting, |
| String name, Builder member, Uri fileUri) { |
| if (_nominalParameterNameSpace != null) { |
| NominalParameterBuilder? tv = |
| _nominalParameterNameSpace.getTypeParameter(name); |
| if (tv != null) { |
| _problemReporting.addProblem( |
| templateConflictsWithTypeParameter.withArguments(name), |
| member.fileOffset, |
| name.length, |
| fileUri, |
| context: [ |
| messageConflictsWithTypeParameterCause.withLocation( |
| tv.fileUri!, tv.fileOffset, name.length) |
| ]); |
| } |
| } |
| } |
| |
| MutableDeclarationNameSpace buildNameSpace( |
| {required SourceLoader loader, |
| required ProblemReporting problemReporting, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder declarationBuilder, |
| required IndexedLibrary? indexedLibrary, |
| required IndexedContainer? indexedContainer, |
| required ContainerType containerType, |
| required ContainerName containerName, |
| required List<SourceMemberBuilder> constructorBuilders, |
| required List<SourceMemberBuilder> memberBuilders}) { |
| List<NominalParameterBuilder> unboundNominalParameters = []; |
| Map<String, LookupResult> content = {}; |
| Map<String, MemberBuilder> constructors = {}; |
| |
| Map<String, List<Fragment>> fragmentsByName = {}; |
| for (Fragment fragment in _fragments) { |
| (fragmentsByName[fragment.name] ??= []).add(fragment); |
| } |
| |
| void _addBuilder(_AddBuilder addBuilder) { |
| String name = addBuilder.name; |
| NamedBuilder declaration = addBuilder.declaration; |
| UriOffsetLength uriOffset = addBuilder.uriOffset; |
| |
| assert(declaration.next == null, |
| "Unexpected declaration.next ${declaration.next} on $declaration"); |
| |
| bool isConstructor = |
| declaration is ConstructorBuilder || declaration is FactoryBuilder; |
| if (!isConstructor && name == _name) { |
| problemReporting.addProblem2( |
| messageMemberWithSameNameAsClass, uriOffset); |
| } |
| if (isConstructor) { |
| constructorBuilders.add(declaration as SourceMemberBuilder); |
| } else { |
| memberBuilders.add(declaration as SourceMemberBuilder); |
| } |
| |
| if (addBuilder.inPatch && |
| !name.startsWith('_') && |
| !_allowInjectedPublicMember(enclosingLibraryBuilder, declaration)) { |
| // TODO(johnniwinther): Test adding a no-name constructor in the |
| // patch, either as an injected or duplicated constructor. |
| problemReporting.addProblem2( |
| templatePatchInjectionFailed.withArguments( |
| name, enclosingLibraryBuilder.importUri), |
| uriOffset); |
| } |
| |
| if (isConstructor) { |
| NamedBuilder? existing = constructors[name]; |
| |
| assert(existing != declaration, |
| "Unexpected existing declaration $existing"); |
| |
| if (declaration.next != null && |
| // Coverage-ignore(suite): Not run. |
| declaration.next != existing) { |
| unexpected( |
| "${declaration.next!.fileUri}@${declaration.next!.fileOffset}", |
| "${existing?.fileUri}@${existing?.fileOffset}", |
| declaration.fileOffset, |
| declaration.fileUri); |
| } |
| declaration.next = existing; |
| constructors[name] = declaration as MemberBuilder; |
| } else { |
| LookupResult? existingResult = content[name]; |
| NamedBuilder? existing = |
| existingResult?.getable ?? existingResult?.setable; |
| |
| assert(existing != declaration, |
| "Unexpected existing declaration $existing"); |
| |
| if (declaration.next != null && |
| // Coverage-ignore(suite): Not run. |
| declaration.next != existing) { |
| unexpected( |
| "${declaration.next!.fileUri}@${declaration.next!.fileOffset}", |
| "${existing?.fileUri}@${existing?.fileOffset}", |
| declaration.fileOffset, |
| declaration.fileUri); |
| } |
| declaration.next = existing; |
| content[name] = declaration as LookupResult; |
| } |
| } |
| |
| for (MapEntry<String, List<Fragment>> entry in fragmentsByName.entries) { |
| List<_AddBuilder> addBuilders = []; |
| _computeBuildersFromFragments(entry.key, entry.value, |
| loader: loader, |
| problemReporting: problemReporting, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| builders: addBuilders, |
| unboundNominalParameters: unboundNominalParameters, |
| // TODO(johnniwinther): Avoid passing this: |
| mixinApplications: const {}, |
| indexedLibrary: indexedLibrary, |
| indexedContainer: indexedContainer, |
| containerType: containerType, |
| containerName: containerName); |
| for (_AddBuilder addBuilder in addBuilders) { |
| _addBuilder(addBuilder); |
| } |
| } |
| |
| void checkConflicts(String name, Builder member) { |
| checkTypeParameterConflict( |
| problemReporting, name, member, member.fileUri!); |
| } |
| |
| content.forEach((String name, LookupResult lookupResult) { |
| NamedBuilder member = (lookupResult.getable ?? lookupResult.setable)!; |
| checkTypeParameterConflict( |
| problemReporting, name, member, member.fileUri!); |
| }); |
| constructors.forEach(checkConflicts); |
| |
| enclosingLibraryBuilder |
| .registerUnboundNominalParameters(unboundNominalParameters); |
| |
| return new SourceDeclarationNameSpace( |
| content: content, constructors: constructors); |
| } |
| } |
| |
| enum TypeScopeKind { |
| library, |
| declarationTypeParameters, |
| classDeclaration, |
| mixinDeclaration, |
| enumDeclaration, |
| extensionDeclaration, |
| extensionTypeDeclaration, |
| memberTypeParameters, |
| functionTypeParameters, |
| unnamedMixinApplication, |
| } |
| |
| class TypeScope { |
| final TypeScopeKind kind; |
| |
| List<NamedTypeBuilder> _unresolvedNamedTypes = []; |
| |
| List<TypeScope> _childScopes = []; |
| |
| final LookupScope lookupScope; |
| |
| TypeScope(this.kind, this.lookupScope, [TypeScope? parent]) { |
| parent?._childScopes.add(this); |
| } |
| |
| void registerUnresolvedNamedType(NamedTypeBuilder namedTypeBuilder) { |
| _unresolvedNamedTypes.add(namedTypeBuilder); |
| } |
| |
| int resolveTypes(ProblemReporting problemReporting) { |
| int typeCount = _unresolvedNamedTypes.length; |
| if (_unresolvedNamedTypes.isNotEmpty) { |
| for (NamedTypeBuilder namedTypeBuilder in _unresolvedNamedTypes) { |
| namedTypeBuilder.resolveIn(lookupScope, namedTypeBuilder.charOffset!, |
| namedTypeBuilder.fileUri!, problemReporting); |
| } |
| _unresolvedNamedTypes.clear(); |
| } |
| for (TypeScope childScope in _childScopes) { |
| typeCount += childScope.resolveTypes(problemReporting); |
| } |
| return typeCount; |
| } |
| |
| // Coverage-ignore(suite): Not run. |
| bool get isEmpty => _unresolvedNamedTypes.isEmpty && _childScopes.isEmpty; |
| |
| @override |
| String toString() => 'TypeScope($kind,$_unresolvedNamedTypes)'; |
| } |
| |
| List<SourceNominalParameterBuilder>? createNominalParameterBuilders( |
| List<TypeParameterFragment>? fragments, |
| List<NominalParameterBuilder> unboundNominalParameters) { |
| if (fragments == null) return null; |
| List<SourceNominalParameterBuilder> list = []; |
| for (TypeParameterFragment fragment in fragments) { |
| list.add(createNominalParameterBuilder(fragment, unboundNominalParameters)); |
| } |
| return list; |
| } |
| |
| SourceNominalParameterBuilder createNominalParameterBuilder( |
| TypeParameterFragment fragment, |
| List<NominalParameterBuilder> unboundNominalParameters) { |
| SourceNominalParameterBuilder builder = new SourceNominalParameterBuilder( |
| new RegularNominalParameterDeclaration(fragment), |
| bound: fragment.bound, |
| variableVariance: fragment.variance); |
| |
| unboundNominalParameters.add(builder); |
| fragment.builder = builder; |
| return builder; |
| } |
| |
| _AddBuilder _createTypedefBuilder(TypedefFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| List<SourceNominalParameterBuilder>? nominalParameters = |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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.buildersCreatedWithReferences[reference] = typedefBuilder; |
| } |
| return new _AddBuilder(fragment.name, typedefBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createClassBuilder( |
| ClassFragment fragment, List<Fragment>? augmentations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| String name = fragment.name; |
| DeclarationNameSpaceBuilder nameSpaceBuilder = |
| fragment.toDeclarationNameSpaceBuilder(); |
| ClassDeclaration introductoryDeclaration = |
| new RegularClassDeclaration(fragment); |
| List<SourceNominalParameterBuilder>? nominalParameters = |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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(messagePatchClassTypeParametersMismatch, |
| augmentation.nameOffset, name.length, augmentation.fileUri, |
| context: [ |
| messagePatchClassOrigin.withLocation( |
| fragment.fileUri, fragment.nameOffset, name.length) |
| ]); |
| |
| // Error recovery. Create fresh type parameters for the |
| // augmentation. |
| augmentation.nominalParameterNameSpace.addTypeParameters( |
| problemReporting, |
| createNominalParameterBuilders( |
| augmentation.typeParameters, unboundNominalParameters), |
| 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.buildersCreatedWithReferences[indexedClass.reference] = classBuilder; |
| } |
| return new _AddBuilder(fragment.name, classBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createMixinBuilder(MixinFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| IndexedClass? indexedClass = |
| indexedLibrary?.lookupIndexedClass(fragment.name); |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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.buildersCreatedWithReferences[indexedClass.reference] = mixinBuilder; |
| } |
| return new _AddBuilder(fragment.name, mixinBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createNamedMixinApplicationBuilder( |
| NamedMixinApplicationFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required Map<SourceClassBuilder, TypeBuilder> mixinApplications, |
| required IndexedLibrary? indexedLibrary}) { |
| List<TypeBuilder> mixins = fragment.mixins.toList(); |
| TypeBuilder mixin = mixins.removeLast(); |
| ClassDeclaration classDeclaration = |
| new NamedMixinApplication(fragment, mixins); |
| |
| String name = fragment.name; |
| |
| IndexedClass? referencesFromIndexedClass; |
| if (indexedLibrary != null) { |
| referencesFromIndexedClass = indexedLibrary.lookupIndexedClass(name); |
| } |
| |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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.buildersCreatedWithReferences[referencesFromIndexedClass.reference] = |
| classBuilder; |
| } |
| return new _AddBuilder(fragment.name, classBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createEnumBuilder(EnumFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| IndexedClass? indexedClass = |
| indexedLibrary?.lookupIndexedClass(fragment.name); |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| List<SourceNominalParameterBuilder>? typeParameters = |
| fragment.typeParameters?.builders; |
| 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.buildersCreatedWithReferences[indexedClass.reference] = enumBuilder; |
| } |
| return new _AddBuilder(fragment.name, enumBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createExtensionBuilder( |
| ExtensionFragment fragment, List<Fragment>? augmentations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| DeclarationNameSpaceBuilder nameSpaceBuilder = |
| fragment.toDeclarationNameSpaceBuilder(); |
| List<SourceNominalParameterBuilder>? nominalParameters = |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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( |
| messagePatchExtensionTypeParametersMismatch, |
| augmentation.nameOrExtensionOffset, |
| nameLength, |
| augmentation.fileUri, |
| context: [ |
| messagePatchExtensionOrigin.withLocation( |
| fragment.fileUri, fragment.nameOrExtensionOffset, nameLength) |
| ]); |
| |
| // Error recovery. Create fresh type parameters for the |
| // augmentation. |
| augmentation.nominalParameterNameSpace.addTypeParameters( |
| problemReporting, |
| createNominalParameterBuilders( |
| augmentation.typeParameters, unboundNominalParameters), |
| 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.buildersCreatedWithReferences[reference] = extensionBuilder; |
| } |
| return new _AddBuilder(fragment.name, extensionBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createExtensionTypeBuilder(ExtensionTypeFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary}) { |
| IndexedContainer? indexedContainer = |
| indexedLibrary?.lookupIndexedExtensionTypeDeclaration(fragment.name); |
| List<PrimaryConstructorFieldFragment> primaryConstructorFields = |
| fragment.primaryConstructorFields; |
| PrimaryConstructorFieldFragment? representationFieldFragment; |
| if (primaryConstructorFields.isNotEmpty) { |
| representationFieldFragment = primaryConstructorFields.first; |
| } |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| 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.buildersCreatedWithReferences[indexedContainer!.reference] = |
| extensionTypeDeclarationBuilder; |
| } |
| return new _AddBuilder( |
| fragment.name, extensionTypeDeclarationBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createPropertyBuilder({ |
| required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required String name, |
| required UriOffsetLength uriOffset, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required FieldDeclaration? fieldDeclaration, |
| required GetterDeclaration? getterDeclaration, |
| required List<GetterDeclaration> getterAugmentations, |
| required SetterDeclaration? setterDeclaration, |
| required List<SetterDeclaration> setterAugmentations, |
| required ContainerName? containerName, |
| required ContainerType containerType, |
| required IndexedLibrary? indexedLibrary, |
| required IndexedContainer? indexedContainer, |
| 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 ??= 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, unboundNominalParameters); |
| for (GetterDeclaration augmentation in getterAugmentations) { |
| augmentation.createGetterEncoding(problemReporting, propertyBuilder, |
| propertyEncodingStrategy, unboundNominalParameters); |
| } |
| |
| setterDeclaration?.createSetterEncoding(problemReporting, propertyBuilder, |
| propertyEncodingStrategy, unboundNominalParameters); |
| for (SetterDeclaration augmentation in setterAugmentations) { |
| augmentation.createSetterEncoding(problemReporting, propertyBuilder, |
| propertyEncodingStrategy, unboundNominalParameters); |
| } |
| |
| references.registerReference(loader, propertyBuilder); |
| |
| return new _AddBuilder(name, propertyBuilder, uriOffset, inPatch: inPatch); |
| } |
| |
| _AddBuilder _createMethodBuilder( |
| MethodFragment fragment, List<Fragment>? augmentations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| required IndexedContainer? indexedContainer, |
| required ContainerName? containerName}) { |
| String name = fragment.name; |
| final bool isInstanceMember = |
| containerType != ContainerType.Library && !fragment.modifiers.isStatic; |
| |
| createNominalParameterBuilders( |
| fragment.declaredTypeParameters, unboundNominalParameters); |
| |
| 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 ??= 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)); |
| |
| createNominalParameterBuilders( |
| augmentation.declaredTypeParameters, unboundNominalParameters); |
| |
| 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, unboundNominalParameters); |
| for (MethodDeclaration augmentation in augmentationDeclarations) { |
| augmentation.createEncoding(problemReporting, methodBuilder, |
| encodingStrategy, unboundNominalParameters); |
| } |
| |
| if (procedureReference != null) { |
| loader.buildersCreatedWithReferences[procedureReference] = methodBuilder; |
| } |
| return new _AddBuilder(fragment.name, methodBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingDeclaration?.isPatch ?? |
| fragment.enclosingCompilationUnit.isPatch); |
| } |
| |
| _AddBuilder _createConstructorBuilder( |
| ConstructorFragment fragment, List<Fragment>? augmentations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| required IndexedContainer? indexedContainer, |
| required ContainerName? containerName}) { |
| String name = fragment.name; |
| bool isConst = fragment.modifiers.isConst; |
| bool isExternal = fragment.modifiers.isExternal; |
| |
| NameScheme nameScheme = new NameScheme( |
| isInstanceMember: false, |
| containerName: containerName, |
| containerType: containerType, |
| libraryName: indexedLibrary != null |
| ? new LibraryName(indexedLibrary.library.reference) |
| : enclosingLibraryBuilder.libraryName); |
| |
| createNominalParameterBuilders( |
| fragment.typeParameters, unboundNominalParameters); |
| |
| ConstructorReferences constructorReferences = new ConstructorReferences( |
| name: name, |
| nameScheme: nameScheme, |
| indexedContainer: indexedContainer, |
| loader: loader, |
| declarationBuilder: declarationBuilder!); |
| |
| ConstructorDeclaration createConstructorDeclaration( |
| ConstructorFragment fragment) { |
| switch (declarationBuilder) { |
| case ExtensionTypeDeclarationBuilder(): |
| List<SourceNominalParameterBuilder>? typeParameters = fragment |
| .typeParameters |
| // Coverage-ignore(suite): Not run. |
| ?.builders; |
| NominalParameterCopy? nominalVariableCopy = |
| NominalParameterCopy.copyTypeParameters( |
| unboundNominalParameters: unboundNominalParameters, |
| oldParameterBuilders: declarationBuilder.typeParameters, |
| oldParameterFragments: |
| fragment.enclosingDeclaration.typeParameters, |
| kind: TypeParameterKind.extensionSynthesized, |
| instanceTypeParameterAccess: |
| InstanceTypeParameterAccessState.Allowed); |
| if (nominalVariableCopy != null) { |
| if (typeParameters != null) { |
| // Coverage-ignore-block(suite): Not run. |
| typeParameters = nominalVariableCopy.newParameterBuilders |
| ..addAll(typeParameters); |
| } else { |
| typeParameters = nominalVariableCopy.newParameterBuilders; |
| } |
| } |
| fragment.typeParameterNameSpace.addTypeParameters( |
| problemReporting, typeParameters, |
| ownerName: fragment.name, allowNameConflict: true); |
| return new ExtensionTypeConstructorDeclaration(fragment, |
| typeParameters: typeParameters); |
| case ClassBuilder(): |
| List<FormalParameterBuilder>? syntheticFormals; |
| if (declarationBuilder.isEnum) { |
| syntheticFormals = [ |
| new FormalParameterBuilder( |
| FormalParameterKind.requiredPositional, |
| Modifiers.empty, |
| loader.target.intType, |
| "#index", |
| fragment.fullNameOffset, |
| fileUri: fragment.fileUri, |
| hasImmediatelyDeclaredInitializer: false), |
| new FormalParameterBuilder( |
| FormalParameterKind.requiredPositional, |
| Modifiers.empty, |
| loader.target.stringType, |
| "#name", |
| fragment.fullNameOffset, |
| fileUri: fragment.fileUri, |
| hasImmediatelyDeclaredInitializer: false), |
| ]; |
| } |
| List<SourceNominalParameterBuilder>? typeParameters = |
| fragment.typeParameters?.builders; |
| fragment.typeParameterNameSpace.addTypeParameters( |
| problemReporting, typeParameters, |
| ownerName: fragment.name, allowNameConflict: true); |
| return new RegularConstructorDeclaration(fragment, |
| typeParameters: typeParameters, |
| syntheticFormals: syntheticFormals, |
| isEnumConstructor: declarationBuilder.isEnum); |
| case ExtensionBuilder(): |
| List<SourceNominalParameterBuilder>? typeParameters = fragment |
| .typeParameters |
| // Coverage-ignore(suite): Not run. |
| ?.builders; |
| NominalParameterCopy? nominalVariableCopy = |
| NominalParameterCopy.copyTypeParameters( |
| unboundNominalParameters: unboundNominalParameters, |
| oldParameterBuilders: declarationBuilder.typeParameters, |
| oldParameterFragments: |
| fragment.enclosingDeclaration.typeParameters, |
| kind: TypeParameterKind.extensionSynthesized, |
| instanceTypeParameterAccess: |
| InstanceTypeParameterAccessState.Allowed); |
| if (nominalVariableCopy != null) { |
| if (typeParameters != null) { |
| // Coverage-ignore-block(suite): Not run. |
| typeParameters = nominalVariableCopy.newParameterBuilders |
| ..addAll(typeParameters); |
| } else { |
| typeParameters = nominalVariableCopy.newParameterBuilders; |
| } |
| } |
| fragment.typeParameterNameSpace.addTypeParameters( |
| problemReporting, typeParameters, |
| ownerName: fragment.name, allowNameConflict: true); |
| return new ExtensionConstructorDeclaration(fragment, |
| typeParameters: typeParameters); |
| } |
| } |
| |
| ConstructorDeclaration constructorDeclaration = |
| createConstructorDeclaration(fragment); |
| |
| List<ConstructorDeclaration> augmentationDeclarations = []; |
| if (augmentations != null) { |
| for (Fragment augmentation in augmentations) { |
| // Promote [augmentation] to [ConstructorFragment]. |
| augmentation as ConstructorFragment; |
| |
| createNominalParameterBuilders( |
| augmentation.typeParameters, unboundNominalParameters); |
| |
| augmentationDeclarations.add(createConstructorDeclaration(augmentation)); |
| |
| if (!augmentation.modifiers.isExternal) { |
| isExternal = false; |
| } |
| } |
| augmentations.clear(); |
| } |
| |
| return _createConstructorBuilderFromDeclarations( |
| constructorDeclaration, augmentationDeclarations, |
| problemReporting: problemReporting, |
| loader: loader, |
| name: name, |
| uriOffset: fragment.uriOffset, |
| nameScheme: nameScheme, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName, |
| constructorReferences: constructorReferences, |
| nativeMethodName: fragment.nativeMethodName, |
| isConst: isConst, |
| isExternal: isExternal, |
| inPatch: fragment.enclosingDeclaration.isPatch); |
| } |
| |
| _AddBuilder _createConstructorBuilderFromDeclarations( |
| ConstructorDeclaration constructorDeclaration, |
| List<ConstructorDeclaration> augmentationDeclarations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required String name, |
| required UriOffsetLength uriOffset, |
| required NameScheme nameScheme, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| required IndexedContainer? indexedContainer, |
| required ContainerName? containerName, |
| required ConstructorReferences constructorReferences, |
| required String? nativeMethodName, |
| required bool isConst, |
| required bool isExternal, |
| required bool inPatch}) { |
| SourceConstructorBuilder constructorBuilder = new SourceConstructorBuilder( |
| name: name, |
| libraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder!, |
| fileUri: uriOffset.fileUri, |
| fileOffset: uriOffset.fileOffset, |
| constructorReferences: constructorReferences, |
| nameScheme: nameScheme, |
| nativeMethodName: nativeMethodName, |
| introductory: constructorDeclaration, |
| augmentations: augmentationDeclarations, |
| isConst: isConst, |
| isExternal: isExternal); |
| constructorReferences.registerReference(loader, constructorBuilder); |
| |
| constructorDeclaration.createEncoding(constructorBuilder); |
| for (ConstructorDeclaration augmentation in augmentationDeclarations) { |
| augmentation.createEncoding(constructorBuilder); |
| } |
| return new _AddBuilder(name, constructorBuilder, uriOffset, inPatch: inPatch); |
| } |
| |
| _AddBuilder _createPrimaryConstructorBuilder( |
| PrimaryConstructorFragment fragment, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| required IndexedContainer? indexedContainer, |
| required ContainerName? containerName}) { |
| String name = fragment.name; |
| |
| NameScheme nameScheme = new NameScheme( |
| isInstanceMember: false, |
| containerName: containerName, |
| containerType: containerType, |
| libraryName: indexedLibrary != null |
| ? new LibraryName(indexedLibrary.library.reference) |
| : enclosingLibraryBuilder.libraryName); |
| |
| ConstructorReferences constructorReferences = new ConstructorReferences( |
| name: name, |
| nameScheme: nameScheme, |
| indexedContainer: indexedContainer, |
| loader: loader, |
| declarationBuilder: declarationBuilder!); |
| |
| ConstructorDeclaration constructorDeclaration; |
| switch (declarationBuilder) { |
| case ExtensionTypeDeclarationBuilder(): |
| NominalParameterCopy? nominalVariableCopy = |
| NominalParameterCopy.copyTypeParameters( |
| unboundNominalParameters: unboundNominalParameters, |
| oldParameterBuilders: declarationBuilder.typeParameters, |
| oldParameterFragments: |
| fragment.enclosingDeclaration.typeParameters, |
| kind: TypeParameterKind.extensionSynthesized, |
| instanceTypeParameterAccess: |
| InstanceTypeParameterAccessState.Allowed); |
| |
| List<SourceNominalParameterBuilder>? typeParameters = |
| nominalVariableCopy?.newParameterBuilders; |
| fragment.typeParameterNameSpace.addTypeParameters( |
| problemReporting, typeParameters, |
| ownerName: fragment.name, allowNameConflict: true); |
| constructorDeclaration = new ExtensionTypePrimaryConstructorDeclaration( |
| fragment, |
| typeParameters: typeParameters); |
| // Coverage-ignore(suite): Not run. |
| case ClassBuilder(): |
| constructorDeclaration = new PrimaryConstructorDeclaration(fragment); |
| // Coverage-ignore(suite): Not run. |
| case ExtensionBuilder(): |
| throw new UnsupportedError( |
| 'Unexpected extension primary constructor $fragment'); |
| } |
| return _createConstructorBuilderFromDeclarations( |
| constructorDeclaration, const [], |
| problemReporting: problemReporting, |
| loader: loader, |
| name: name, |
| uriOffset: fragment.uriOffset, |
| nameScheme: nameScheme, |
| enclosingLibraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder, |
| unboundNominalParameters: unboundNominalParameters, |
| indexedLibrary: indexedLibrary, |
| containerType: containerType, |
| indexedContainer: indexedContainer, |
| containerName: containerName, |
| constructorReferences: constructorReferences, |
| nativeMethodName: null, |
| isConst: fragment.modifiers.isConst, |
| isExternal: fragment.modifiers.isExternal, |
| inPatch: fragment.enclosingDeclaration.isPatch); |
| } |
| |
| _AddBuilder _createFactoryBuilder( |
| FactoryFragment fragment, List<Fragment>? augmentations, |
| {required ProblemReporting problemReporting, |
| required SourceLoader loader, |
| required SourceLibraryBuilder enclosingLibraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<NominalParameterBuilder> unboundNominalParameters, |
| required IndexedLibrary? indexedLibrary, |
| required ContainerType containerType, |
| required IndexedContainer? indexedContainer, |
| required ContainerName? containerName}) { |
| String name = fragment.name; |
| Modifiers modifiers = fragment.modifiers; |
| |
| FactoryDeclaration createFactoryDeclaration(FactoryFragment fragment) { |
| NominalParameterCopy? nominalParameterCopy = |
| NominalParameterCopy.copyTypeParameters( |
| unboundNominalParameters: unboundNominalParameters, |
| oldParameterBuilders: declarationBuilder!.typeParameters, |
| oldParameterFragments: fragment.enclosingDeclaration.typeParameters, |
| kind: TypeParameterKind.function, |
| instanceTypeParameterAccess: |
| InstanceTypeParameterAccessState.Allowed); |
| List<SourceNominalParameterBuilder>? typeParameters = |
| nominalParameterCopy?.newParameterBuilders; |
| TypeBuilder returnType; |
| switch (declarationBuilder) { |
| case ExtensionBuilder(): |
| // Make the synthesized return type invalid for extensions. |
| returnType = new NamedTypeBuilderImpl.forInvalidType( |
| fragment.constructorName.fullName, |
| const NullabilityBuilder.omitted(), |
| messageExtensionDeclaresConstructor.withLocation( |
| fragment.fileUri, |
| fragment.constructorName.fullNameOffset, |
| fragment.constructorName.fullNameLength)); |
| case ClassBuilder(): |
| case ExtensionTypeDeclarationBuilder(): |
| returnType = new NamedTypeBuilderImpl.fromTypeDeclarationBuilder( |
| declarationBuilder, const NullabilityBuilder.omitted(), |
| arguments: nominalParameterCopy?.newTypeArguments, |
| fileUri: fragment.fileUri, |
| charOffset: fragment.constructorName.fullNameOffset, |
| instanceTypeParameterAccess: |
| InstanceTypeParameterAccessState.Allowed); |
| } |
| |
| fragment.typeParameterNameSpace.addTypeParameters( |
| problemReporting, typeParameters, |
| ownerName: fragment.name, allowNameConflict: true); |
| return new FactoryDeclarationImpl(fragment, |
| returnType: returnType, typeParameters: typeParameters); |
| } |
| |
| FactoryDeclaration introductoryDeclaration = |
| createFactoryDeclaration(fragment); |
| |
| bool isRedirectingFactory = fragment.redirectionTarget != null; |
| List<FactoryDeclaration> augmentationDeclarations = []; |
| if (augmentations != null) { |
| for (Fragment augmentation in augmentations) { |
| // Promote [augmentation] to [FactoryFragment]. |
| augmentation as FactoryFragment; |
| |
| augmentationDeclarations.add(createFactoryDeclaration(augmentation)); |
| |
| isRedirectingFactory |= augmentation.redirectionTarget != null; |
| |
| if (!augmentation.modifiers.isExternal) { |
| modifiers -= Modifiers.External; |
| } |
| } |
| } |
| |
| NameScheme nameScheme = new NameScheme( |
| containerName: containerName, |
| containerType: containerType, |
| isInstanceMember: false, |
| libraryName: indexedLibrary != null |
| ? new LibraryName(indexedLibrary.library.reference) |
| : enclosingLibraryBuilder.libraryName); |
| |
| Reference? procedureReference; |
| Reference? tearOffReference; |
| if (indexedContainer != null) { |
| procedureReference = indexedContainer.lookupConstructorReference( |
| nameScheme.getConstructorMemberName(name, isTearOff: false).name); |
| tearOffReference = indexedContainer.lookupGetterReference( |
| nameScheme.getConstructorMemberName(name, isTearOff: true).name); |
| } |
| // Coverage-ignore(suite): Not run. |
| else if (indexedLibrary != null) { |
| procedureReference = indexedLibrary.lookupGetterReference( |
| nameScheme.getConstructorMemberName(name, isTearOff: false).name); |
| tearOffReference = indexedLibrary.lookupGetterReference( |
| nameScheme.getConstructorMemberName(name, isTearOff: true).name); |
| } |
| |
| SourceFactoryBuilder factoryBuilder = new SourceFactoryBuilder( |
| modifiers: modifiers, |
| name: name, |
| libraryBuilder: enclosingLibraryBuilder, |
| declarationBuilder: declarationBuilder!, |
| fileUri: fragment.fileUri, |
| fileOffset: fragment.fullNameOffset, |
| procedureReference: procedureReference, |
| tearOffReference: tearOffReference, |
| nameScheme: nameScheme, |
| introductory: introductoryDeclaration, |
| augmentations: augmentationDeclarations); |
| if (isRedirectingFactory) { |
| (enclosingLibraryBuilder.redirectingFactoryBuilders ??= []) |
| .add(factoryBuilder); |
| } |
| fragment.builder = factoryBuilder; |
| if (augmentations != null) { |
| for (Fragment augmentation in augmentations) { |
| // Promote [augmentation] to [FactoryFragment]. |
| augmentation as FactoryFragment; |
| |
| augmentation.builder = factoryBuilder; |
| } |
| augmentations.clear(); |
| } |
| // TODO(johnniwinther): There is no way to pass the tear off reference |
| // here. |
| if (procedureReference != null) { |
| loader.buildersCreatedWithReferences[procedureReference] = factoryBuilder; |
| } |
| return new _AddBuilder(fragment.name, factoryBuilder, fragment.uriOffset, |
| inPatch: fragment.enclosingDeclaration.isPatch); |
| } |
| |
| class _PropertyDeclarations { |
| final FieldDeclaration? field; |
| final GetterDeclaration? getter; |
| final SetterDeclaration? setter; |
| |
| _PropertyDeclarations({this.field, this.getter, this.setter}); |
| } |