| // Copyright (c) 2021, 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 file contains code to generate scanner and parser message |
| /// based on the information in pkg/front_end/messages.yaml. |
| /// |
| /// For each message in messages.yaml that contains an 'index:' field, |
| /// this tool generates an error with the name specified by the 'analyzerCode:' |
| /// field and an entry in the fastaAnalyzerErrorList for that generated error. |
| /// The text in the 'analyzerCode:' field must contain the name of the class |
| /// containing the error and the name of the error separated by a `.` |
| /// (e.g. ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND). |
| /// |
| /// It is expected that 'dart pkg/front_end/tool/generate_messages.dart' |
| /// has already been successfully run. |
| library; |
| |
| import 'dart:convert'; |
| |
| import 'package:analyzer_testing/package_root.dart' as pkg_root; |
| import 'package:analyzer_utilities/analyzer_messages.dart'; |
| import 'package:analyzer_utilities/located_error.dart'; |
| import 'package:analyzer_utilities/messages.dart'; |
| import 'package:analyzer_utilities/tools.dart'; |
| |
| Future<void> main() async { |
| await GeneratedContent.generateAll(pkg_root.packageRoot, allTargets); |
| } |
| |
| /// A list of all targets generated by this code generator. |
| final List<GeneratedContent> allTargets = _analyzerGeneratedFiles(); |
| |
| /// Generates a list of [GeneratedContent] objects describing all the analyzer |
| /// files that need to be generated. |
| List<GeneratedContent> _analyzerGeneratedFiles() { |
| var classesByFile = <GeneratedDiagnosticFile, List<DiagnosticClassInfo>>{}; |
| for (var diagnosticClassInfo in diagnosticClasses) { |
| // Lint codes are generated separately. |
| if (diagnosticClassInfo == linterLintCodeInfo) continue; |
| |
| (classesByFile[diagnosticClassInfo.file] ??= []).add(diagnosticClassInfo); |
| } |
| return [ |
| for (var entry in classesByFile.entries) |
| GeneratedFile(entry.key.path, (pkgRoot) async { |
| var codeGenerator = _AnalyzerDiagnosticClassGenerator( |
| entry.key, |
| entry.value, |
| ); |
| codeGenerator.generate(); |
| return codeGenerator.out.toString(); |
| }), |
| GeneratedFile('analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart', ( |
| pkgRoot, |
| ) async { |
| var codeGenerator = _DiagnosticCodeValuesGenerator(); |
| codeGenerator.generate(); |
| return codeGenerator.out.toString(); |
| }), |
| for (var package in AnalyzerDiagnosticPackage.values) |
| GeneratedFile( |
| '${package.dirName}/lib/${package.diagnosticPathPart}.g.dart', |
| (pkgRoot) async { |
| var codeGenerator = _AnalyzerDiagnosticGenerator( |
| package: package, |
| parentLibrary: |
| 'package:${package.dirName}/${package.diagnosticPathPart}.dart', |
| ); |
| codeGenerator.generate(); |
| return codeGenerator.out.toString(); |
| }, |
| ), |
| ]; |
| } |
| |
| /// Code generator for analyzer diagnostic classes. |
| class _AnalyzerDiagnosticClassGenerator { |
| final GeneratedDiagnosticFile file; |
| |
| final List<DiagnosticClassInfo> diagnosticClasses; |
| |
| final StringBuffer out = StringBuffer(''' |
| // Copyright (c) 2021, 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 FILE IS GENERATED. DO NOT EDIT. |
| // |
| // Instead modify 'pkg/analyzer/messages.yaml' and run |
| // 'dart run pkg/analyzer/tool/messages/generate.dart' to update. |
| '''); |
| |
| _AnalyzerDiagnosticClassGenerator(this.file, this.diagnosticClasses); |
| |
| void generate() { |
| file.package.writeIgnoresTo(out); |
| out.writeln(); |
| out.write(''' |
| part of ${json.encode(file.parentLibrary)}; |
| '''); |
| for (var diagnosticClass |
| in diagnosticClasses.toList() |
| ..sort((a, b) => a.name.compareTo(b.name))) { |
| out.writeln(); |
| if (diagnosticClass.comment.isNotEmpty) { |
| diagnosticClass.comment.trimRight().split('\n').forEach((line) { |
| out.writeln('/// $line'); |
| }); |
| } |
| out.write('class ${diagnosticClass.name} {'); |
| var memberAccumulator = MemberAccumulator(); |
| |
| for (var message |
| in diagnosticTables.activeMessagesByPackage[diagnosticClass |
| .file |
| .package]!) { |
| if (message.analyzerCode.diagnosticClass != diagnosticClass) continue; |
| |
| LocatedError.wrap(span: message.keySpan, () { |
| message.toClassMember(memberAccumulator: memberAccumulator); |
| }); |
| } |
| |
| var constructor = StringBuffer(); |
| constructor.writeln('/// Do not construct instances of this class.'); |
| constructor.writeln('${diagnosticClass.name}._() : assert(false);'); |
| memberAccumulator.constructors['_'] = constructor.toString(); |
| |
| memberAccumulator.writeTo(out); |
| out.writeln('}'); |
| } |
| } |
| } |
| |
| /// Code generator for files containing analyzer diagnostics as top level |
| /// constants. |
| class _AnalyzerDiagnosticGenerator { |
| /// The package into which diagnostic will be generated. |
| final AnalyzerDiagnosticPackage package; |
| |
| /// The Uri of the library that the generated file will be a part of. |
| final String parentLibrary; |
| |
| final StringBuffer out = StringBuffer(''' |
| // 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. |
| |
| // THIS FILE IS GENERATED. DO NOT EDIT. |
| // |
| // Instead modify 'pkg/analyzer/messages.yaml' and run |
| // 'dart run pkg/analyzer/tool/messages/generate.dart' to update. |
| '''); |
| |
| _AnalyzerDiagnosticGenerator({ |
| required this.package, |
| required this.parentLibrary, |
| }); |
| |
| void generate() { |
| package.writeIgnoresTo(out); |
| out.writeln(); |
| out.write(''' |
| part of ${json.encode(parentLibrary)}; |
| '''); |
| out.writeln(); |
| |
| var memberAccumulator = MemberAccumulator(); |
| |
| for (var message in diagnosticTables.activeMessagesByPackage[package]!) { |
| LocatedError.wrap(span: message.keySpan, () { |
| message.toAnalyzerCode(memberAccumulator: memberAccumulator); |
| }); |
| } |
| |
| memberAccumulator.writeTo(out); |
| } |
| } |
| |
| class _DiagnosticCodeValuesGenerator { |
| final StringBuffer out = StringBuffer(''' |
| // Copyright (c) 2014, 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 FILE IS GENERATED. DO NOT EDIT. |
| // |
| // Instead modify 'pkg/analyzer/messages.yaml' and run |
| // 'dart run pkg/analyzer/tool/messages/generate.dart' to update. |
| '''); |
| |
| void generate() { |
| AnalyzerDiagnosticPackage.analyzer.writeIgnoresTo(out); |
| out.writeln(); |
| out.writeln(r''' |
| part of 'diagnostic_code_values.dart'; |
| '''); |
| out.writeln(); |
| out.writeln( |
| "@AnalyzerPublicApi(message: 'exported by lib/error/error.dart')", |
| ); |
| out.writeln('const List<DiagnosticCode> diagnosticCodeValues = ['); |
| for (var message |
| in diagnosticTables.activeMessagesByPackage[AnalyzerDiagnosticPackage |
| .analyzer]!) { |
| out.writeln(' ${message.analyzerCode.analyzerCodeReference},'); |
| } |
| out.writeln('];'); |
| out.writeln(); |
| _generateSharedAnalyzerCodeList(); |
| out.writeln( |
| "@AnalyzerPublicApi(message: 'exported by lib/error/error.dart')", |
| ); |
| out.writeln('@Deprecated("Use \'diagnosticCodeValues\' instead")'); |
| out.writeln( |
| 'List<DiagnosticCode> get errorCodeValues => diagnosticCodeValues;', |
| ); |
| } |
| |
| void _generateSharedAnalyzerCodeList() { |
| out.writeln('final sharedAnalyzerCodes = <DiagnosticCode>['); |
| for (var entry in diagnosticTables.sortedSharedDiagnostics) { |
| out.writeln('${entry.analyzerCode.analyzerCodeReference},'); |
| } |
| out.writeln('];'); |
| } |
| } |