Files
sdk/pkg/front_end/test/parser_test_parser_creator.dart
T
Paul Berry 49597f85d9 [front_end,kernel] Add ignores for codegen to prepare for new syntax.
(Part of https://github.com/dart-lang/sdk/issues/63288)

Updates various code generators in the `front_end` and `kernel`
packages to output `ignore_for_file` comments to ignore the
`unnecessary_type_name_in_constructor` lint.

This is a first step towards migrating the `front_end` and `kernel`
packages to use the new constructor declaration syntax, since it will
allow the `unnecessary_type_name_in_constructor` lint to be enabled
without breaking generated code.

Once all the packages have had their SDK constraints bumped to a
language version that supports the new syntax, I'll update the code
generator to use the new syntax, and remove the ignores.

For more information about the new constructor declaration syntax, see
https://github.com/dart-lang/language/blob/main/accepted/future-releases/primary-constructors/feature-specification.md#abbreviations-of-in-body-constructor-declarations.

Change-Id: I73fd960a7eea2a1a59316602c49d56816a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506380
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2026-05-27 10:11:50 -07:00

380 lines
11 KiB
Dart

// Copyright (c) 2019, 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 'dart:io';
import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/parser/experimental_features.dart';
import 'package:_fe_analyzer_shared/src/parser/parser.dart';
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart';
import 'package:dart_style/dart_style.dart' show DartFormatter;
import 'utils/io_utils.dart' show computeRepoDirUri, getPackageVersionFor;
void main(List<String> args) {
final Uri repoDir = computeRepoDirUri();
String generated = generateTestParser(repoDir);
new File.fromUri(
computeTestParserUri(repoDir),
).writeAsStringSync(generated, flush: true);
}
Uri computeTestParserUri(Uri repoDir) {
return repoDir.resolve("pkg/front_end/test/parser_test_parser.dart");
}
String generateTestParser(Uri repoDir) {
StringBuffer out = new StringBuffer();
File f = new File.fromUri(
repoDir.resolve("pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart"),
);
Uint8List rawBytes = f.readAsBytesSync();
Utf8BytesScanner scanner = new Utf8BytesScanner(
rawBytes,
includeComments: true,
);
Token firstToken = scanner.tokenize();
out.write("""
// Copyright (c) 2019, 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.
""");
// This code generator generates Dart 3.12-style constructor declarations, so
// ignore the `unnecessary_type_name_in_constructor` lint.
// TODO(paulberry): switch the code generator to Dart 3.13-style constructor
// declarations, and remove this ignore comment.
out.write("""
// ignore_for_file: unnecessary_type_name_in_constructor
""");
out.write(r"""
import 'package:_fe_analyzer_shared/src/experiments/flags.dart';
import 'package:_fe_analyzer_shared/src/parser/assert.dart';
import 'package:_fe_analyzer_shared/src/parser/block_kind.dart';
import 'package:_fe_analyzer_shared/src/parser/constructor_reference_context.dart';
import 'package:_fe_analyzer_shared/src/parser/declaration_kind.dart';
import 'package:_fe_analyzer_shared/src/parser/directive_context.dart';
import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart';
import 'package:_fe_analyzer_shared/src/parser/identifier_context.dart';
import 'package:_fe_analyzer_shared/src/parser/listener.dart' show Listener;
import 'package:_fe_analyzer_shared/src/parser/member_kind.dart';
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show ConstantPatternContext, ExperimentalFeatures, Parser;
import 'package:_fe_analyzer_shared/src/parser/parser_impl.dart'
show AwaitOrYieldContext, ForPartsContext, PatternContext;
import 'package:_fe_analyzer_shared/src/parser/token_stream_rewriter.dart';
import 'package:_fe_analyzer_shared/src/parser/type_info.dart';
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:front_end/src/codes/cfe_codes.dart' as codes;
import 'package:front_end/src/source/diet_parser.dart'
show useImplicitCreationExpressionInCfe;
// THIS FILE IS AUTO GENERATED BY 'test/parser_test_parser_creator.dart'
// Run this command to update it:
// 'dart pkg/front_end/test/parser_test_parser_creator.dart'
class TestParser extends Parser {
int indent = 0;
StringBuffer sb = new StringBuffer();
final bool trace;
bool _inhibitPrinting = false;
TestParser(Listener listener, this.trace,
{required ExperimentalFeatures experimentalFeatures})
: super(listener,
useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
experimentalFeatures: experimentalFeatures);
String createTrace() {
List<String> traceLines = StackTrace.current.toString().split("\n");
for (int i = 0; i < traceLines.length; i++) {
// Find first one that's not any of the denylisted ones.
String line = traceLines[i];
if (line.contains("parser_test_listener.dart:") ||
line.contains("parser_suite.dart:") ||
line.contains("parser_test_parser.dart:") ||
line == "<asynchronous suspension>") {
continue;
}
return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")"));
}
return "N/A";
}
void doPrint(String s) {
if (_inhibitPrinting) return;
String traceString = "";
if (trace) traceString = " (${createTrace()})";
sb.writeln((" " * indent) + s + traceString);
}
@override
T inhibitPrinting<T>(T Function() callback) {
bool previousInhibitPrinting = _inhibitPrinting;
_inhibitPrinting = true;
try {
return callback();
} finally {
_inhibitPrinting = previousInhibitPrinting;
}
}
""");
ParserCreatorListener listener = new ParserCreatorListener(out);
ClassMemberParser parser = new ClassMemberParser(
listener,
experimentalFeatures: const DefaultExperimentalFeatures(),
);
parser.parseUnit(firstToken);
out.writeln("}");
return new DartFormatter(
languageVersion: getPackageVersionFor("front_end"),
).format("$out");
}
class ParserCreatorListener extends Listener {
final StringSink out;
bool insideParserClass = false;
String? currentMethodName;
List<String> parameters = [];
List<String?> parametersNamed = [];
ParserCreatorListener(this.out);
@override
void beginClassDeclaration(
Token begin,
Token? abstractToken,
Token? sealedToken,
Token? baseToken,
Token? interfaceToken,
Token? finalToken,
Token? augmentToken,
Token? mixinToken,
Token name,
) {
if (name.lexeme == "Parser") insideParserClass = true;
}
@override
void endClassDeclaration(Token beginToken, Token endToken) {
insideParserClass = false;
}
@override
void beginConstructor(
DeclarationKind declarationKind,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? varFinalOrConst,
Token? getOrSet,
Token? newToken,
Token name,
String? enclosingDeclarationName,
) {
currentMethodName = name.lexeme;
}
@override
void beginMethod(
DeclarationKind declarationKind,
Token? augmentToken,
Token? externalToken,
Token? staticToken,
Token? covariantToken,
Token? varFinalOrConst,
Token? getOrSet,
Token name,
String? enclosingDeclarationName,
) {
currentMethodName = name.lexeme;
}
@override
void endConstructor(
DeclarationKind kind,
Token beginToken,
Token? newToken,
Token beginParam,
Token? beginInitializers,
Token endToken,
) {
parameters.clear();
parametersNamed.clear();
currentMethodName = null;
}
@override
void endMethod(
DeclarationKind kind,
Token? getOrSet,
Token beginToken,
Token beginParam,
Token? beginInitializers,
Token endToken,
) {
if (insideParserClass &&
!currentMethodName!.startsWith("_") &&
currentMethodName != 'inhibitPrinting') {
Token token = beginToken;
Token? latestToken;
out.writeln(" @override");
out.write(" ");
while (true) {
if (troubleParameterTokens.containsKey(token)) {
if (latestToken != null && latestToken.charEnd < token.charOffset) {
out.write(" ");
}
out.write("dynamic");
token = troubleParameterTokens[token]!;
}
if (latestToken != null && latestToken.charEnd < token.charOffset) {
out.write(" ");
}
if (token is SimpleToken && token.type == TokenType.FUNCTION) {
// Don't write out the '=>'.
out.write("{");
break;
}
out.write(token.lexeme);
if (token is BeginToken &&
token.type == TokenType.OPEN_CURLY_BRACKET &&
(beginParam.endGroup == endToken ||
token.charOffset > beginParam.endGroup!.charOffset)) {
break;
}
if (token == endToken) {
throw token.runtimeType;
}
latestToken = token;
token = token.next!;
}
out.write("\n ");
out.write("doPrint('$currentMethodName(");
String separator = "";
for (int i = 0; i < parameters.length; i++) {
out.write(separator);
out.write(r"' '$");
out.write(parameters[i]);
separator = ", ";
}
for (int i = 0; i < parametersNamed.length; i++) {
out.write(separator);
out.write("' '");
out.write(parametersNamed[i]);
out.write(r": $");
out.write(parametersNamed[i]);
separator = ", ";
}
out.write(")');\n ");
out.write("indent++;\n ");
out.write("var result = super.$currentMethodName");
if (getOrSet != null && getOrSet.lexeme == "get") {
// no parens
out.write(";\n ");
} else {
out.write("(");
String separator = "";
for (int i = 0; i < parameters.length; i++) {
out.write(separator);
out.write(parameters[i]);
separator = ", ";
}
for (int i = 0; i < parametersNamed.length; i++) {
out.write(separator);
out.write(parametersNamed[i]);
out.write(": ");
out.write(parametersNamed[i]);
separator = ", ";
}
out.write(");\n ");
}
out.write("indent--;\n ");
out.write("return result;\n ");
out.write("}");
out.write("\n\n");
}
parameters.clear();
parametersNamed.clear();
currentMethodName = null;
}
int formalParametersNestLevel = 0;
@override
void beginFormalParameters(Token token, MemberKind kind) {
formalParametersNestLevel++;
}
@override
void endFormalParameters(
int count,
Token beginToken,
Token endToken,
MemberKind kind,
) {
formalParametersNestLevel--;
}
Token? currentFormalParameterToken;
@override
void beginFormalParameter(
Token token,
MemberKind kind,
Token? requiredToken,
Token? covariantToken,
Token? varFinalOrConst,
) {
if (formalParametersNestLevel == 1) {
currentFormalParameterToken = token;
}
}
Map<Token?, Token?> troubleParameterTokens = {};
@override
void handleIdentifier(Token token, IdentifierContext context) {
if (formalParametersNestLevel > 0 && token.lexeme.startsWith("_")) {
troubleParameterTokens[currentFormalParameterToken] = null;
}
}
@override
void endFormalParameter(
Token? varOrFinal,
Token? thisKeyword,
Token? superKeyword,
Token? periodAfterThisOrSuper,
Token nameToken,
Token? initializerStart,
Token? initializerEnd,
FormalParameterKind kind,
MemberKind memberKind,
) {
if (formalParametersNestLevel != 1) {
return;
}
if (troubleParameterTokens.containsKey(currentFormalParameterToken)) {
troubleParameterTokens[currentFormalParameterToken] = nameToken;
}
currentFormalParameterToken = null;
if (kind == FormalParameterKind.optionalNamed ||
kind == FormalParameterKind.requiredNamed) {
parametersNamed.add(nameToken.lexeme);
} else {
parameters.add(nameToken.lexeme);
}
}
}