[cfe] Move body builder helpers to their own part
This helps navigate the already fairly long body_builder.dart file.
Change-Id: I091a8c63ed95893a37e21c863fd1a8b45137cc1d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448200
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 654aa48..764c1f6 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -133,14 +133,7 @@
import 'type_algorithms.dart' show calculateBounds;
import 'utils.dart';
-// TODO(ahe): Remove this and ensure all nodes have a location.
-const int noLocation = TreeNode.noOffset;
-
-enum JumpTargetKind {
- Break,
- Continue,
- Goto, // Continue label in switch.
-}
+part 'body_builder_helpers.dart';
class BodyBuilder extends StackListenerImpl
implements ExpressionGeneratorHelper {
@@ -12315,558 +12308,3 @@
push(dotShorthand);
}
}
-
-class Operator {
- final Token token;
-
- String get name => token.stringValue!;
-
- final int charOffset;
-
- Operator(this.token, this.charOffset);
-
- @override
- String toString() => "operator($name)";
-}
-
-class JumpTarget {
- final List<Statement> users = <Statement>[];
-
- final JumpTargetKind kind;
-
- final int functionNestingLevel;
-
- final Uri fileUri;
-
- final int charOffset;
-
- JumpTarget(
- this.kind,
- this.functionNestingLevel,
- this.fileUri,
- this.charOffset,
- );
-
- bool get isBreakTarget => kind == JumpTargetKind.Break;
-
- bool get isContinueTarget => kind == JumpTargetKind.Continue;
-
- bool get isGotoTarget => kind == JumpTargetKind.Goto;
-
- bool get hasUsers => users.isNotEmpty;
-
- void addBreak(Statement statement) {
- assert(isBreakTarget);
- users.add(statement);
- }
-
- void addContinue(Statement statement) {
- assert(isContinueTarget);
- users.add(statement);
- }
-
- void addGoto(Statement statement) {
- assert(isGotoTarget);
- users.add(statement);
- }
-
- void resolveBreaks(
- Forest forest,
- LabeledStatement target,
- Statement targetStatement,
- ) {
- assert(isBreakTarget);
- for (Statement user in users) {
- BreakStatementImpl breakStatement = user as BreakStatementImpl;
- breakStatement.target = target;
- breakStatement.targetStatement = targetStatement;
- }
- users.clear();
- }
-
- List<BreakStatementImpl>? resolveContinues(
- Forest forest,
- LabeledStatement target,
- ) {
- assert(isContinueTarget);
- List<BreakStatementImpl> statements = <BreakStatementImpl>[];
- for (Statement user in users) {
- BreakStatementImpl breakStatement = user as BreakStatementImpl;
- breakStatement.target = target;
- statements.add(breakStatement);
- }
- users.clear();
- return statements;
- }
-
- void resolveGotos(Forest forest, SwitchCase target) {
- assert(isGotoTarget);
- for (Statement user in users) {
- ContinueSwitchStatement continueSwitchStatement =
- user as ContinueSwitchStatement;
- continueSwitchStatement.target = target;
- }
- users.clear();
- }
-}
-
-class LabelTarget implements JumpTarget {
- final JumpTarget breakTarget;
-
- final JumpTarget continueTarget;
-
- @override
- final int functionNestingLevel;
-
- @override
- final Uri fileUri;
-
- @override
- final int charOffset;
-
- LabelTarget(this.functionNestingLevel, this.fileUri, this.charOffset)
- : breakTarget = new JumpTarget(
- JumpTargetKind.Break,
- functionNestingLevel,
- fileUri,
- charOffset,
- ),
- continueTarget = new JumpTarget(
- JumpTargetKind.Continue,
- functionNestingLevel,
- fileUri,
- charOffset,
- );
-
- @override
- // Coverage-ignore(suite): Not run.
- bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;
-
- @override
- // Coverage-ignore(suite): Not run.
- List<Statement> get users => unsupported("users", charOffset, fileUri);
-
- @override
- // Coverage-ignore(suite): Not run.
- JumpTargetKind get kind => unsupported("kind", charOffset, fileUri);
-
- @override
- bool get isBreakTarget => true;
-
- @override
- bool get isContinueTarget => true;
-
- @override
- bool get isGotoTarget => false;
-
- @override
- void addBreak(Statement statement) {
- breakTarget.addBreak(statement);
- }
-
- @override
- void addContinue(Statement statement) {
- continueTarget.addContinue(statement);
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- void addGoto(Statement statement) {
- unsupported("addGoto", charOffset, fileUri);
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- void resolveBreaks(
- Forest forest,
- LabeledStatement target,
- Statement targetStatement,
- ) {
- breakTarget.resolveBreaks(forest, target, targetStatement);
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- List<BreakStatementImpl>? resolveContinues(
- Forest forest,
- LabeledStatement target,
- ) {
- return continueTarget.resolveContinues(forest, target);
- }
-
- @override
- // Coverage-ignore(suite): Not run.
- void resolveGotos(Forest forest, SwitchCase target) {
- unsupported("resolveGotos", charOffset, fileUri);
- }
-}
-
-class FunctionTypeParameters {
- final List<ParameterBuilder>? parameters;
- final int charOffset;
- final int length;
- final Uri uri;
-
- FunctionTypeParameters(
- this.parameters,
- this.charOffset,
- this.length,
- this.uri,
- ) {
- if (parameters?.isEmpty ?? false) {
- throw "Empty parameters should be null";
- }
- }
-
- TypeBuilder toFunctionType(
- TypeBuilder returnType,
- NullabilityBuilder nullabilityBuilder, {
- List<StructuralParameterBuilder>? structuralVariableBuilders,
- required bool hasFunctionFormalParameterSyntax,
- }) {
- return new FunctionTypeBuilderImpl(
- returnType,
- structuralVariableBuilders,
- parameters,
- nullabilityBuilder,
- uri,
- charOffset,
- hasFunctionFormalParameterSyntax: hasFunctionFormalParameterSyntax,
- );
- }
-
- @override
- String toString() {
- return "FormalParameters($parameters, $charOffset, $uri)";
- }
-}
-
-class FormalParameters {
- final List<FormalParameterBuilder>? parameters;
- final int charOffset;
- final int length;
- final Uri uri;
-
- FormalParameters(this.parameters, this.charOffset, this.length, this.uri) {
- if (parameters?.isEmpty ?? false) {
- throw "Empty parameters should be null";
- }
- }
-
- FunctionNode buildFunctionNode(
- SourceLibraryBuilder library,
- TypeBuilder? returnTypeBuilder,
- List<NominalParameterBuilder>? typeParameterBuilders,
- AsyncMarker asyncModifier,
- Statement body,
- int fileEndOffset,
- ) {
- DartType returnType =
- returnTypeBuilder?.build(library, TypeUse.returnType) ??
- const DynamicType();
- int requiredParameterCount = 0;
- List<VariableDeclaration> positionalParameters = <VariableDeclaration>[];
- List<VariableDeclaration> namedParameters = <VariableDeclaration>[];
- if (parameters != null) {
- for (FormalParameterBuilder formal in parameters!) {
- VariableDeclaration parameter = formal.build(library);
- if (formal.isPositional) {
- positionalParameters.add(parameter);
- if (formal.isRequiredPositional) requiredParameterCount++;
- } else if (formal.isNamed) {
- namedParameters.add(parameter);
- }
- }
- namedParameters.sort((VariableDeclaration a, VariableDeclaration b) {
- return a.name!.compareTo(b.name!);
- });
- }
-
- List<TypeParameter>? typeParameters;
- if (typeParameterBuilders != null) {
- typeParameters = <TypeParameter>[];
- for (NominalParameterBuilder t in typeParameterBuilders) {
- typeParameters.add(t.parameter);
- // Build the bound to detect cycles in typedefs.
- t.bound?.build(library, TypeUse.typeParameterBound);
- }
- }
- return new FunctionNode(
- body,
- typeParameters: typeParameters,
- positionalParameters: positionalParameters,
- namedParameters: namedParameters,
- requiredParameterCount: requiredParameterCount,
- returnType: returnType,
- asyncMarker: asyncModifier,
- )
- ..fileOffset = charOffset
- ..fileEndOffset = fileEndOffset;
- }
-
- LocalScope computeFormalParameterScope(
- LocalScope parent,
- ExpressionGeneratorHelper helper, {
- bool wildcardVariablesEnabled = false,
- }) {
- if (parameters == null) return parent;
- assert(parameters!.isNotEmpty);
- Map<String, VariableBuilder> local = {};
-
- for (FormalParameterBuilder parameter in parameters!) {
- // Avoid having wildcard parameters in scope.
- if (wildcardVariablesEnabled && parameter.isWildcard) continue;
- Builder? existing = local[parameter.name];
- if (existing != null) {
- helper.reportDuplicatedDeclaration(
- existing,
- parameter.name,
- parameter.fileOffset,
- );
- } else {
- local[parameter.name] = parameter;
- }
- }
- return parent.createNestedFixedScope(
- debugName: "formals",
- kind: ScopeKind.formals,
- local: local,
- );
- }
-
- @override
- String toString() {
- return "FormalParameters($parameters, $charOffset, $uri)";
- }
-}
-
-/// Returns a block like this:
-///
-/// {
-/// statement;
-/// body;
-/// }
-///
-/// If [body] is a [Block], it's returned with [statement] prepended to it.
-Block combineStatements(Statement statement, Statement body) {
- if (body is Block) {
- if (statement is Block) {
- body.statements.insertAll(0, statement.statements);
- setParents(statement.statements, body);
- } else {
- body.statements.insert(0, statement);
- statement.parent = body;
- }
- return body;
- } else {
- return new Block(<Statement>[
- if (statement is Block) ...statement.statements else statement,
- body,
- ])..fileOffset = statement.fileOffset;
- }
-}
-
-/// DartDocTest(
-/// debugName("myClassName", "myName"),
-/// "myClassName.myName"
-/// )
-/// DartDocTest(
-/// debugName("myClassName", ""),
-/// "myClassName"
-/// )
-/// DartDocTest(
-/// debugName("", ""),
-/// ""
-/// )
-String debugName(String className, String name) {
- return name.isEmpty ? className : "$className.$name";
-}
-
-/// A data holder used to hold the information about a label that is pushed on
-/// the stack.
-class Label {
- String name;
- int charOffset;
-
- Label(this.name, this.charOffset);
-
- @override
- String toString() => "label($name)";
-}
-
-class ForInElements {
- VariableDeclaration? explicitVariableDeclaration;
- VariableDeclaration? syntheticVariableDeclaration;
- Expression? syntheticAssignment;
- Expression? expressionProblem;
- Statement? expressionEffects;
-
- VariableDeclaration get variable =>
- (explicitVariableDeclaration ?? syntheticVariableDeclaration)!;
-}
-
-class _BodyBuilderCloner extends CloneVisitorNotMembers {
- final BodyBuilder bodyBuilder;
-
- _BodyBuilderCloner(this.bodyBuilder);
-
- @override
- // Coverage-ignore(suite): Not run.
- TreeNode visitStaticInvocation(StaticInvocation node) {
- if (node is FactoryConstructorInvocation) {
- FactoryConstructorInvocation result = new FactoryConstructorInvocation(
- node.target,
- clone(node.arguments),
- isConst: node.isConst,
- )..hasBeenInferred = node.hasBeenInferred;
- return result;
- } else if (node is TypeAliasedFactoryInvocation) {
- TypeAliasedFactoryInvocation result = new TypeAliasedFactoryInvocation(
- node.typeAliasBuilder,
- node.target,
- clone(node.arguments),
- isConst: node.isConst,
- )..hasBeenInferred = node.hasBeenInferred;
- return result;
- }
- return super.visitStaticInvocation(node);
- }
-
- @override
- TreeNode visitConstructorInvocation(ConstructorInvocation node) {
- if (node is TypeAliasedConstructorInvocation) {
- // Coverage-ignore-block(suite): Not run.
- TypeAliasedConstructorInvocation result =
- new TypeAliasedConstructorInvocation(
- node.typeAliasBuilder,
- node.target,
- clone(node.arguments),
- isConst: node.isConst,
- )..hasBeenInferred = node.hasBeenInferred;
- return result;
- }
- return super.visitConstructorInvocation(node);
- }
-
- @override
- TreeNode visitArguments(Arguments node) {
- if (node is ArgumentsImpl) {
- return ArgumentsImpl.clone(
- node,
- node.positional.map(clone).toList(),
- node.named.map(clone).toList(),
- node.types.map(visitType).toList(),
- );
- }
- return super.visitArguments(node);
- }
-}
-
-// Coverage-ignore(suite): Not run.
-/// Returns `true` if [node] is not part of its parent member.
-///
-/// This computation is costly and should only be used in assertions to verify
-/// that [node] has been removed from the AST.
-bool isOrphaned(TreeNode node) {
- TreeNode? parent = node;
- Member? member;
- while (parent != null) {
- if (parent is Member) {
- member = parent;
- break;
- }
- parent = parent.parent;
- }
- if (member == null) {
- return true;
- }
- _FindChildVisitor visitor = new _FindChildVisitor(node);
- member.accept(visitor);
- return !visitor.foundNode;
-}
-
-// Coverage-ignore(suite): Not run.
-class _FindChildVisitor extends VisitorDefault<void> with VisitorVoidMixin {
- final TreeNode soughtNode;
- bool foundNode = false;
-
- _FindChildVisitor(this.soughtNode);
-
- @override
- void defaultNode(Node node) {
- if (!foundNode) {
- if (identical(node, soughtNode)) {
- foundNode = true;
- } else {
- node.visitChildren(this);
- }
- }
- }
-}
-
-class Condition {
- final Expression expression;
- final PatternGuard? patternGuard;
-
- Condition(this.expression, [this.patternGuard]);
-
- @override
- String toString() =>
- 'Condition($expression'
- '${patternGuard != null ? ',$patternGuard' : ''})';
-}
-
-final ExpressionOrPatternGuardCase dummyExpressionOrPatternGuardCase =
- new ExpressionOrPatternGuardCase.expression(
- TreeNode.noOffset,
- dummyExpression,
- );
-
-class ExpressionOrPatternGuardCase {
- final int caseOffset;
- final Expression? expression;
- final PatternGuard? patternGuard;
-
- ExpressionOrPatternGuardCase.expression(
- this.caseOffset,
- Expression this.expression,
- ) : patternGuard = null;
-
- ExpressionOrPatternGuardCase.patternGuard(
- this.caseOffset,
- PatternGuard this.patternGuard,
- ) : expression = null;
-}
-
-class RedirectionTarget {
- final Member target;
- final List<DartType> typeArguments;
-
- RedirectionTarget(this.target, this.typeArguments);
-}
-
-extension on MemberKind {
- bool get isFunctionType {
- switch (this) {
- case MemberKind.FunctionTypeAlias:
- case MemberKind.FunctionTypedParameter:
- case MemberKind.GeneralizedFunctionType:
- return true;
- case MemberKind.Catch:
- case MemberKind.Factory:
- case MemberKind.Local:
- case MemberKind.NonStaticMethod:
- case MemberKind.StaticMethod:
- case MemberKind.TopLevelMethod:
- case MemberKind.ExtensionNonStaticMethod:
- case MemberKind.ExtensionStaticMethod:
- case MemberKind.ExtensionTypeNonStaticMethod:
- case MemberKind.ExtensionTypeStaticMethod:
- case MemberKind.NonStaticField:
- case MemberKind.StaticField:
- case MemberKind.TopLevelField:
- case MemberKind.PrimaryConstructor:
- return false;
- }
- }
-}
diff --git a/pkg/front_end/lib/src/kernel/body_builder_helpers.dart b/pkg/front_end/lib/src/kernel/body_builder_helpers.dart
new file mode 100644
index 0000000..3e7d4fc
--- /dev/null
+++ b/pkg/front_end/lib/src/kernel/body_builder_helpers.dart
@@ -0,0 +1,569 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of 'body_builder.dart';
+
+// TODO(ahe): Remove this and ensure all nodes have a location.
+const int noLocation = TreeNode.noOffset;
+
+enum JumpTargetKind {
+ Break,
+ Continue,
+ Goto, // Continue label in switch.
+}
+
+class Operator {
+ final Token token;
+
+ String get name => token.stringValue!;
+
+ final int charOffset;
+
+ Operator(this.token, this.charOffset);
+
+ @override
+ String toString() => "operator($name)";
+}
+
+class JumpTarget {
+ final List<Statement> users = <Statement>[];
+
+ final JumpTargetKind kind;
+
+ final int functionNestingLevel;
+
+ final Uri fileUri;
+
+ final int charOffset;
+
+ JumpTarget(
+ this.kind,
+ this.functionNestingLevel,
+ this.fileUri,
+ this.charOffset,
+ );
+
+ bool get isBreakTarget => kind == JumpTargetKind.Break;
+
+ bool get isContinueTarget => kind == JumpTargetKind.Continue;
+
+ bool get isGotoTarget => kind == JumpTargetKind.Goto;
+
+ bool get hasUsers => users.isNotEmpty;
+
+ void addBreak(Statement statement) {
+ assert(isBreakTarget);
+ users.add(statement);
+ }
+
+ void addContinue(Statement statement) {
+ assert(isContinueTarget);
+ users.add(statement);
+ }
+
+ void addGoto(Statement statement) {
+ assert(isGotoTarget);
+ users.add(statement);
+ }
+
+ void resolveBreaks(
+ Forest forest,
+ LabeledStatement target,
+ Statement targetStatement,
+ ) {
+ assert(isBreakTarget);
+ for (Statement user in users) {
+ BreakStatementImpl breakStatement = user as BreakStatementImpl;
+ breakStatement.target = target;
+ breakStatement.targetStatement = targetStatement;
+ }
+ users.clear();
+ }
+
+ List<BreakStatementImpl>? resolveContinues(
+ Forest forest,
+ LabeledStatement target,
+ ) {
+ assert(isContinueTarget);
+ List<BreakStatementImpl> statements = <BreakStatementImpl>[];
+ for (Statement user in users) {
+ BreakStatementImpl breakStatement = user as BreakStatementImpl;
+ breakStatement.target = target;
+ statements.add(breakStatement);
+ }
+ users.clear();
+ return statements;
+ }
+
+ void resolveGotos(Forest forest, SwitchCase target) {
+ assert(isGotoTarget);
+ for (Statement user in users) {
+ ContinueSwitchStatement continueSwitchStatement =
+ user as ContinueSwitchStatement;
+ continueSwitchStatement.target = target;
+ }
+ users.clear();
+ }
+}
+
+class LabelTarget implements JumpTarget {
+ final JumpTarget breakTarget;
+
+ final JumpTarget continueTarget;
+
+ @override
+ final int functionNestingLevel;
+
+ @override
+ final Uri fileUri;
+
+ @override
+ final int charOffset;
+
+ LabelTarget(this.functionNestingLevel, this.fileUri, this.charOffset)
+ : breakTarget = new JumpTarget(
+ JumpTargetKind.Break,
+ functionNestingLevel,
+ fileUri,
+ charOffset,
+ ),
+ continueTarget = new JumpTarget(
+ JumpTargetKind.Continue,
+ functionNestingLevel,
+ fileUri,
+ charOffset,
+ );
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ List<Statement> get users => unsupported("users", charOffset, fileUri);
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ JumpTargetKind get kind => unsupported("kind", charOffset, fileUri);
+
+ @override
+ bool get isBreakTarget => true;
+
+ @override
+ bool get isContinueTarget => true;
+
+ @override
+ bool get isGotoTarget => false;
+
+ @override
+ void addBreak(Statement statement) {
+ breakTarget.addBreak(statement);
+ }
+
+ @override
+ void addContinue(Statement statement) {
+ continueTarget.addContinue(statement);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void addGoto(Statement statement) {
+ unsupported("addGoto", charOffset, fileUri);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void resolveBreaks(
+ Forest forest,
+ LabeledStatement target,
+ Statement targetStatement,
+ ) {
+ breakTarget.resolveBreaks(forest, target, targetStatement);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ List<BreakStatementImpl>? resolveContinues(
+ Forest forest,
+ LabeledStatement target,
+ ) {
+ return continueTarget.resolveContinues(forest, target);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void resolveGotos(Forest forest, SwitchCase target) {
+ unsupported("resolveGotos", charOffset, fileUri);
+ }
+}
+
+class FunctionTypeParameters {
+ final List<ParameterBuilder>? parameters;
+ final int charOffset;
+ final int length;
+ final Uri uri;
+
+ FunctionTypeParameters(
+ this.parameters,
+ this.charOffset,
+ this.length,
+ this.uri,
+ ) {
+ if (parameters?.isEmpty ?? false) {
+ throw "Empty parameters should be null";
+ }
+ }
+
+ TypeBuilder toFunctionType(
+ TypeBuilder returnType,
+ NullabilityBuilder nullabilityBuilder, {
+ List<StructuralParameterBuilder>? structuralVariableBuilders,
+ required bool hasFunctionFormalParameterSyntax,
+ }) {
+ return new FunctionTypeBuilderImpl(
+ returnType,
+ structuralVariableBuilders,
+ parameters,
+ nullabilityBuilder,
+ uri,
+ charOffset,
+ hasFunctionFormalParameterSyntax: hasFunctionFormalParameterSyntax,
+ );
+ }
+
+ @override
+ String toString() {
+ return "FormalParameters($parameters, $charOffset, $uri)";
+ }
+}
+
+class FormalParameters {
+ final List<FormalParameterBuilder>? parameters;
+ final int charOffset;
+ final int length;
+ final Uri uri;
+
+ FormalParameters(this.parameters, this.charOffset, this.length, this.uri) {
+ if (parameters?.isEmpty ?? false) {
+ throw "Empty parameters should be null";
+ }
+ }
+
+ FunctionNode buildFunctionNode(
+ SourceLibraryBuilder library,
+ TypeBuilder? returnTypeBuilder,
+ List<NominalParameterBuilder>? typeParameterBuilders,
+ AsyncMarker asyncModifier,
+ Statement body,
+ int fileEndOffset,
+ ) {
+ DartType returnType =
+ returnTypeBuilder?.build(library, TypeUse.returnType) ??
+ const DynamicType();
+ int requiredParameterCount = 0;
+ List<VariableDeclaration> positionalParameters = <VariableDeclaration>[];
+ List<VariableDeclaration> namedParameters = <VariableDeclaration>[];
+ if (parameters != null) {
+ for (FormalParameterBuilder formal in parameters!) {
+ VariableDeclaration parameter = formal.build(library);
+ if (formal.isPositional) {
+ positionalParameters.add(parameter);
+ if (formal.isRequiredPositional) requiredParameterCount++;
+ } else if (formal.isNamed) {
+ namedParameters.add(parameter);
+ }
+ }
+ namedParameters.sort((VariableDeclaration a, VariableDeclaration b) {
+ return a.name!.compareTo(b.name!);
+ });
+ }
+
+ List<TypeParameter>? typeParameters;
+ if (typeParameterBuilders != null) {
+ typeParameters = <TypeParameter>[];
+ for (NominalParameterBuilder t in typeParameterBuilders) {
+ typeParameters.add(t.parameter);
+ // Build the bound to detect cycles in typedefs.
+ t.bound?.build(library, TypeUse.typeParameterBound);
+ }
+ }
+ return new FunctionNode(
+ body,
+ typeParameters: typeParameters,
+ positionalParameters: positionalParameters,
+ namedParameters: namedParameters,
+ requiredParameterCount: requiredParameterCount,
+ returnType: returnType,
+ asyncMarker: asyncModifier,
+ )
+ ..fileOffset = charOffset
+ ..fileEndOffset = fileEndOffset;
+ }
+
+ LocalScope computeFormalParameterScope(
+ LocalScope parent,
+ ExpressionGeneratorHelper helper, {
+ bool wildcardVariablesEnabled = false,
+ }) {
+ if (parameters == null) return parent;
+ assert(parameters!.isNotEmpty);
+ Map<String, VariableBuilder> local = {};
+
+ for (FormalParameterBuilder parameter in parameters!) {
+ // Avoid having wildcard parameters in scope.
+ if (wildcardVariablesEnabled && parameter.isWildcard) continue;
+ Builder? existing = local[parameter.name];
+ if (existing != null) {
+ helper.reportDuplicatedDeclaration(
+ existing,
+ parameter.name,
+ parameter.fileOffset,
+ );
+ } else {
+ local[parameter.name] = parameter;
+ }
+ }
+ return parent.createNestedFixedScope(
+ debugName: "formals",
+ kind: ScopeKind.formals,
+ local: local,
+ );
+ }
+
+ @override
+ String toString() {
+ return "FormalParameters($parameters, $charOffset, $uri)";
+ }
+}
+
+/// Returns a block like this:
+///
+/// {
+/// statement;
+/// body;
+/// }
+///
+/// If [body] is a [Block], it's returned with [statement] prepended to it.
+Block combineStatements(Statement statement, Statement body) {
+ if (body is Block) {
+ if (statement is Block) {
+ body.statements.insertAll(0, statement.statements);
+ setParents(statement.statements, body);
+ } else {
+ body.statements.insert(0, statement);
+ statement.parent = body;
+ }
+ return body;
+ } else {
+ return new Block(<Statement>[
+ if (statement is Block) ...statement.statements else statement,
+ body,
+ ])..fileOffset = statement.fileOffset;
+ }
+}
+
+/// DartDocTest(
+/// debugName("myClassName", "myName"),
+/// "myClassName.myName"
+/// )
+/// DartDocTest(
+/// debugName("myClassName", ""),
+/// "myClassName"
+/// )
+/// DartDocTest(
+/// debugName("", ""),
+/// ""
+/// )
+String debugName(String className, String name) {
+ return name.isEmpty ? className : "$className.$name";
+}
+
+/// A data holder used to hold the information about a label that is pushed on
+/// the stack.
+class Label {
+ String name;
+ int charOffset;
+
+ Label(this.name, this.charOffset);
+
+ @override
+ String toString() => "label($name)";
+}
+
+class ForInElements {
+ VariableDeclaration? explicitVariableDeclaration;
+ VariableDeclaration? syntheticVariableDeclaration;
+ Expression? syntheticAssignment;
+ Expression? expressionProblem;
+ Statement? expressionEffects;
+
+ VariableDeclaration get variable =>
+ (explicitVariableDeclaration ?? syntheticVariableDeclaration)!;
+}
+
+class _BodyBuilderCloner extends CloneVisitorNotMembers {
+ final BodyBuilder bodyBuilder;
+
+ _BodyBuilderCloner(this.bodyBuilder);
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ TreeNode visitStaticInvocation(StaticInvocation node) {
+ if (node is FactoryConstructorInvocation) {
+ FactoryConstructorInvocation result = new FactoryConstructorInvocation(
+ node.target,
+ clone(node.arguments),
+ isConst: node.isConst,
+ )..hasBeenInferred = node.hasBeenInferred;
+ return result;
+ } else if (node is TypeAliasedFactoryInvocation) {
+ TypeAliasedFactoryInvocation result = new TypeAliasedFactoryInvocation(
+ node.typeAliasBuilder,
+ node.target,
+ clone(node.arguments),
+ isConst: node.isConst,
+ )..hasBeenInferred = node.hasBeenInferred;
+ return result;
+ }
+ return super.visitStaticInvocation(node);
+ }
+
+ @override
+ TreeNode visitConstructorInvocation(ConstructorInvocation node) {
+ if (node is TypeAliasedConstructorInvocation) {
+ // Coverage-ignore-block(suite): Not run.
+ TypeAliasedConstructorInvocation result =
+ new TypeAliasedConstructorInvocation(
+ node.typeAliasBuilder,
+ node.target,
+ clone(node.arguments),
+ isConst: node.isConst,
+ )..hasBeenInferred = node.hasBeenInferred;
+ return result;
+ }
+ return super.visitConstructorInvocation(node);
+ }
+
+ @override
+ TreeNode visitArguments(Arguments node) {
+ if (node is ArgumentsImpl) {
+ return ArgumentsImpl.clone(
+ node,
+ node.positional.map(clone).toList(),
+ node.named.map(clone).toList(),
+ node.types.map(visitType).toList(),
+ );
+ }
+ return super.visitArguments(node);
+ }
+}
+
+// Coverage-ignore(suite): Not run.
+/// Returns `true` if [node] is not part of its parent member.
+///
+/// This computation is costly and should only be used in assertions to verify
+/// that [node] has been removed from the AST.
+bool isOrphaned(TreeNode node) {
+ TreeNode? parent = node;
+ Member? member;
+ while (parent != null) {
+ if (parent is Member) {
+ member = parent;
+ break;
+ }
+ parent = parent.parent;
+ }
+ if (member == null) {
+ return true;
+ }
+ _FindChildVisitor visitor = new _FindChildVisitor(node);
+ member.accept(visitor);
+ return !visitor.foundNode;
+}
+
+// Coverage-ignore(suite): Not run.
+class _FindChildVisitor extends VisitorDefault<void> with VisitorVoidMixin {
+ final TreeNode soughtNode;
+ bool foundNode = false;
+
+ _FindChildVisitor(this.soughtNode);
+
+ @override
+ void defaultNode(Node node) {
+ if (!foundNode) {
+ if (identical(node, soughtNode)) {
+ foundNode = true;
+ } else {
+ node.visitChildren(this);
+ }
+ }
+ }
+}
+
+class Condition {
+ final Expression expression;
+ final PatternGuard? patternGuard;
+
+ Condition(this.expression, [this.patternGuard]);
+
+ @override
+ String toString() =>
+ 'Condition($expression'
+ '${patternGuard != null ? ',$patternGuard' : ''})';
+}
+
+final ExpressionOrPatternGuardCase dummyExpressionOrPatternGuardCase =
+ new ExpressionOrPatternGuardCase.expression(
+ TreeNode.noOffset,
+ dummyExpression,
+ );
+
+class ExpressionOrPatternGuardCase {
+ final int caseOffset;
+ final Expression? expression;
+ final PatternGuard? patternGuard;
+
+ ExpressionOrPatternGuardCase.expression(
+ this.caseOffset,
+ Expression this.expression,
+ ) : patternGuard = null;
+
+ ExpressionOrPatternGuardCase.patternGuard(
+ this.caseOffset,
+ PatternGuard this.patternGuard,
+ ) : expression = null;
+}
+
+class RedirectionTarget {
+ final Member target;
+ final List<DartType> typeArguments;
+
+ RedirectionTarget(this.target, this.typeArguments);
+}
+
+extension on MemberKind {
+ bool get isFunctionType {
+ switch (this) {
+ case MemberKind.FunctionTypeAlias:
+ case MemberKind.FunctionTypedParameter:
+ case MemberKind.GeneralizedFunctionType:
+ return true;
+ case MemberKind.Catch:
+ case MemberKind.Factory:
+ case MemberKind.Local:
+ case MemberKind.NonStaticMethod:
+ case MemberKind.StaticMethod:
+ case MemberKind.TopLevelMethod:
+ case MemberKind.ExtensionNonStaticMethod:
+ case MemberKind.ExtensionStaticMethod:
+ case MemberKind.ExtensionTypeNonStaticMethod:
+ case MemberKind.ExtensionTypeStaticMethod:
+ case MemberKind.NonStaticField:
+ case MemberKind.StaticField:
+ case MemberKind.TopLevelField:
+ case MemberKind.PrimaryConstructor:
+ return false;
+ }
+ }
+}
diff --git a/pkg/front_end/test/dartdoctest_suite.status b/pkg/front_end/test/dartdoctest_suite.status
index 1bb32d5..24ef63d 100644
--- a/pkg/front_end/test/dartdoctest_suite.status
+++ b/pkg/front_end/test/dartdoctest_suite.status
@@ -2,3 +2,4 @@
# 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.
+front_end/lib/src/kernel/body_builder_helpers: Crash # Issue 61438
\ No newline at end of file