Skip to content

Commit d6f6e52

Browse files
stereotype441Commit Queue
authored andcommitted
[messages] Extract computation of constantStyle.
Extracts the computation of `concreteClassName` and `staticType` from `MessageWithAnalyzerCode.toAnalyzerCode` to a late field, `constantStyle`, that encapsulates these values. The late field also captures information about what kind of diagnostic constant should be code generated, and if it should be a diagnostic constant that supports `withArguments`, what the parameters of `withArguments` should be. This paves the way for a follow-up CL that will move the diagnostic constants to top level declarations; this logic will require multiple methods in `MessageWithAnalyzerCode` to refer to the constant style. Change-Id: I6a6a69644ff69061186f61a6ba146916fbf4ef1c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/461141 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 9d1c453 commit d6f6e52

File tree

2 files changed

+92
-28
lines changed

2 files changed

+92
-28
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// Encapsulates information about how to generate an analyzer diagnostic
6+
/// message constant, including the style of constant to generate (e.g. with
7+
/// arguments or without) and the classes that should be referenced by the
8+
/// generated code.
9+
sealed class ConstantStyle {
10+
/// The concrete class name that should be used to construct the constant.
11+
final String concreteClassName;
12+
13+
/// The static type of the constant that should be generated.
14+
final String staticType;
15+
16+
ConstantStyle({required this.concreteClassName, required this.staticType});
17+
}
18+
19+
/// [ConstantStyle] object indicating that an "old style" constant should be
20+
/// generated (one that does not support the new analyzer literate API for
21+
/// constants).
22+
// TODO(paulberry): finish supporting the literate API in all analyzer messages
23+
// and eliminate this.
24+
class OldConstantStyle extends ConstantStyle {
25+
OldConstantStyle({
26+
required super.concreteClassName,
27+
required super.staticType,
28+
});
29+
}
30+
31+
/// [ConstantStyle] object indicating that a constant should be generated that
32+
/// supports a `.withArguments` getter.
33+
class WithArgumentsConstantStyle extends ConstantStyle {
34+
/// The parameters that should be accepted by the `.withArguments` getter.
35+
final String withArgumentsParams;
36+
37+
WithArgumentsConstantStyle({
38+
required super.concreteClassName,
39+
required super.staticType,
40+
required this.withArgumentsParams,
41+
});
42+
}
43+
44+
/// [ConstantStyle] object indicating that a constant should be generated that
45+
/// doesn't require any arguments.
46+
class WithoutArgumentsConstantStyle extends ConstantStyle {
47+
WithoutArgumentsConstantStyle({
48+
required super.concreteClassName,
49+
required super.staticType,
50+
});
51+
}

pkg/analyzer_utilities/lib/analyzer_messages.dart

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:convert';
99
import 'dart:io';
1010

1111
import 'package:analyzer_testing/package_root.dart' as pkg_root;
12+
import 'package:analyzer_utilities/analyzer_message_constant_style.dart';
1213
import 'package:analyzer_utilities/extensions/string.dart';
1314
import 'package:analyzer_utilities/messages.dart';
1415
import 'package:analyzer_utilities/tools.dart';
@@ -550,6 +551,42 @@ class DiagnosticClassInfo {
550551
/// Interface class for diagnostic messages that have an analyzer code, and thus
551552
/// can be reported by the analyzer.
552553
mixin MessageWithAnalyzerCode on Message {
554+
late ConstantStyle constantStyle = () {
555+
var usesParameters = [problemMessage, correctionMessage].any(
556+
(value) =>
557+
value != null && value.any((part) => part is TemplateParameterPart),
558+
);
559+
var baseClasses = analyzerCode.diagnosticClass.type.baseClasses;
560+
if (parameters.isNotEmpty && !usesParameters) {
561+
throw 'Error code declares parameters using a `parameters` entry, but '
562+
"doesn't use them";
563+
} else if (parameters.values.any((p) => !p.type.isSupportedByAnalyzer)) {
564+
// Do not generate literate API yet.
565+
return OldConstantStyle(
566+
concreteClassName: baseClasses.withExpectedTypesClass,
567+
staticType: 'DiagnosticCode',
568+
);
569+
} else if (parameters.isNotEmpty) {
570+
// Parameters are present so generate a diagnostic template (with
571+
// `.withArguments` support).
572+
var withArgumentsParams = parameters.entries
573+
.map((p) => 'required ${p.value.type.analyzerName} ${p.key}')
574+
.join(', ');
575+
var templateParameters =
576+
'<LocatableDiagnostic Function({$withArgumentsParams})>';
577+
return WithArgumentsConstantStyle(
578+
concreteClassName: baseClasses.withArgumentsClass,
579+
staticType: 'DiagnosticWithArguments$templateParameters',
580+
withArgumentsParams: withArgumentsParams,
581+
);
582+
} else {
583+
return WithoutArgumentsConstantStyle(
584+
concreteClassName: baseClasses.withoutArgumentsImplClass,
585+
staticType: baseClasses.withoutArgumentsClass,
586+
);
587+
}
588+
}();
589+
553590
late final DiagnosticClassInfo diagnosticClassInfo =
554591
analyzerCode.diagnosticClass;
555592

@@ -583,44 +620,20 @@ mixin MessageWithAnalyzerCode on Message {
583620
}) {
584621
var diagnosticCode = analyzerCode.snakeCaseName;
585622
var correctionMessage = this.correctionMessage;
586-
var parameters = this.parameters;
587-
var usesParameters = [problemMessage, correctionMessage].any(
588-
(value) =>
589-
value != null && value.any((part) => part is TemplateParameterPart),
590-
);
591-
String concreteClassName;
592-
String staticType;
593623
String? withArgumentsName;
594624
var baseClasses = analyzerCode.diagnosticClass.type.baseClasses;
595-
if (parameters.isNotEmpty && !usesParameters) {
596-
throw 'Error code declares parameters using a `parameters` entry, but '
597-
"doesn't use them";
598-
} else if (parameters.values.any((p) => !p.type.isSupportedByAnalyzer)) {
599-
// Do not generate literate API yet.
600-
concreteClassName = baseClasses.withExpectedTypesClass;
601-
staticType = 'DiagnosticCode';
602-
} else if (parameters.isNotEmpty) {
603-
// Parameters are present so generate a diagnostic template (with
604-
// `.withArguments` support).
605-
concreteClassName = baseClasses.withArgumentsClass;
606-
var withArgumentsParams = parameters.entries
607-
.map((p) => 'required ${p.value.type.analyzerName} ${p.key}')
608-
.join(', ');
625+
var ConstantStyle(:concreteClassName, :staticType) = constantStyle;
626+
if (constantStyle case WithArgumentsConstantStyle(
627+
:var withArgumentsParams,
628+
)) {
609629
var argumentNames = parameters.keys.join(', ');
610630
withArgumentsName = '_withArguments${analyzerCode.pascalCaseName}';
611-
var templateParameters =
612-
'<LocatableDiagnostic Function({$withArgumentsParams})>';
613-
staticType = 'DiagnosticWithArguments$templateParameters';
614631
memberAccumulator.staticMethods[withArgumentsName] =
615632
'''
616633
static LocatableDiagnostic $withArgumentsName({$withArgumentsParams}) {
617634
return LocatableDiagnosticImpl(
618635
${diagnosticClassInfo.name}.$constantName, [$argumentNames]);
619636
}''';
620-
} else {
621-
// Parameters are not present so generate a "withoutArguments" constant.
622-
concreteClassName = baseClasses.withoutArgumentsImplClass;
623-
staticType = baseClasses.withoutArgumentsClass;
624637
}
625638

626639
var constant = StringBuffer();

0 commit comments

Comments
 (0)