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 <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Sam Rawlins
2025-09-15 16:07:55 -07:00
committed by Commit Queue
parent 0a47e565b0
commit 03d0629a69
3 changed files with 87 additions and 18 deletions
@@ -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.
@@ -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<void> {
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<void> {
final AnalysisRule rule;
@@ -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<protocol.AnalysisErrorsParams> 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<void> 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<void> 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());