From dfd26d463c559b79c722e7e5a2cd0b7ef302e876 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 17 Feb 2026 14:35:19 -0800 Subject: [PATCH] [messages] Move AbstractAnalysisRule class hierarchy into src. Moves the following classes from `package:analyzer/analysis_rule/analysis_rule.dart` into `package:analyzer/src/analysis_rule/analysis_rule.dart`: - `AbstractAnalysisRule` - `AnalysisRule` - `MultiAnalysisRule` - `RemovedAnalysisRule` These classes are part of the analyzer public API, so the file `package:analyzer/analysis_rule/analysis_rule.dart` remains, exporting the declarations so that they can still be used by clients. This paves the way for a follow-up CL that will use extensions to add functionality that we *don't* want to include in the analyzer public API yet. Change-Id: I6a6a696431f00f69b4b80e0d98b1b8fbb33f020f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/481164 Reviewed-by: Konstantin Shcheglov Commit-Queue: Paul Berry --- .../lib/analysis_rule/analysis_rule.dart | 330 +---------------- .../lib/src/analysis_rule/analysis_rule.dart | 341 ++++++++++++++++++ pkg/analyzer_testing/api.txt | 4 +- 3 files changed, 349 insertions(+), 326 deletions(-) create mode 100644 pkg/analyzer/lib/src/analysis_rule/analysis_rule.dart diff --git a/pkg/analyzer/lib/analysis_rule/analysis_rule.dart b/pkg/analyzer/lib/analysis_rule/analysis_rule.dart index f78c6951306..f0c0b5a9de0 100644 --- a/pkg/analyzer/lib/analysis_rule/analysis_rule.dart +++ b/pkg/analyzer/lib/analysis_rule/analysis_rule.dart @@ -2,327 +2,9 @@ // 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 'package:analyzer/analysis_rule/pubspec.dart'; -import 'package:analyzer/analysis_rule/rule_context.dart'; -import 'package:analyzer/analysis_rule/rule_state.dart'; -import 'package:analyzer/analysis_rule/rule_visitor_registry.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/token.dart'; -import 'package:analyzer/diagnostic/diagnostic.dart'; -import 'package:analyzer/error/error.dart'; -import 'package:analyzer/error/listener.dart'; -import 'package:analyzer/src/lint/pub.dart'; -import 'package:pub_semver/pub_semver.dart'; - -/// Describes a static analysis rule, either a lint rule (which must be enabled -/// via analysis options) or a warning rule (which is enabled by default). -sealed class AbstractAnalysisRule { - /// Used to report lints and warnings. - /// - /// NOTE: this is set by the framework before any node processors start - /// visiting nodes. - late DiagnosticReporter _reporter; - - /// Short description suitable for display in console output and IDEs. - /// - /// This text may be used when providing information about a rule listed in - /// analysis options file, or to suggest enabling a rule. - final String description; - - /// The rule name. - final String name; - - /// The state of this analysis rule. - /// - /// See [RuleState] for a list of the possible states and when they should be - /// applied to a given rule. - final RuleState state; - - AbstractAnalysisRule({ - required this.name, - required this.description, - this.state = const RuleState.stable(), - }); - - /// Indicates whether this analysis rule can work with just the parsed - /// information or if it requires a resolved unit. - bool get canUseParsedResult => false; - - /// The diagnostic codes associated with this analysis rule. - List get diagnosticCodes; - - /// A list of incompatible rule names. - /// - /// Two rules are incompatible if there are situations where it is difficult - /// or impossible to comply with both. The analyzer will warn if two - /// incompatible rules are both enabled in analysis options. - List get incompatibleRules => const []; - - /// A visitor that visits a [Pubspec] to perform analysis. - /// - /// Diagnostics are reported via this [AbstractAnalysisRule]'s error - /// [reporter]. - PubspecVisitor? get pubspecVisitor => null; - - /// Sets the [DiagnosticReporter] for the [CompilationUnit] currently being - /// visited. - set reporter(DiagnosticReporter value) => _reporter = value; - - /// Registers node processors in the given [registry]. - /// - /// The node processors may use the provided [context] to access information - /// that is not available from the AST nodes or their associated elements. - void registerNodeProcessors( - RuleVisitorRegistry registry, - RuleContext context, - ) {} - - Diagnostic? _reportAtNode( - AstNode? node, { - List arguments = const [], - List? contextMessages, - required DiagnosticCode diagnosticCode, - }) { - if (node != null && !node.isSynthetic) { - return _reporter.atNode( - node, - diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - } - return null; - } - - Diagnostic _reportAtOffset( - int offset, - int length, { - required DiagnosticCode diagnosticCode, - List arguments = const [], - List? contextMessages, - }) { - return _reporter.atOffset( - offset: offset, - length: length, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - } - - Diagnostic _reportAtPubNode( - PubspecNodeImpl node, { - List arguments = const [], - List contextMessages = const [], - required DiagnosticCode diagnosticCode, - }) { - // Cache diagnostic and location info for creating `AnalysisErrorInfo`s. - var diagnostic = Diagnostic.tmp( - source: node.source, - offset: node.span.start.offset, - length: node.span.length, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - _reporter.reportError(diagnostic); - return diagnostic; - } - - Diagnostic? _reportAtToken( - Token token, { - required DiagnosticCode diagnosticCode, - List arguments = const [], - List? contextMessages, - }) { - if (!token.isSynthetic) { - return _reporter.atToken( - token, - diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - } - return null; - } -} - -/// Describes an [AbstractAnalysisRule] which reports exactly one type of -/// diagnostic (one [DiagnosticCode]). -abstract class AnalysisRule extends AbstractAnalysisRule { - AnalysisRule({required super.name, required super.description, super.state}); - - /// The code to report for a violation. - DiagnosticCode get diagnosticCode; - - @override - List get diagnosticCodes => [diagnosticCode]; - - /// Reports a diagnostic at [node] with message [arguments] and - /// [contextMessages]. - /// - /// {@template analyzer.lib.analysis_rule.analysis_rule.arguments} - /// The [arguments] are interpolated into the [DiagnosticCode.problemMessage] - /// and [DiagnosticCode.correctionMessage] text. If present, the first - /// argument (at position 0) replaces each instance of `{0}`, the second - /// argument (at position 1) replaces each instance of `{1}`, etc. - /// {@endtemplate} - Diagnostic? reportAtNode( - AstNode? node, { - List arguments = const [], - List? contextMessages, - }) => _reportAtNode( - node, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - - /// Reports a diagnostic at [offset], with [length], with message [arguments] - /// and [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic reportAtOffset( - int offset, - int length, { - List arguments = const [], - List? contextMessages, - }) => _reportAtOffset( - offset, - length, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - - /// Reports a diagnostic at Pubspec [node], with message [arguments] and - /// [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic reportAtPubNode( - PubspecNode node, { - List arguments = const [], - List contextMessages = const [], - }) => _reportAtPubNode( - node as PubspecNodeImpl, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - - /// Reports a diagnostic at [token], with message [arguments] and - /// [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic? reportAtToken( - Token token, { - List arguments = const [], - List? contextMessages, - }) => _reportAtToken( - token, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); -} - -/// Describes an [AbstractAnalysisRule] which reports diagnostics using multiple -/// [DiagnosticCode]s). -abstract class MultiAnalysisRule extends AbstractAnalysisRule { - MultiAnalysisRule({ - required super.name, - required super.description, - super.state, - }); - - /// Reports [diagnosticCode] at [node] with message [arguments] and - /// [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic? reportAtNode( - AstNode? node, { - List arguments = const [], - List? contextMessages, - required DiagnosticCode diagnosticCode, - }) => _reportAtNode( - node, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - - /// Reports [diagnosticCode] at [offset], with [length], with message [arguments] - /// and [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic reportAtOffset( - int offset, - int length, { - required DiagnosticCode diagnosticCode, - List arguments = const [], - List? contextMessages, - }) => _reportAtOffset( - offset, - length, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - - /// Reports [diagnosticCode] at Pubspec [node], with message [arguments] and - /// [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic reportAtPubNode( - PubspecNode node, { - required DiagnosticCode diagnosticCode, - List arguments = const [], - List contextMessages = const [], - }) { - // Cache diagnostic and location info for creating `AnalysisErrorInfo`s. - var diagnostic = Diagnostic.tmp( - source: (node as PubspecNodeImpl).source, - offset: node.span.start.offset, - length: node.span.length, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); - _reporter.reportError(diagnostic); - return diagnostic; - } - - /// Reports [diagnosticCode] at [token], with message [arguments] and - /// [contextMessages]. - /// - /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} - Diagnostic? reportAtToken( - Token token, { - required DiagnosticCode diagnosticCode, - List arguments = const [], - List? contextMessages, - }) => _reportAtToken( - token, - diagnosticCode: diagnosticCode, - arguments: arguments, - contextMessages: contextMessages, - ); -} - -/// Describes an [AbstractAnalysisRule] whose implementation has been removed. -final class RemovedAnalysisRule extends MultiAnalysisRule { - RemovedAnalysisRule({ - required super.name, - required super.description, - Version? since, - String? replacedBy, - }) : super( - // Note: the reason `RuleState.removed` is deprecated is to encourage - // clients to use `AbstractAnalysisRule`, so this reference is ok. - // ignore: deprecated_member_use_from_same_package - state: RuleState.removed(since: since, replacedBy: replacedBy), - ); - - @override - List get diagnosticCodes => const []; -} +export 'package:analyzer/src/analysis_rule/analysis_rule.dart' + show + AbstractAnalysisRule, + AnalysisRule, + MultiAnalysisRule, + RemovedAnalysisRule; diff --git a/pkg/analyzer/lib/src/analysis_rule/analysis_rule.dart b/pkg/analyzer/lib/src/analysis_rule/analysis_rule.dart new file mode 100644 index 00000000000..ae04487e929 --- /dev/null +++ b/pkg/analyzer/lib/src/analysis_rule/analysis_rule.dart @@ -0,0 +1,341 @@ +// Copyright (c) 2026, 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 'package:_fe_analyzer_shared/src/base/analyzer_public_api.dart'; +import 'package:analyzer/analysis_rule/pubspec.dart'; +import 'package:analyzer/analysis_rule/rule_context.dart'; +import 'package:analyzer/analysis_rule/rule_state.dart'; +import 'package:analyzer/analysis_rule/rule_visitor_registry.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/token.dart'; +import 'package:analyzer/diagnostic/diagnostic.dart'; +import 'package:analyzer/error/error.dart'; +import 'package:analyzer/error/listener.dart'; +import 'package:analyzer/src/lint/pub.dart'; +import 'package:pub_semver/pub_semver.dart'; + +/// Describes a static analysis rule, either a lint rule (which must be enabled +/// via analysis options) or a warning rule (which is enabled by default). +@AnalyzerPublicApi( + message: 'Exported by package:analyzer/analysis_rule/analysis_rule.dart', +) +sealed class AbstractAnalysisRule { + /// Used to report lints and warnings. + /// + /// NOTE: this is set by the framework before any node processors start + /// visiting nodes. + late DiagnosticReporter _reporter; + + /// Short description suitable for display in console output and IDEs. + /// + /// This text may be used when providing information about a rule listed in + /// analysis options file, or to suggest enabling a rule. + final String description; + + /// The rule name. + final String name; + + /// The state of this analysis rule. + /// + /// See [RuleState] for a list of the possible states and when they should be + /// applied to a given rule. + final RuleState state; + + AbstractAnalysisRule({ + required this.name, + required this.description, + this.state = const RuleState.stable(), + }); + + /// Indicates whether this analysis rule can work with just the parsed + /// information or if it requires a resolved unit. + bool get canUseParsedResult => false; + + /// The diagnostic codes associated with this analysis rule. + List get diagnosticCodes; + + /// A list of incompatible rule names. + /// + /// Two rules are incompatible if there are situations where it is difficult + /// or impossible to comply with both. The analyzer will warn if two + /// incompatible rules are both enabled in analysis options. + List get incompatibleRules => const []; + + /// A visitor that visits a [Pubspec] to perform analysis. + /// + /// Diagnostics are reported via this [AbstractAnalysisRule]'s error + /// [reporter]. + PubspecVisitor? get pubspecVisitor => null; + + /// Sets the [DiagnosticReporter] for the [CompilationUnit] currently being + /// visited. + set reporter(DiagnosticReporter value) => _reporter = value; + + /// Registers node processors in the given [registry]. + /// + /// The node processors may use the provided [context] to access information + /// that is not available from the AST nodes or their associated elements. + void registerNodeProcessors( + RuleVisitorRegistry registry, + RuleContext context, + ) {} + + Diagnostic? _reportAtNode( + AstNode? node, { + List arguments = const [], + List? contextMessages, + required DiagnosticCode diagnosticCode, + }) { + if (node != null && !node.isSynthetic) { + return _reporter.atNode( + node, + diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + } + return null; + } + + Diagnostic _reportAtOffset( + int offset, + int length, { + required DiagnosticCode diagnosticCode, + List arguments = const [], + List? contextMessages, + }) { + return _reporter.atOffset( + offset: offset, + length: length, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + } + + Diagnostic _reportAtPubNode( + PubspecNodeImpl node, { + List arguments = const [], + List contextMessages = const [], + required DiagnosticCode diagnosticCode, + }) { + // Cache diagnostic and location info for creating `AnalysisErrorInfo`s. + var diagnostic = Diagnostic.tmp( + source: node.source, + offset: node.span.start.offset, + length: node.span.length, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + _reporter.reportError(diagnostic); + return diagnostic; + } + + Diagnostic? _reportAtToken( + Token token, { + required DiagnosticCode diagnosticCode, + List arguments = const [], + List? contextMessages, + }) { + if (!token.isSynthetic) { + return _reporter.atToken( + token, + diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + } + return null; + } +} + +/// Describes an [AbstractAnalysisRule] which reports exactly one type of +/// diagnostic (one [DiagnosticCode]). +@AnalyzerPublicApi( + message: 'Exported by package:analyzer/analysis_rule/analysis_rule.dart', +) +abstract class AnalysisRule extends AbstractAnalysisRule { + AnalysisRule({required super.name, required super.description, super.state}); + + /// The code to report for a violation. + DiagnosticCode get diagnosticCode; + + @override + List get diagnosticCodes => [diagnosticCode]; + + /// Reports a diagnostic at [node] with message [arguments] and + /// [contextMessages]. + /// + /// {@template analyzer.lib.analysis_rule.analysis_rule.arguments} + /// The [arguments] are interpolated into the [DiagnosticCode.problemMessage] + /// and [DiagnosticCode.correctionMessage] text. If present, the first + /// argument (at position 0) replaces each instance of `{0}`, the second + /// argument (at position 1) replaces each instance of `{1}`, etc. + /// {@endtemplate} + Diagnostic? reportAtNode( + AstNode? node, { + List arguments = const [], + List? contextMessages, + }) => _reportAtNode( + node, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + + /// Reports a diagnostic at [offset], with [length], with message [arguments] + /// and [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic reportAtOffset( + int offset, + int length, { + List arguments = const [], + List? contextMessages, + }) => _reportAtOffset( + offset, + length, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + + /// Reports a diagnostic at Pubspec [node], with message [arguments] and + /// [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic reportAtPubNode( + PubspecNode node, { + List arguments = const [], + List contextMessages = const [], + }) => _reportAtPubNode( + node as PubspecNodeImpl, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + + /// Reports a diagnostic at [token], with message [arguments] and + /// [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic? reportAtToken( + Token token, { + List arguments = const [], + List? contextMessages, + }) => _reportAtToken( + token, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); +} + +/// Describes an [AbstractAnalysisRule] which reports diagnostics using multiple +/// [DiagnosticCode]s). +@AnalyzerPublicApi( + message: 'Exported by package:analyzer/analysis_rule/analysis_rule.dart', +) +abstract class MultiAnalysisRule extends AbstractAnalysisRule { + MultiAnalysisRule({ + required super.name, + required super.description, + super.state, + }); + + /// Reports [diagnosticCode] at [node] with message [arguments] and + /// [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic? reportAtNode( + AstNode? node, { + List arguments = const [], + List? contextMessages, + required DiagnosticCode diagnosticCode, + }) => _reportAtNode( + node, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + + /// Reports [diagnosticCode] at [offset], with [length], with message [arguments] + /// and [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic reportAtOffset( + int offset, + int length, { + required DiagnosticCode diagnosticCode, + List arguments = const [], + List? contextMessages, + }) => _reportAtOffset( + offset, + length, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + + /// Reports [diagnosticCode] at Pubspec [node], with message [arguments] and + /// [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic reportAtPubNode( + PubspecNode node, { + required DiagnosticCode diagnosticCode, + List arguments = const [], + List contextMessages = const [], + }) { + // Cache diagnostic and location info for creating `AnalysisErrorInfo`s. + var diagnostic = Diagnostic.tmp( + source: (node as PubspecNodeImpl).source, + offset: node.span.start.offset, + length: node.span.length, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); + _reporter.reportError(diagnostic); + return diagnostic; + } + + /// Reports [diagnosticCode] at [token], with message [arguments] and + /// [contextMessages]. + /// + /// {@macro analyzer.lib.analysis_rule.analysis_rule.arguments} + Diagnostic? reportAtToken( + Token token, { + required DiagnosticCode diagnosticCode, + List arguments = const [], + List? contextMessages, + }) => _reportAtToken( + token, + diagnosticCode: diagnosticCode, + arguments: arguments, + contextMessages: contextMessages, + ); +} + +/// Describes an [AbstractAnalysisRule] whose implementation has been removed. +@AnalyzerPublicApi( + message: 'Exported by package:analyzer/analysis_rule/analysis_rule.dart', +) +final class RemovedAnalysisRule extends MultiAnalysisRule { + RemovedAnalysisRule({ + required super.name, + required super.description, + Version? since, + String? replacedBy, + }) : super( + // Note: the reason `RuleState.removed` is deprecated is to encourage + // clients to use `AbstractAnalysisRule`, so this reference is ok. + // ignore: deprecated_member_use_from_same_package + state: RuleState.removed(since: since, replacedBy: replacedBy), + ); + + @override + List get diagnosticCodes => const []; +} diff --git a/pkg/analyzer_testing/api.txt b/pkg/analyzer_testing/api.txt index e9bbf653506..d51689d1272 100644 --- a/pkg/analyzer_testing/api.txt +++ b/pkg/analyzer_testing/api.txt @@ -92,13 +92,13 @@ dart:core: package:_fe_analyzer_shared/src/base/errors.dart: Diagnostic (referenced) DiagnosticCode (referenced) -package:analyzer/analysis_rule/analysis_rule.dart: - AbstractAnalysisRule (referenced) package:analyzer/file_system/file_system.dart: File (referenced) Folder (referenced) Link (referenced) ResourceProvider (referenced) +package:analyzer/src/analysis_rule/analysis_rule.dart: + AbstractAnalysisRule (referenced) package:analyzer/utilities/package_config_file_builder.dart: PackageConfigFileBuilder (referenced) package:path/src/context.dart: