Skip to content

Commit 401c8bf

Browse files
srawlinsCommit Queue
authored andcommitted
DAS plugins: Fix the path at which part diagnostics are reported
I had not run the first fix through manual testing. Manual testing revealed a second location (!!) where the file path is stored, for diagnostics. This updates the code to send a notification for each file path, including parts. Change-Id: Iee60330c579563f31c8d9a2c65a22c9cde4b64d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448881 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent caece5d commit 401c8bf

File tree

3 files changed

+66
-31
lines changed

3 files changed

+66
-31
lines changed

pkg/analysis_server_plugin/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Require Dart SDK `^3.9.0`.
55
- Add support for automatic re-analysis of files changed on-disk (as opposed to
66
file contents changed in the IDE, which is already supported).
7+
- Add support for analyzing and reporting diagnostics in part files.
78
- Breaking change: a `Plugin` class must now implement `String get name`.
89

910
## 0.2.2

pkg/analysis_server_plugin/lib/src/plugin_server.dart

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,16 @@ import 'package:analyzer_plugin/protocol/protocol_constants.dart' as protocol;
4444
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as protocol;
4545
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
4646

47-
typedef _ErrorAndProtocolError = ({
47+
/// A pair, matching a [Diagnostic] with it's equivalent
48+
/// [protocol.AnalysisError].
49+
typedef _DiagnosticAndAnalysisError = ({
4850
Diagnostic diagnostic,
49-
protocol.AnalysisError protocolError,
51+
protocol.AnalysisError analysisError,
5052
});
5153

5254
typedef _PluginState = ({
5355
AnalysisContext analysisContext,
54-
List<_ErrorAndProtocolError> errors,
56+
List<_DiagnosticAndAnalysisError> errors,
5557
});
5658

5759
/// The server that communicates with the analysis server, passing requests and
@@ -201,7 +203,7 @@ class PluginServer {
201203
var errorFixesList = <protocol.AnalysisErrorFixes>[];
202204

203205
var workspace = DartChangeWorkspace([analysisContext.currentSession]);
204-
for (var (:diagnostic, :protocolError) in lintAtOffset) {
206+
for (var (:diagnostic, :analysisError) in lintAtOffset) {
205207
var context = DartFixContext(
206208
// TODO(srawlins): Use a real instrumentation service. Other
207209
// implementations get InstrumentationService from AnalysisServer.
@@ -223,7 +225,7 @@ class PluginServer {
223225

224226
if (fixes.isNotEmpty) {
225227
fixes.sort(Fix.compareFixes);
226-
var errorFixes = protocol.AnalysisErrorFixes(protocolError);
228+
var errorFixes = protocol.AnalysisErrorFixes(analysisError);
227229
errorFixesList.add(errorFixes);
228230
for (var fix in fixes) {
229231
errorFixes.fixes.add(protocol.PrioritizedSourceChange(1, fix.change));
@@ -282,7 +284,7 @@ class PluginServer {
282284
.where((p) => file_paths.isDart(_resourceProvider.pathContext, p))
283285
.toSet();
284286

285-
await _analyzeFiles(analysisContext: analysisContext, paths: paths);
287+
await _analyzeLibraries(analysisContext: analysisContext, paths: paths);
286288
});
287289
_channel.sendNotification(
288290
protocol.PluginStatusParams(
@@ -291,52 +293,65 @@ class PluginServer {
291293
);
292294
}
293295

294-
Future<void> _analyzeFile({
296+
/// Analyzes the library at the given [libraryPath], sending an
297+
/// 'analysis.errors' [Notification] for each compilation unit.
298+
Future<void> _analyzeLibrary({
295299
required AnalysisContext analysisContext,
296-
required String path,
300+
required String libraryPath,
297301
}) async {
298-
var file = _resourceProvider.getFile(path);
302+
var file = _resourceProvider.getFile(libraryPath);
299303
var analysisOptions = analysisContext.getAnalysisOptionsForFile(file);
300-
var diagnostics = await _computeDiagnostics(
304+
var analysisErrorsByPath = await _computeAnalysisErrors(
301305
analysisContext,
302-
path,
306+
libraryPath,
303307
analysisOptions: analysisOptions as AnalysisOptionsImpl,
304308
);
305-
_channel.sendNotification(
306-
protocol.AnalysisErrorsParams(path, diagnostics).toNotification(),
307-
);
309+
for (var MapEntry(key: path, value: analysisErrors)
310+
in analysisErrorsByPath.entries) {
311+
_channel.sendNotification(
312+
protocol.AnalysisErrorsParams(path, analysisErrors).toNotification(),
313+
);
314+
}
308315
}
309316

310-
/// Analyzes the files at the given [paths].
311-
Future<void> _analyzeFiles({
317+
/// Analyzes the libraries at the given [paths].
318+
Future<void> _analyzeLibraries({
312319
required AnalysisContext analysisContext,
313320
required Set<String> paths,
314321
}) async {
315322
// First analyze priority files.
316323
for (var path in _priorityPaths) {
317324
if (paths.remove(path)) {
318-
await _analyzeFile(analysisContext: analysisContext, path: path);
325+
await _analyzeLibrary(
326+
analysisContext: analysisContext,
327+
libraryPath: path,
328+
);
319329
}
320330
}
321331

322332
// Then analyze the remaining files.
323333
for (var path in paths) {
324-
await _analyzeFile(analysisContext: analysisContext, path: path);
334+
await _analyzeLibrary(
335+
analysisContext: analysisContext,
336+
libraryPath: path,
337+
);
325338
}
326339
}
327340

328-
Future<List<protocol.AnalysisError>> _computeDiagnostics(
341+
/// Computes and returns [protocol.AnalysisError]s for each of the parts in
342+
/// the library at [libraryPath].
343+
Future<Map<String, List<protocol.AnalysisError>>> _computeAnalysisErrors(
329344
AnalysisContext analysisContext,
330-
String path, {
345+
String libraryPath, {
331346
required AnalysisOptionsImpl analysisOptions,
332347
}) async {
333348
var libraryResult = await analysisContext.currentSession.getResolvedLibrary(
334-
path,
349+
libraryPath,
335350
);
336351
if (libraryResult is! ResolvedLibraryResult) {
337352
// We only handle analyzing at the library-level. Below, we work through
338353
// each of the compilation units found in `libraryResult`.
339-
return const [];
354+
return const {};
340355
}
341356

342357
var diagnosticListeners = {
@@ -426,8 +441,8 @@ class PluginServer {
426441

427442
// The list of the `AnalysisError`s and their associated
428443
// `protocol.AnalysisError`s.
429-
var diagnosticsAndProtocolErrors =
430-
<({Diagnostic diagnostic, protocol.AnalysisError protocolError})>[];
444+
var diagnosticsAndAnalysisErrors =
445+
<({Diagnostic diagnostic, protocol.AnalysisError analysisError})>[];
431446

432447
diagnosticListeners.forEach((unitResult, listener) {
433448
var ignoreInfo = IgnoreInfo.forDart(unitResult.unit, unitResult.content);
@@ -442,9 +457,9 @@ class PluginServer {
442457
});
443458

444459
for (var diagnostic in diagnostics) {
445-
diagnosticsAndProtocolErrors.add((
460+
diagnosticsAndAnalysisErrors.add((
446461
diagnostic: diagnostic,
447-
protocolError: protocol.AnalysisError(
462+
analysisError: protocol.AnalysisError(
448463
severityMapping[diagnostic.diagnosticCode] ??
449464
protocol.AnalysisErrorSeverity.INFO,
450465
protocol.AnalysisErrorType.STATIC_WARNING,
@@ -459,11 +474,22 @@ class PluginServer {
459474
}
460475
});
461476

462-
_recentState[path] = (
477+
_recentState[libraryPath] = (
463478
analysisContext: analysisContext,
464-
errors: [...diagnosticsAndProtocolErrors],
479+
errors: [...diagnosticsAndAnalysisErrors],
465480
);
466-
return diagnosticsAndProtocolErrors.map((e) => e.protocolError).toList();
481+
482+
// A map that has a key for each unit's path. It is important to collect the
483+
// analysis errors for each unit, even if it has none. We must send a
484+
// notification for each unit, even if there are no analysis errors to
485+
// report.
486+
var analysisErrorsByPath = <String, List<protocol.AnalysisError>>{
487+
for (var unitResult in libraryResult.units) unitResult.path: [],
488+
};
489+
for (var (diagnostic: _, :analysisError) in diagnosticsAndAnalysisErrors) {
490+
analysisErrorsByPath[analysisError.location.file]!.add(analysisError);
491+
}
492+
return analysisErrorsByPath;
467493
}
468494

469495
/// Converts the severity of [code] into a [protocol.AnalysisErrorSeverity].
@@ -601,7 +627,7 @@ class PluginServer {
601627
/// one or more files. The implementation may check if these files should
602628
/// be analyzed, do such analysis, and send diagnostics.
603629
///
604-
/// By default invokes [_analyzeFiles] only for files that are analyzed in
630+
/// By default invokes [_analyzeLibraries] only for files that are analyzed in
605631
/// this [analysisContext].
606632
Future<void> _handleAffectedFiles({
607633
required AnalysisContext analysisContext,
@@ -611,7 +637,10 @@ class PluginServer {
611637
.where(analysisContext.contextRoot.isAnalyzed)
612638
.toSet();
613639

614-
await _analyzeFiles(analysisContext: analysisContext, paths: analyzedPaths);
640+
await _analyzeLibraries(
641+
analysisContext: analysisContext,
642+
paths: analyzedPaths,
643+
);
615644
}
616645

617646
/// Handles an 'analysis.setContextRoots' request.

pkg/analysis_server_plugin/test/src/plugin_server_test.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,13 @@ String s = "hello";
351351
}),
352352
);
353353

354+
params = await paramsQueue.next;
355+
expect(params.errors, isEmpty);
356+
expect(params.file, filePath);
357+
354358
params = await paramsQueue.next;
355359
expect(params.errors, hasLength(1));
360+
expect(params.file, file2Path);
356361
_expectAnalysisError(
357362
params.errors.single,
358363
message: 'No references to Strings',

0 commit comments

Comments
 (0)