49597f85d9
(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>
380 lines
11 KiB
Dart
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);
|
|
}
|
|
}
|
|
}
|