Skip to content

Commit 606975e

Browse files
bogdanenedoghitoiuCommit Queue
authored andcommitted
[analysis_server] Add document links for plugins in analysis_options.yaml
Closes #62493 GitOrigin-RevId: 6fc5b1b Change-Id: I147c5b4843d1e3437b9212ce6e66ca7285229621 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/475422 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent 46a8211 commit 606975e

3 files changed

Lines changed: 91 additions & 3 deletions

File tree

pkg/analysis_server/lib/src/lsp/handlers/handler_document_link.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class DocumentLinkHandler
7777
return _convert(link, lineInfo);
7878
}
7979

80-
var visitor = AnalysisOptionLinkComputer();
80+
var visitor = AnalysisOptionLinkComputer(server.pubApi.pubHostedUrl);
8181
return success(
8282
visitor.findLinks(analysisOptionsContent).map(convert).toList(),
8383
);

pkg/analysis_server/test/lsp/document_link_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,60 @@ linter:
7979
await _test_pubspec_links(content, []);
8080
}
8181

82+
Future<void> test_analysisOptions_plugins_and_lints() async {
83+
var content = '''
84+
analyzer:
85+
plugins:
86+
- /*[0*/my_plugin/*0]*/
87+
88+
linter:
89+
rules:
90+
- /*[1*/await_only_futures/*1]*/
91+
''';
92+
93+
var expectedLinks = [
94+
'${_pubBase}my_plugin',
95+
'${_lintBase}await_only_futures',
96+
];
97+
98+
await _test_analysisOptions_links(content, expectedLinks);
99+
}
100+
101+
Future<void> test_analysisOptions_plugins_list() async {
102+
var content = '''
103+
analyzer:
104+
plugins:
105+
- /*[0*/dart_code_metrics/*0]*/
106+
- /*[1*/custom_lint/*1]*/
107+
''';
108+
109+
var expectedLinks = [
110+
'${_pubBase}dart_code_metrics',
111+
'${_pubBase}custom_lint',
112+
];
113+
114+
await _test_analysisOptions_links(content, expectedLinks);
115+
}
116+
117+
Future<void> test_analysisOptions_plugins_map() async {
118+
var content = '''
119+
analyzer:
120+
plugins:
121+
/*[0*/dart_code_metrics/*0]*/:
122+
enabled: true
123+
/*[1*/custom_lint/*1]*/:
124+
options:
125+
foo: bar
126+
''';
127+
128+
var expectedLinks = [
129+
'${_pubBase}dart_code_metrics',
130+
'${_pubBase}custom_lint',
131+
];
132+
133+
await _test_analysisOptions_links(content, expectedLinks);
134+
}
135+
82136
Future<void> test_analysisOptions_undefinedLint() async {
83137
var content = '''
84138
linter:

pkg/analyzer_plugin/lib/src/utilities/navigation/document_links.dart

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import 'package:yaml/yaml.dart';
1414
/// Computes [DocumentLink]s for lint names in an 'analysis_options.yaml'.
1515
class AnalysisOptionLinkComputer {
1616
static const _lintsUrl = 'https://dart.dev/tools/linter-rules/';
17+
final String pubHostedUrl;
1718

18-
AnalysisOptionLinkComputer();
19+
AnalysisOptionLinkComputer(this.pubHostedUrl);
1920

2021
List<DocumentLink> findLinks(String content) {
2122
YamlNode node;
@@ -30,7 +31,7 @@ class AnalysisOptionLinkComputer {
3031
var allRules = <YamlNode>[
3132
if (node.nodes['linter'] case YamlMap dependencies)
3233
...switch (dependencies.nodes['rules']) {
33-
YamlMap(:var nodes) => nodes.keys.map((node) => node as YamlNode),
34+
YamlMap(:var nodes) => nodes.keys.cast<YamlNode>(),
3435
YamlList rules => rules.nodes,
3536
_ => const <YamlNode>[],
3637
},
@@ -47,6 +48,28 @@ class AnalysisOptionLinkComputer {
4748
}
4849
}
4950

51+
var allPlugins = <YamlNode>[
52+
if (node.nodes['analyzer'] case YamlMap analyzer)
53+
if (analyzer.nodes['plugins'] case YamlNode plugins)
54+
...switch (plugins) {
55+
YamlMap(:var nodes) => nodes.keys.cast<YamlNode>(),
56+
YamlList plugins => plugins.nodes,
57+
_ => const <YamlNode>[],
58+
},
59+
];
60+
61+
for (final plugin in allPlugins) {
62+
var pluginLink = _computePluginLink(plugin);
63+
64+
if (pluginLink != null) {
65+
var offset = plugin.span.start.offset;
66+
var length = plugin.span.length;
67+
links.add(DocumentLink(offset, length, pluginLink));
68+
}
69+
}
70+
71+
links.sort((a, b) => a.offset.compareTo(b.offset));
72+
5073
return links;
5174
}
5275

@@ -65,6 +88,17 @@ class AnalysisOptionLinkComputer {
6588

6689
return Uri.tryParse(_lintsUrl + name);
6790
}
91+
92+
/// Computes a link for the plugin named [plugin].
93+
Uri? _computePluginLink(YamlNode plugin) {
94+
if (plugin is! YamlScalar) return null;
95+
var name = plugin.value;
96+
if (name is! String || name.isEmpty) return null;
97+
98+
var separator = pubHostedUrl.endsWith('/') ? '' : '/';
99+
100+
return Uri.parse('$pubHostedUrl${separator}packages/$name');
101+
}
68102
}
69103

70104
/// A visitor to locate links to other documents in a file.

0 commit comments

Comments
 (0)