From 03d0629a69d61ca16a0dca3e0f8e285041b61350 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 15 Sep 2025 16:07:55 -0700 Subject: [PATCH] DAS plugins: provide a WorkspacePackage to RuleContext Fixes https://github.com/dart-lang/sdk/issues/61489 Change-Id: I50dc5a0649ef9f77e37efb27430cbb3736814313 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449360 Commit-Queue: Samuel Rawlins Reviewed-by: Brian Wilkerson --- .../lib/src/plugin_server.dart | 6 +- .../test/src/lint_rules.dart | 67 ++++++++++++++----- .../test/src/plugin_server_test.dart | 32 ++++++++- 3 files changed, 87 insertions(+), 18 deletions(-) diff --git a/pkg/analysis_server_plugin/lib/src/plugin_server.dart b/pkg/analysis_server_plugin/lib/src/plugin_server.dart index 79bc6b6f3d5..dec9ce1d363 100644 --- a/pkg/analysis_server_plugin/lib/src/plugin_server.dart +++ b/pkg/analysis_server_plugin/lib/src/plugin_server.dart @@ -390,14 +390,16 @@ class PluginServer { // TODO(srawlins): Enable timing similar to what the linter package's // `benchmark.dart` script does. var nodeRegistry = RuleVisitorRegistryImpl(enableTiming: false); + var package = analysisContext.contextRoot.workspace.findPackageFor( + libraryPath, + ); var context = RuleContextWithResolvedResults( allUnits, definingContextUnit, libraryResult.element.typeProvider, libraryResult.element.typeSystem as TypeSystemImpl, - // TODO(srawlins): Support 'package' parameter. - null, + package, ); // A mapping from each diagnostic code to its corresponding plugin. diff --git a/pkg/analysis_server_plugin/test/src/lint_rules.dart b/pkg/analysis_server_plugin/test/src/lint_rules.dart index 4cb042ebccb..e93129999bc 100644 --- a/pkg/analysis_server_plugin/test/src/lint_rules.dart +++ b/pkg/analysis_server_plugin/test/src/lint_rules.dart @@ -9,6 +9,30 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/error/error.dart'; +class NeedsPackageRule extends AnalysisRule { + static const LintCode code = LintCode( + 'needs_package', + 'Needs Package at {0}', + ); + + NeedsPackageRule() + : super(name: 'needs_package', description: 'This rule needs package info'); + + @override + DiagnosticCode get diagnosticCode => code; + + @override + void registerNodeProcessors( + RuleVisitorRegistry registry, + RuleContext context, + ) { + if (context.isInLibDir) { + var visitor = _NeedsPackageVisitor(this, context); + registry.addIntegerLiteral(this, visitor); + } + } +} + class NoBoolsRule extends AnalysisRule { static const LintCode code = LintCode('no_bools', 'No bools message'); @@ -27,11 +51,18 @@ class NoBoolsRule extends AnalysisRule { } } -class NoDoublesRule extends AnalysisRule { - static const LintCode code = LintCode('no_doubles', 'No doubles message'); +class NoDoublesCustomSeverityRule extends AnalysisRule { + static const LintCode code = LintCode( + 'no_doubles_custom_severity', + 'No doubles message', + severity: DiagnosticSeverity.WARNING, + ); - NoDoublesRule() - : super(name: 'no_doubles', description: 'No doubles message'); + NoDoublesCustomSeverityRule() + : super( + name: 'no_doubles_custom_severity', + description: 'No doubles message', + ); @override DiagnosticCode get diagnosticCode => code; @@ -46,18 +77,11 @@ class NoDoublesRule extends AnalysisRule { } } -class NoDoublesCustomSeverityRule extends AnalysisRule { - static const LintCode code = LintCode( - 'no_doubles_custom_severity', - 'No doubles message', - severity: DiagnosticSeverity.WARNING, - ); +class NoDoublesRule extends AnalysisRule { + static const LintCode code = LintCode('no_doubles', 'No doubles message'); - NoDoublesCustomSeverityRule() - : super( - name: 'no_doubles_custom_severity', - description: 'No doubles message', - ); + NoDoublesRule() + : super(name: 'no_doubles', description: 'No doubles message'); @override DiagnosticCode get diagnosticCode => code; @@ -97,6 +121,19 @@ class NoReferencesToStringsRule extends AnalysisRule { } } +class _NeedsPackageVisitor extends SimpleAstVisitor { + final AnalysisRule rule; + + final RuleContext context; + + _NeedsPackageVisitor(this.rule, this.context); + + @override + void visitIntegerLiteral(IntegerLiteral node) { + rule.reportAtNode(node, arguments: ['"${context.package!.root.path}"']); + } +} + class _NoBoolsVisitor extends SimpleAstVisitor { final AnalysisRule rule; diff --git a/pkg/analysis_server_plugin/test/src/plugin_server_test.dart b/pkg/analysis_server_plugin/test/src/plugin_server_test.dart index ba6a902a57d..5300e338391 100644 --- a/pkg/analysis_server_plugin/test/src/plugin_server_test.dart +++ b/pkg/analysis_server_plugin/test/src/plugin_server_test.dart @@ -36,6 +36,8 @@ class PluginServerTest extends PluginServerTestBase { String get file2Path => join(packagePath, 'lib', 'test2.dart'); + String get testFilePath => join(packagePath, 'test', 'test.dart'); + String get packagePath => convertPath('/package1'); StreamQueue get _analysisErrorsParams { @@ -43,7 +45,12 @@ class PluginServerTest extends PluginServerTestBase { channel.notifications .where((n) => n.event == protocol.ANALYSIS_NOTIFICATION_ERRORS) .map((n) => protocol.AnalysisErrorsParams.fromNotification(n)) - .where((p) => p.file == filePath || p.file == file2Path), + .where( + (p) => + p.file == filePath || + p.file == file2Path || + p.file == testFilePath, + ), ); } @@ -260,6 +267,7 @@ bool b = false; expect( details.lintRules, unorderedEquals([ + 'needs_package', 'no_doubles', 'no_doubles_custom_severity', 'no_references_to_strings', @@ -277,6 +285,27 @@ bool b = false; expect(assist.message, 'Invert Boolean value'); } + Future test_rulesHaveAccessToPackage() async { + writeAnalysisOptionsWithPlugin({'needs_package': 'enable'}); + newFile(filePath, 'var x = 1;'); + newFile(testFilePath, 'var x = 1;'); + await channel.sendRequest( + protocol.AnalysisSetContextRootsParams([contextRoot]), + ); + var paramsQueue = _analysisErrorsParams; + var params = await paramsQueue.next; + expect(params.file, filePath); + expect(params.errors, hasLength(1)); + _expectAnalysisError( + params.errors.single, + message: 'Needs Package at "$packagePath"', + ); + + params = await paramsQueue.next; + expect(params.file, testFilePath); + expect(params.errors, isEmpty); + } + Future test_unsupportedRequest() async { writeAnalysisOptionsWithPlugin(); newFile(filePath, 'bool b = false;'); @@ -626,6 +655,7 @@ class _NoLiteralsPlugin extends Plugin { @override void register(PluginRegistry registry) { + registry.registerLintRule(NeedsPackageRule()); registry.registerWarningRule(NoBoolsRule()); registry.registerLintRule(NoDoublesRule()); registry.registerLintRule(NoDoublesCustomSeverityRule());