blob: 830341bd0d9d914944fe402d85763bd1b902b24a [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/type_environment.dart';
import '../base/modifiers.dart';
import '../base/name_space.dart';
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/metadata_builder.dart';
import '../builder/method_builder.dart';
import '../fragment/method/declaration.dart';
import '../kernel/hierarchy/class_member.dart';
import '../kernel/hierarchy/members_builder.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/member_covariance.dart';
import '../kernel/type_algorithms.dart';
import 'name_scheme.dart';
import 'source_class_builder.dart';
import 'source_library_builder.dart';
import 'source_member_builder.dart';
class SourceMethodBuilder extends SourceMemberBuilderImpl
implements MethodBuilder {
@override
final Uri fileUri;
@override
final int fileOffset;
@override
final String name;
@override
final SourceLibraryBuilder libraryBuilder;
@override
final DeclarationBuilder? declarationBuilder;
@override
final bool isStatic;
final NameScheme _nameScheme;
@override
final bool isOperator;
/// The declarations that introduces this method. Subsequent methods of the
/// same name must be augmentations.
final MethodDeclaration _introductory;
final List<MethodDeclaration> _augmentations;
final Modifiers _modifiers;
final Reference _reference;
final Reference? _tearOffReference;
final MemberName _memberName;
late final Procedure _invokeTarget;
late final Procedure? _readTarget;
SourceMethodBuilder(
{required this.fileUri,
required this.fileOffset,
required this.name,
required this.libraryBuilder,
required this.declarationBuilder,
required this.isStatic,
required Modifiers modifiers,
required NameScheme nameScheme,
required MethodDeclaration introductory,
required List<MethodDeclaration> augmentations,
required Reference? reference,
required Reference? tearOffReference})
: _nameScheme = nameScheme,
_introductory = introductory,
_modifiers = modifiers,
isOperator = introductory.isOperator,
_reference = reference ?? new Reference(),
_tearOffReference = tearOffReference,
_memberName = nameScheme.getDeclaredName(name),
_augmentations = augmentations;
@override
Builder get parent => declarationBuilder ?? libraryBuilder;
@override
// Coverage-ignore(suite): Not run.
bool get isAugmentation => _modifiers.isAugment;
@override
bool get isAbstract => _modifiers.isAbstract;
@override
// Coverage-ignore(suite): Not run.
bool get isFinal => false;
@override
// Coverage-ignore(suite): Not run.
bool get isSynthesized => false;
@override
Builder get getable => this;
@override
Builder? get setable => null;
@override
int buildBodyNodes(BuildNodesCallback f) {
// TODO(johnniwinther): Generate the needed augmented methods.
return 0;
}
@override
void buildOutlineNodes(BuildNodesCallback f) {
List<MethodDeclaration> augmentedFragments = [
_introductory,
..._augmentations
];
// TODO(johnniwinther): Support augmenting a concrete method with an
// abstract method.
MethodDeclaration lastFragment = augmentedFragments.removeLast();
lastFragment.buildOutlineNode(libraryBuilder, _nameScheme, f,
reference: _reference,
tearOffReference: _tearOffReference,
classTypeParameters: classBuilder?.cls.typeParameters);
for (MethodDeclaration augmented in augmentedFragments) {
augmented.buildOutlineNode(
libraryBuilder, _nameScheme, noAddBuildNodesCallback,
reference: new Reference(),
tearOffReference: new Reference(),
classTypeParameters: classBuilder?.cls.typeParameters);
}
_invokeTarget = lastFragment.invokeTarget;
_readTarget = lastFragment.readTarget;
}
bool hasBuiltOutlineExpressions = false;
@override
void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (!hasBuiltOutlineExpressions) {
_introductory.buildOutlineExpressions(
classHierarchy: classHierarchy,
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
methodBuilder: this,
annotatable: _invokeTarget,
annotatableFileUri: _invokeTarget.fileUri,
isClassInstanceMember: isClassInstanceMember);
for (MethodDeclaration augmentation in _augmentations) {
augmentation.buildOutlineExpressions(
classHierarchy: classHierarchy,
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
methodBuilder: this,
annotatable: _invokeTarget,
annotatableFileUri: _invokeTarget.fileUri,
isClassInstanceMember: isClassInstanceMember);
}
hasBuiltOutlineExpressions = true;
}
}
@override
void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace,
TypeEnvironment typeEnvironment) {
// TODO(johnniwinther): Updated checks for default values to handle
// default values declared on the introductory method and omitted on the
// augmenting method.
_introductory.checkTypes(library, typeEnvironment);
for (MethodDeclaration augmentation in _augmentations) {
augmentation.checkTypes(library, typeEnvironment);
}
}
@override
void checkVariance(
SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
if (!isClassInstanceMember) return;
_introductory.checkVariance(sourceClassBuilder, typeEnvironment);
for (MethodDeclaration augmentation in _augmentations) {
augmentation.checkVariance(sourceClassBuilder, typeEnvironment);
}
}
@override
Iterable<Reference> get exportedMemberReferences => [
_reference,
];
List<ClassMember>? _localMembers;
@override
List<ClassMember> get localMembers =>
_localMembers ??= [new _MethodClassMember(this)];
@override
List<ClassMember> get localSetters => const [];
@override
Name get memberName => _memberName.name;
@override
Member? get readTarget => _readTarget;
@override
// Coverage-ignore(suite): Not run.
Reference? get readTargetReference => _tearOffReference ?? _reference;
@override
Member get invokeTarget => _invokeTarget;
@override
Reference get invokeTargetReference => _reference;
@override
// Coverage-ignore(suite): Not run.
Member? get writeTarget => null;
@override
// Coverage-ignore(suite): Not run.
Reference? get writeTargetReference => null;
@override
int computeDefaultTypes(ComputeDefaultTypeContext context,
{required bool inErrorRecovery}) {
int count = _introductory.computeDefaultTypes(context);
for (MethodDeclaration augmentation in _augmentations) {
count += augmentation.computeDefaultTypes(context);
}
return count;
}
@override
// Coverage-ignore(suite): Not run.
Iterable<MetadataBuilder>? get metadataForTesting => _introductory.metadata;
@override
bool get isProperty => false;
bool _typeEnsured = false;
ClassMembersBuilder? _classMembersBuilder;
Set<ClassMember>? _overrideDependencies;
void _registerOverrideDependency(
ClassMembersBuilder membersBuilder, Set<ClassMember> overriddenMembers) {
assert(
overriddenMembers.every((overriddenMember) =>
overriddenMember.declarationBuilder != classBuilder),
"Unexpected override dependencies for $this: $overriddenMembers");
_classMembersBuilder ??= membersBuilder;
_overrideDependencies ??= {};
_overrideDependencies!.addAll(overriddenMembers);
}
void _ensureTypes() {
if (_typeEnsured) return;
if (_classMembersBuilder != null) {
assert(_overrideDependencies != null);
_introductory.ensureTypes(_classMembersBuilder!,
declarationBuilder as SourceClassBuilder, _overrideDependencies);
_overrideDependencies = null;
_classMembersBuilder = null;
}
_typeEnsured = true;
}
}
class _MethodClassMember implements ClassMember {
final SourceMethodBuilder _builder;
late final Covariance _covariance =
new Covariance.fromMethod(_builder.invokeTarget as Procedure);
_MethodClassMember(this._builder);
@override
int get charOffset => _builder.fileOffset;
@override
DeclarationBuilder get declarationBuilder => _builder.declarationBuilder!;
@override
// Coverage-ignore(suite): Not run.
List<ClassMember> get declarations =>
throw new UnsupportedError('$runtimeType.declarations');
@override
Uri get fileUri => _builder.fileUri;
@override
bool get forSetter => false;
@override
String get fullName {
String className = declarationBuilder.fullNameForErrors;
return "${className}.${fullNameForErrors}";
}
@override
String get fullNameForErrors => _builder.fullNameForErrors;
@override
Covariance getCovariance(ClassMembersBuilder membersBuilder) => _covariance;
@override
Member getMember(ClassMembersBuilder membersBuilder) {
return _builder.invokeTarget;
}
@override
// Coverage-ignore(suite): Not run.
MemberResult getMemberResult(ClassMembersBuilder membersBuilder) {
if (isStatic) {
return new StaticMemberResult(getMember(membersBuilder), memberKind,
isDeclaredAsField: false,
fullName: '${declarationBuilder.name}.${_builder.memberName.text}');
} else if (_builder.isExtensionTypeMember) {
ExtensionTypeDeclaration extensionTypeDeclaration =
(declarationBuilder as ExtensionTypeDeclarationBuilder)
.extensionTypeDeclaration;
Member member = getTearOff(membersBuilder) ?? getMember(membersBuilder);
return new ExtensionTypeMemberResult(
extensionTypeDeclaration, member, memberKind, name,
isDeclaredAsField: false);
} else {
return new TypeDeclarationInstanceMemberResult(
getMember(membersBuilder), memberKind,
isDeclaredAsField: false);
}
}
@override
Member? getTearOff(ClassMembersBuilder membersBuilder) {
if (_builder.readTarget != _builder.invokeTarget) {
return _builder.readTarget;
}
return null;
}
@override
bool get hasDeclarations => false;
@override
void inferType(ClassMembersBuilder membersBuilder) {
_builder._ensureTypes();
}
@override
ClassMember get interfaceMember => this;
@override
bool get isAbstract => _builder.isAbstract;
@override
bool get isDuplicate => _builder.isDuplicate;
@override
bool get isExtensionTypeMember => _builder.isExtensionTypeMember;
@override
bool get isNoSuchMethodForwarder => false;
@override
bool isObjectMember(ClassBuilder objectClass) {
return declarationBuilder == objectClass;
}
@override
bool get isProperty => false;
@override
// Coverage-ignore(suite): Not run.
bool isSameDeclaration(ClassMember other) {
return other is _MethodClassMember && _builder == other._builder;
}
@override
bool get isSetter => false;
@override
bool get isSourceDeclaration => true;
@override
bool get isStatic => _builder.isStatic;
@override
bool get isSynthesized => false;
@override
ClassMemberKind get memberKind => ClassMemberKind.Method;
@override
Name get name => _builder.memberName;
@override
void registerOverrideDependency(
ClassMembersBuilder membersBuilder, Set<ClassMember> overriddenMembers) {
_builder._registerOverrideDependency(membersBuilder, overriddenMembers);
}
@override
String toString() => '$runtimeType($fullName,forSetter=${forSetter})';
}