Skip to content

Commit a9a9c37

Browse files
stereotype441Commit Queue
authored andcommitted
[analyzer] Prepare to rename error codes to camelCase.
A temporary script is added, `pkg/analyzer/tool/messages/rename_error_constants.dart`, which will rename every error code in the analyzer (and related packages) from SCREAMING_CAPS to camelCase. Also, the error message code generator is enhanced so that it can generate error codes using either SCREAMING_CAPS or camelCase, based on the setting of a temporary constant, `_useLowerCamelCaseNames`. The constant is currently set to `false`; `rename_error_constants.dart` will change it to `true`. There are a few references to the old SCREAMING_CAPS names that won't be able to be automatically addressed by the script. To avoid breakages, a mechanism has been added to the error message code generator to preserve those names after the migration, as deprecated aliases. The names that will be preserved are listed in the `ErrorClassInfo.deprecatedSnakeCaseNames` field, in `error_code_info.dart`. These will be cleaned up in future CLs. Once the rename is complete, the temporary script and constant will be removed. Change-Id: I6a6a69640b077c6bc4da92cec97686e4b2c3b906 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/444920 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Moritz Sümmermann <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent 6f4b7e2 commit a9a9c37

File tree

7 files changed

+267
-13
lines changed

7 files changed

+267
-13
lines changed

pkg/analyzer/lib/src/utilities/extensions/string.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,33 @@ extension StringExtension on String {
160160
}
161161
}
162162

163+
/// Converts `SCREAMING_SNAKE_CASE` or `snake_case` to `camelCase`.
164+
String toCamelCase() {
165+
var parts = toLowerCase().split('_');
166+
var buffer = StringBuffer();
167+
var i = 0;
168+
// Preserve initial '_'s
169+
while (i < parts.length - 1 && parts[i].isEmpty) {
170+
buffer.write('_');
171+
++i;
172+
}
173+
if (i < parts.length) {
174+
// Convert first word to lower case
175+
buffer.write(parts[i].toLowerCase());
176+
++i;
177+
// Convert remaining words to initial upper case
178+
while (i < parts.length) {
179+
var part = parts[i];
180+
if (part.isNotEmpty) {
181+
buffer.write(part[0].toUpperCase());
182+
buffer.write(part.substring(1));
183+
}
184+
++i;
185+
}
186+
}
187+
return buffer.toString();
188+
}
189+
163190
/// Converts `camelCase` / `PascalCase` to `SCREAMING_SNAKE_CASE`.
164191
/// Examples:
165192
/// - camelCase -> CAMEL_CASE

pkg/analyzer/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dependencies:
3131
# See also https://dart.dev/tools/pub/dependencies.
3232
dev_dependencies:
3333
analysis_server_client: any
34+
analyzer_plugin: any
3435
analyzer_testing: any
3536
analyzer_utilities: any
3637
args: any

pkg/analyzer/test/src/utilities/extensions/string_test.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,18 @@ class StringExtensionTest {
197197
expect('01234'.removeSuffix('5'), isNull);
198198
}
199199

200+
void test_toCamelCase() {
201+
expect('CAMEL_CASE'.toCamelCase(), 'camelCase');
202+
expect('alreadyCamel_case'.toCamelCase(), 'alreadycamelCase');
203+
expect('FOO_123_BAR'.toCamelCase(), 'foo123Bar');
204+
expect('FOO'.toCamelCase(), 'foo');
205+
expect('___'.toCamelCase(), '___');
206+
expect(''.toCamelCase(), '');
207+
expect('_FOO_BAR'.toCamelCase(), '_fooBar');
208+
expect('FOO__BAR'.toCamelCase(), 'fooBar');
209+
expect('FOO_BAR_'.toCamelCase(), 'fooBar');
210+
}
211+
200212
void test_toScreamingSnake() {
201213
expect('camelCase'.toScreamingSnake(), 'CAMEL_CASE');
202214
expect('HTTPRequest'.toScreamingSnake(), 'HTTP_REQUEST');

pkg/analyzer/tool/messages/error_code_info.dart

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ const List<ErrorClassInfo> errorClasses = [
3434
file: codesFile,
3535
name: 'CompileTimeErrorCode',
3636
type: 'COMPILE_TIME_ERROR',
37+
deprecatedSnakeCaseNames: {
38+
'IMPORT_INTERNAL_LIBRARY', // Referenced by `verify_docs.dart`.
39+
'INSTANCE_ACCESS_TO_STATIC_MEMBER', // Referenced by `messages.yaml`.
40+
'INVALID_OVERRIDE', // Referenced by `messages.yaml`.
41+
'TYPE_ARGUMENT_NOT_MATCHING_BOUNDS', // Referenced by `messages.yaml`.
42+
'UNDEFINED_CLASS', // Referenced by `messages.yaml`.
43+
},
3744
),
3845
ErrorClassInfo(
3946
file: scannerErrorFile,
@@ -51,19 +58,35 @@ const List<ErrorClassInfo> errorClasses = [
5158
name: 'WarningCode',
5259
type: 'STATIC_WARNING',
5360
severity: 'WARNING',
61+
deprecatedSnakeCaseNames: {
62+
'UNUSED_ELEMENT', // Referenced by `verify_docs.dart`.
63+
'UNUSED_IMPORT', // Referenced by `verify_docs.dart`.
64+
'UNUSED_LOCAL_VARIABLE', // Referenced by `verify_docs.dart`.
65+
},
5466
),
5567
ErrorClassInfo(
5668
file: ffiCodesFile,
5769
name: 'FfiCode',
5870
type: 'COMPILE_TIME_ERROR',
5971
),
60-
ErrorClassInfo(file: hintCodesFile, name: 'HintCode', type: 'HINT'),
72+
ErrorClassInfo(
73+
file: hintCodesFile,
74+
name: 'HintCode',
75+
type: 'HINT',
76+
deprecatedSnakeCaseNames: {
77+
'UNNECESSARY_IMPORT', // Referenced by `verify_docs.dart`.
78+
},
79+
),
6180
ErrorClassInfo(
6281
file: syntacticErrorsFile,
6382
name: 'ParserErrorCode',
6483
type: 'SYNTACTIC_ERROR',
6584
severity: 'ERROR',
6685
includeCfeMessages: true,
86+
deprecatedSnakeCaseNames: {
87+
'EXPERIMENT_NOT_ENABLED', // Referenced by `messages.yaml`.
88+
'UNEXPECTED_TOKEN', // Referenced by `package:dart_style`.
89+
},
6790
),
6891
ErrorClassInfo(
6992
file: manifestWarningCodeFile,
@@ -492,6 +515,11 @@ class ErrorClassInfo {
492515
/// The type of errors in this class.
493516
final String type;
494517

518+
/// The names of any errors which are relied upon by analyzer clients, and
519+
/// therefore will need their "snake case" form preserved (with a deprecation
520+
/// notice) after migration to camel case error codes.
521+
final Set<String> deprecatedSnakeCaseNames;
522+
495523
const ErrorClassInfo({
496524
this.extraImports = const [],
497525
required this.file,
@@ -500,6 +528,7 @@ class ErrorClassInfo {
500528
this.severity,
501529
this.superclass = 'DiagnosticCode',
502530
required this.type,
531+
this.deprecatedSnakeCaseNames = const {},
503532
});
504533

505534
/// Generates the code to compute the severity of errors of this class.

pkg/analyzer/tool/messages/generate.dart

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ library;
1919
import 'dart:convert';
2020
import 'dart:io';
2121

22+
import 'package:analyzer/src/utilities/extensions/string.dart';
2223
import 'package:analyzer_testing/package_root.dart' as pkg_root;
2324
import 'package:analyzer_utilities/tools.dart';
2425
import 'package:collection/collection.dart';
@@ -34,6 +35,14 @@ Future<void> main() async {
3435
..printSummary();
3536
}
3637

38+
/// Whether the error constants that should be generated should use camel-case
39+
/// names.
40+
///
41+
/// This is a temporary flag to allow the codebase to be transitioned to using
42+
/// camel-case error constants. TODO(paulberry): once the transition is
43+
/// complete, remove this constant.
44+
const _useLowerCamelCaseNames = false;
45+
3746
/// A list of all targets generated by this code generator.
3847
final List<GeneratedContent> allTargets = _analyzerGeneratedFiles();
3948

@@ -44,7 +53,7 @@ List<GeneratedContent> _analyzerGeneratedFiles() {
4453
for (var errorClassInfo in errorClasses) {
4554
(classesByFile[errorClassInfo.file] ??= []).add(errorClassInfo);
4655
}
47-
var generatedCodes = <String>[];
56+
var generatedCodes = <(String, String)>[];
4857
return [
4958
for (var entry in classesByFile.entries)
5059
GeneratedFile(entry.key.path, (pkgRoot) async {
@@ -72,7 +81,7 @@ class _AnalyzerErrorGenerator {
7281

7382
final List<ErrorClassInfo> errorClasses;
7483

75-
final List<String> generatedCodes;
84+
final List<(String, String)> generatedCodes;
7685

7786
final StringBuffer out = StringBuffer('''
7887
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
@@ -154,15 +163,26 @@ library;
154163
);
155164
out.writeln('${errorCodeInfo.aliasFor};');
156165
} else {
157-
generatedCodes.add('${errorClass.name}.$errorName');
158-
out.writeln(' static const ${errorClass.name} $errorName =');
166+
generatedCodes.add((errorClass.name, errorName));
167+
var constantName =
168+
_useLowerCamelCaseNames ? errorName.toCamelCase() : errorName;
169+
out.writeln(' static const ${errorClass.name} $constantName =');
159170
out.writeln(
160171
errorCodeInfo.toAnalyzerCode(
161172
errorClass,
162173
errorName,
163174
useExplicitConst: file.shouldUseExplicitConst,
164175
),
165176
);
177+
178+
if (_useLowerCamelCaseNames &&
179+
errorClass.deprecatedSnakeCaseNames.contains(errorName)) {
180+
out.writeln();
181+
out.writeln(' @Deprecated("Please use $constantName")');
182+
out.writeln(
183+
' static const ${errorClass.name} $errorName = $constantName;',
184+
);
185+
}
166186
}
167187
} catch (e, st) {
168188
Error.throwWithStackTrace(
@@ -205,14 +225,17 @@ library;
205225
out.writeln('final fastaAnalyzerErrorCodes = <DiagnosticCode?>[');
206226
for (var entry in cfeToAnalyzerErrorCodeTables.indexToInfo) {
207227
var name = cfeToAnalyzerErrorCodeTables.infoToAnalyzerCode[entry];
228+
if (_useLowerCamelCaseNames) {
229+
name = name?.toCamelCase();
230+
}
208231
out.writeln('${name == null ? 'null' : 'ParserErrorCode.$name'},');
209232
}
210233
out.writeln('];');
211234
}
212235
}
213236

214237
class _DiagnosticCodeValuesGenerator {
215-
final List<String> generatedCodes;
238+
final List<(String, String)> generatedCodes;
216239

217240
final StringBuffer out = StringBuffer('''
218241
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
@@ -239,12 +262,12 @@ class _DiagnosticCodeValuesGenerator {
239262
// The scanner error codes are not yet being generated, so we need to add
240263
// them to the list explicitly.
241264
generatedCodes.addAll([
242-
'TodoCode.TODO',
243-
'TodoCode.FIXME',
244-
'TodoCode.HACK',
245-
'TodoCode.UNDONE',
265+
('TodoCode', 'TODO'),
266+
('TodoCode', 'FIXME'),
267+
('TodoCode', 'HACK'),
268+
('TodoCode', 'UNDONE'),
246269
]);
247-
generatedCodes.sort();
270+
generatedCodes.sortBy((x) => '${x.$1}.${x.$2}');
248271

249272
out.writeln();
250273
out.writeln(r'''
@@ -261,8 +284,11 @@ import 'package:analyzer/src/pubspec/pubspec_warning_code.dart';
261284
"@AnalyzerPublicApi(message: 'exported by lib/error/error.dart')",
262285
);
263286
out.writeln('const List<DiagnosticCode> diagnosticCodeValues = [');
264-
for (var name in generatedCodes) {
265-
out.writeln(' $name,');
287+
for (var (className, errorName) in generatedCodes) {
288+
if (_useLowerCamelCaseNames) {
289+
errorName = errorName.toCamelCase();
290+
}
291+
out.writeln(' $className.$errorName,');
266292
}
267293
out.writeln('];');
268294
out.writeln();

0 commit comments

Comments
 (0)