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>
diff --git a/pkg/analysis_server_plugin/lib/src/plugin_server.dart b/pkg/analysis_server_plugin/lib/src/plugin_server.dart
index 79bc6b6..dec9ce1 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 @@
     // 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 4cb042e..e931299 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/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 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 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 _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;
 
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 ba6a902..5300e33 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 @@
 
   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 @@
       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 @@
     expect(
       details.lintRules,
       unorderedEquals([
+        'needs_package',
         'no_doubles',
         'no_doubles_custom_severity',
         'no_references_to_strings',
@@ -277,6 +285,27 @@
     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 @@
 
   @override
   void register(PluginRegistry registry) {
+    registry.registerLintRule(NeedsPackageRule());
     registry.registerWarningRule(NoBoolsRule());
     registry.registerLintRule(NoDoublesRule());
     registry.registerLintRule(NoDoublesCustomSeverityRule());