1
1
// ignore_for_file: public_member_api_docs
2
-
3
2
import 'dart:async' ;
4
3
5
- import 'package:analyzer/dart/analysis/context_locator.dart' ;
4
+ import 'package:analyzer/dart/analysis/analysis_context.dart' ;
5
+ import 'package:analyzer/dart/analysis/analysis_context_collection.dart' ;
6
6
import 'package:analyzer/dart/analysis/results.dart' ;
7
- import 'package:analyzer/file_system/physical_file_system.dart' ;
8
- // ignore: implementation_imports
9
- import 'package:analyzer/src/analysis_options/analysis_options_provider.dart' ;
10
- // ignore: implementation_imports
11
- import 'package:analyzer/src/dart/analysis/context_builder.dart' ;
12
- // ignore: implementation_imports
13
- import 'package:analyzer/src/dart/analysis/driver.dart' ;
14
7
import 'package:analyzer_plugin/plugin/plugin.dart' ;
15
8
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
16
9
@@ -20,18 +13,14 @@ import '../analyzers/lint_analyzer/metrics/metrics_list/number_of_parameters_met
20
13
import '../analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric.dart' ;
21
14
import '../config_builder/config_builder.dart' ;
22
15
import '../config_builder/models/analysis_options.dart' ;
23
- import '../utils/analyzer_utils.dart' ;
24
- import '../utils/yaml_utils.dart' ;
25
16
import 'analyzer_plugin_utils.dart' ;
26
17
27
- final _byteStore = createByteStore (PhysicalResourceProvider .INSTANCE );
28
-
29
18
class AnalyzerPlugin extends ServerPlugin {
30
19
static const _analyzer = LintAnalyzer ();
31
20
32
- final _configs = < AnalysisDriverGeneric , LintAnalysisConfig > {};
21
+ final _configs = < String , LintAnalysisConfig > {};
33
22
34
- var _filesFromSetPriorityFilesRequest = < String > [] ;
23
+ AnalysisContextCollection ? _contextCollection ;
35
24
36
25
@override
37
26
String get contactInfo =>
@@ -46,172 +35,101 @@ class AnalyzerPlugin extends ServerPlugin {
46
35
@override
47
36
String get version => '1.0.0-alpha.0' ;
48
37
49
- AnalyzerPlugin (super .resourceProvider);
50
-
51
- @override
52
- void contentChanged (String path) {
53
- super .driverForPath (path)? .addFile (path);
54
- }
55
-
56
- @override
57
- AnalysisDriverGeneric createAnalysisDriver (plugin.ContextRoot contextRoot) {
58
- final rootPath = contextRoot.root;
59
- final locator =
60
- ContextLocator (resourceProvider: resourceProvider).locateRoots (
61
- includedPaths: [rootPath],
62
- excludedPaths: contextRoot.exclude,
63
- optionsFile: contextRoot.optionsFile,
64
- );
65
-
66
- if (locator.isEmpty) {
67
- final error = StateError ('Unexpected empty context' );
68
- channel.sendNotification (plugin.PluginErrorParams (
69
- true ,
70
- error.message,
71
- error.stackTrace.toString (),
72
- ).toNotification ());
73
-
74
- throw error;
75
- }
76
-
77
- final builder = ContextBuilderImpl (resourceProvider: resourceProvider);
78
- final context = builder.createContext (
79
- contextRoot: locator.first,
80
- byteStore: _byteStore,
81
- );
82
- final dartDriver = context.driver;
83
- final config = _createConfig (dartDriver, rootPath);
84
-
85
- if (config == null ) {
86
- return dartDriver;
87
- }
88
-
89
- // Temporary disable deprecation check
90
- //
91
- // final deprecations = checkConfigDeprecatedOptions(
92
- // config,
93
- // deprecatedOptions,
94
- // contextRoot.optionsFile!,
95
- // );
96
- // if (deprecations.isNotEmpty) {
97
- // channel.sendNotification(plugin.AnalysisErrorsParams(
98
- // contextRoot.optionsFile!,
99
- // deprecations.map((deprecation) => deprecation.error).toList(),
100
- // ).toNotification());
101
- // }
102
-
103
- runZonedGuarded (
104
- () {
105
- dartDriver.results.listen ((analysisResult) {
106
- if (analysisResult is ResolvedUnitResult ) {
107
- _processResult (dartDriver, analysisResult);
108
- }
109
- });
110
- },
111
- (e, stackTrace) {
112
- channel.sendNotification (
113
- plugin.PluginErrorParams (false , e.toString (), stackTrace.toString ())
114
- .toNotification (),
115
- );
116
- },
117
- );
118
-
119
- return dartDriver;
120
- }
38
+ AnalyzerPlugin ({
39
+ required super .resourceProvider,
40
+ });
121
41
122
42
@override
123
- Future <plugin.AnalysisSetContextRootsResult > handleAnalysisSetContextRoots (
124
- plugin.AnalysisSetContextRootsParams parameters,
125
- ) async {
126
- final result = await super .handleAnalysisSetContextRoots (parameters);
127
- // The super-call adds files to the driver, so we need to prioritize them so they get analyzed.
128
- _updatePriorityFiles ();
43
+ Future <void > afterNewContextCollection ({
44
+ required AnalysisContextCollection contextCollection,
45
+ }) {
46
+ _contextCollection = contextCollection;
129
47
130
- return result;
131
- }
48
+ contextCollection.contexts.forEach (_createConfig);
132
49
133
- @override
134
- Future <plugin.AnalysisSetPriorityFilesResult > handleAnalysisSetPriorityFiles (
135
- plugin.AnalysisSetPriorityFilesParams parameters,
136
- ) async {
137
- _filesFromSetPriorityFilesRequest = parameters.files;
138
- _updatePriorityFiles ();
139
-
140
- return plugin.AnalysisSetPriorityFilesResult ();
50
+ return super
51
+ .afterNewContextCollection (contextCollection: contextCollection);
141
52
}
142
53
143
54
@override
144
- Future <plugin.EditGetFixesResult > handleEditGetFixes (
145
- plugin.EditGetFixesParams parameters,
146
- ) async {
55
+ Future <void > analyzeFile ({
56
+ required AnalysisContext analysisContext,
57
+ required String path,
58
+ }) async {
147
59
try {
148
- final driver = driverForPath (parameters.file) as AnalysisDriver ;
149
- // ignore: deprecated_member_use
150
- final analysisResult = await driver.getResult2 (parameters.file);
151
-
152
- if (analysisResult is ! ResolvedUnitResult ) {
153
- return plugin.EditGetFixesResult ([]);
154
- }
60
+ final resolvedUnit =
61
+ await analysisContext.currentSession.getResolvedUnit (path);
155
62
156
- final fixes = _check (driver, analysisResult).where ((fix) {
157
- final location = fix.error.location;
158
-
159
- return location.file == parameters.file &&
160
- location.offset <= parameters.offset &&
161
- parameters.offset <= location.offset + location.length &&
162
- fix.fixes.isNotEmpty;
163
- }).toList ();
63
+ if (resolvedUnit is ResolvedUnitResult ) {
64
+ final analysisErrors = _getErrorsForResolvedUnit (
65
+ resolvedUnit,
66
+ analysisContext.contextRoot.root.path,
67
+ );
164
68
165
- return plugin.EditGetFixesResult (fixes);
69
+ channel.sendNotification (
70
+ plugin.AnalysisErrorsParams (
71
+ path,
72
+ analysisErrors.map ((analysisError) => analysisError.error).toList (),
73
+ ).toNotification (),
74
+ );
75
+ } else {
76
+ channel.sendNotification (
77
+ plugin.AnalysisErrorsParams (path, []).toNotification (),
78
+ );
79
+ }
166
80
} on Exception catch (e, stackTrace) {
167
81
channel.sendNotification (
168
82
plugin.PluginErrorParams (false , e.toString (), stackTrace.toString ())
169
83
.toNotification (),
170
84
);
171
-
172
- return plugin.EditGetFixesResult ([]);
173
85
}
174
86
}
175
87
176
- void _processResult (
177
- AnalysisDriver driver,
178
- ResolvedUnitResult analysisResult ,
179
- ) {
88
+ @override
89
+ Future <plugin. EditGetFixesResult > handleEditGetFixes (
90
+ plugin. EditGetFixesParams parameters ,
91
+ ) async {
180
92
try {
181
- if (driver.analysisContext? .contextRoot.isAnalyzed (analysisResult.path) ??
182
- false ) {
183
- final fixes = _check (driver, analysisResult);
184
-
185
- channel.sendNotification (
186
- plugin.AnalysisErrorsParams (
187
- analysisResult.path,
188
- fixes.map ((fix) => fix.error).toList (),
189
- ).toNotification (),
190
- );
191
- } else {
192
- channel.sendNotification (
193
- plugin.AnalysisErrorsParams (analysisResult.path, []).toNotification (),
194
- );
93
+ final path = parameters.file;
94
+ final analysisContext = _contextCollection? .contextFor (path);
95
+ final resolvedUnit =
96
+ await analysisContext? .currentSession.getResolvedUnit (path);
97
+
98
+ if (analysisContext != null && resolvedUnit is ResolvedUnitResult ) {
99
+ final analysisErrors = _getErrorsForResolvedUnit (
100
+ resolvedUnit,
101
+ analysisContext.contextRoot.root.path,
102
+ ).where ((analysisError) {
103
+ final location = analysisError.error.location;
104
+
105
+ return location.file == parameters.file &&
106
+ location.offset <= parameters.offset &&
107
+ parameters.offset <= location.offset + location.length &&
108
+ analysisError.fixes.isNotEmpty;
109
+ }).toList ();
110
+
111
+ return plugin.EditGetFixesResult (analysisErrors);
195
112
}
196
113
} on Exception catch (e, stackTrace) {
197
114
channel.sendNotification (
198
115
plugin.PluginErrorParams (false , e.toString (), stackTrace.toString ())
199
116
.toNotification (),
200
117
);
201
118
}
119
+
120
+ return plugin.EditGetFixesResult ([]);
202
121
}
203
122
204
- Iterable <plugin.AnalysisErrorFixes > _check (
205
- AnalysisDriver driver,
123
+ Iterable <plugin.AnalysisErrorFixes > _getErrorsForResolvedUnit (
206
124
ResolvedUnitResult analysisResult,
125
+ String rootPath,
207
126
) {
208
127
final result = < plugin.AnalysisErrorFixes > [];
209
- final config = _configs[driver ];
128
+ final config = _configs[rootPath ];
210
129
211
130
if (config != null ) {
212
- final root = driver.analysisContext? .contextRoot.root.path;
213
-
214
- final report = _analyzer.runPluginAnalysis (analysisResult, config, root! );
131
+ final report =
132
+ _analyzer.runPluginAnalysis (analysisResult, config, rootPath);
215
133
216
134
if (report != null ) {
217
135
result.addAll ([
@@ -237,69 +155,26 @@ class AnalyzerPlugin extends ServerPlugin {
237
155
return result;
238
156
}
239
157
240
- LintAnalysisConfig ? _createConfig (AnalysisDriver driver, String rootPath) {
241
- final file = driver.analysisContext? .contextRoot.optionsFile;
158
+ void _createConfig (AnalysisContext analysisContext) {
159
+ final rootPath = analysisContext.contextRoot.root.path;
160
+ final file = analysisContext.contextRoot.optionsFile;
161
+
242
162
if (file != null && file.exists) {
243
- final options = AnalysisOptions (
244
- file.path,
245
- yamlMapToDartMap (
246
- AnalysisOptionsProvider (driver.sourceFactory)
247
- .getOptionsFromFile (file),
248
- ),
249
- );
250
- final config = ConfigBuilder .getLintConfigFromOptions (options);
163
+ final analysisOptions = analysisOptionsFromContext (analysisContext) ??
164
+ analysisOptionsFromFilePath (file.parent.path, analysisContext);
165
+ final config = ConfigBuilder .getLintConfigFromOptions (analysisOptions);
166
+
251
167
final lintConfig = ConfigBuilder .getLintAnalysisConfig (
252
168
config,
253
- options .folderPath ?? rootPath,
169
+ analysisOptions .folderPath ?? rootPath,
254
170
classMetrics: const [],
255
171
functionMetrics: [
256
172
NumberOfParametersMetric (config: config.metrics),
257
173
SourceLinesOfCodeMetric (config: config.metrics),
258
174
],
259
175
);
260
176
261
- _configs[driver] = lintConfig;
262
-
263
- return lintConfig;
264
- }
265
-
266
- return null ;
267
- }
268
-
269
- /// AnalysisDriver doesn't fully resolve files that are added via `addFile` ; they need to be either explicitly requested
270
- /// via `getResult` /etc, or added to `priorityFiles` .
271
- ///
272
- /// This method updates `priorityFiles` on the driver to include:
273
- ///
274
- /// - Any files prioritized by the analysis server via [handleAnalysisSetPriorityFiles]
275
- /// - All other files the driver has been told to analyze via addFile (in [ServerPlugin.handleAnalysisSetContextRoots] )
276
- ///
277
- /// As a result, [_processResult] will get called with resolved units, and thus all of our diagnostics
278
- /// will get run on all files in the repo instead of only the currently open/edited ones!
279
- void _updatePriorityFiles () {
280
- final filesToFullyResolve = {
281
- // Ensure these go first, since they're actually considered priority; ...
282
- ..._filesFromSetPriorityFilesRequest,
283
-
284
- // ... all other files need to be analyzed, but don't trump priority
285
- for (final driver2 in driverMap.values)
286
- ...(driver2 as AnalysisDriver ).addedFiles,
287
- };
288
-
289
- // From ServerPlugin.handleAnalysisSetPriorityFiles.
290
- final filesByDriver = < AnalysisDriverGeneric , List <String >> {};
291
- for (final file in filesToFullyResolve) {
292
- final contextRoot = contextRootContaining (file);
293
- if (contextRoot != null ) {
294
- // TODO(dkrutskikh): Which driver should we use if there is no context root?
295
- final driver = driverMap[contextRoot];
296
- if (driver != null ) {
297
- filesByDriver.putIfAbsent (driver, () => < String > []).add (file);
298
- }
299
- }
177
+ _configs[rootPath] = lintConfig;
300
178
}
301
- filesByDriver.forEach ((driver, files) {
302
- driver.priorityFiles = files;
303
- });
304
179
}
305
180
}
0 commit comments