@@ -56,6 +56,7 @@ protected enum State {
56
56
private readonly DocumentBuffer _buffer = new DocumentBuffer ( ) ;
57
57
private readonly CancellationTokenSource _allProcessingCts = new CancellationTokenSource ( ) ;
58
58
private IReadOnlyList < DiagnosticsEntry > _parseErrors = Array . Empty < DiagnosticsEntry > ( ) ;
59
+ private readonly IDiagnosticsService _diagnosticsService ;
59
60
60
61
private string _documentation ; // Must be null initially.
61
62
private TaskCompletionSource < IDocumentAnalysis > _analysisTcs ;
@@ -72,14 +73,15 @@ protected enum State {
72
73
protected State ContentState { get ; set ; } = State . None ;
73
74
74
75
protected PythonModule ( string name , ModuleType moduleType , IServiceContainer services ) {
75
- Check . ArgumentNotNull ( nameof ( name ) , name ) ;
76
- Name = name ;
77
- Services = services ;
76
+ Name = name ?? throw new ArgumentNullException ( nameof ( name ) ) ;
77
+ Services = services ?? throw new ArgumentNullException ( nameof ( services ) ) ;
78
78
ModuleType = moduleType ;
79
79
80
80
Log = services ? . GetService < ILogger > ( ) ;
81
81
Interpreter = services ? . GetService < IPythonInterpreter > ( ) ;
82
82
Analysis = new EmptyAnalysis ( services , this ) ;
83
+
84
+ _diagnosticsService = services . GetService < IDiagnosticsService > ( ) ;
83
85
}
84
86
85
87
protected PythonModule ( string moduleName , string filePath , ModuleType moduleType , IPythonModule stub , IServiceContainer services ) :
@@ -218,13 +220,13 @@ protected virtual string LoadContent() {
218
220
private void InitializeContent ( string content ) {
219
221
lock ( AnalysisLock ) {
220
222
LoadContent ( content ) ;
223
+
221
224
var startParse = ContentState < State . Parsing && _parsingTask == null ;
222
225
var startAnalysis = startParse | ( ContentState < State . Analyzing && _analysisTcs ? . Task == null ) ;
223
226
224
227
if ( startAnalysis ) {
225
- _analysisTcs = new TaskCompletionSource < IDocumentAnalysis > ( ) ;
228
+ ExpectNewAnalysis ( ) ;
226
229
}
227
-
228
230
if ( startParse ) {
229
231
Parse ( ) ;
230
232
}
@@ -250,6 +252,7 @@ private void LoadContent(string content) {
250
252
public void Dispose ( ) => Dispose ( true ) ;
251
253
252
254
protected virtual void Dispose ( bool disposing ) {
255
+ _diagnosticsService ? . Remove ( Uri ) ;
253
256
_allProcessingCts . Cancel ( ) ;
254
257
_allProcessingCts . Dispose ( ) ;
255
258
}
@@ -288,7 +291,7 @@ public async Task<PythonAst> GetAstAsync(CancellationToken cancellationToken = d
288
291
Task t = null ;
289
292
while ( true ) {
290
293
lock ( AnalysisLock ) {
291
- if ( t == _parsingTask ) {
294
+ if ( t == _parsingTask ) {
292
295
break ;
293
296
}
294
297
cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -314,10 +317,8 @@ public async Task<PythonAst> GetAstAsync(CancellationToken cancellationToken = d
314
317
315
318
public void Update ( IEnumerable < DocumentChange > changes ) {
316
319
lock ( AnalysisLock ) {
317
- ExpectedAnalysisVersion ++ ;
318
-
320
+ ExpectNewAnalysis ( ) ;
319
321
_linkedAnalysisCts ? . Cancel ( ) ;
320
- _analysisTcs = new TaskCompletionSource < IDocumentAnalysis > ( ) ;
321
322
322
323
_parseCts ? . Cancel ( ) ;
323
324
_parseCts = new CancellationTokenSource ( ) ;
@@ -352,18 +353,22 @@ private void Parse() {
352
353
}
353
354
354
355
private void Parse ( CancellationToken cancellationToken ) {
355
- var sink = new CollectingErrorSink ( ) ;
356
+ CollectingErrorSink sink = null ;
356
357
int version ;
357
358
Parser parser ;
358
359
359
360
//Log?.Log(TraceEventType.Verbose, $"Parse begins: {Name}");
360
361
361
362
lock ( AnalysisLock ) {
362
363
version = _buffer . Version ;
363
- parser = Parser . CreateParser ( new StringReader ( _buffer . Text ) , Interpreter . LanguageVersion , new ParserOptions {
364
- StubFile = FilePath != null && Path . GetExtension ( FilePath ) . Equals ( ".pyi" , FileSystem . StringComparison ) ,
365
- ErrorSink = sink
366
- } ) ;
364
+ var options = new ParserOptions {
365
+ StubFile = FilePath != null && Path . GetExtension ( FilePath ) . Equals ( ".pyi" , FileSystem . StringComparison )
366
+ } ;
367
+ if ( ModuleType == ModuleType . User ) {
368
+ sink = new CollectingErrorSink ( ) ;
369
+ options . ErrorSink = sink ;
370
+ }
371
+ parser = Parser . CreateParser ( new StringReader ( _buffer . Text ) , Interpreter . LanguageVersion , options ) ;
367
372
}
368
373
369
374
var ast = parser . ParseFile ( ) ;
@@ -376,7 +381,13 @@ private void Parse(CancellationToken cancellationToken) {
376
381
throw new OperationCanceledException ( ) ;
377
382
}
378
383
_ast = ast ;
379
- _parseErrors = sink . Diagnostics ;
384
+ _parseErrors = sink ? . Diagnostics ?? Array . Empty < DiagnosticsEntry > ( ) ;
385
+
386
+ // Do not report issues with libraries or stubs
387
+ if ( sink != null ) {
388
+ _diagnosticsService ? . Replace ( Uri , _parseErrors ) ;
389
+ }
390
+
380
391
_parsingTask = null ;
381
392
ContentState = State . Parsed ;
382
393
}
@@ -428,11 +439,10 @@ public override void Add(string message, SourceSpan span, int errorCode, Severit
428
439
public void NotifyAnalysisPending ( ) {
429
440
lock ( AnalysisLock ) {
430
441
// The notification comes from the analyzer when it needs to invalidate
431
- // current analysis since one of the dependencies changed. Upon text
432
- // buffer change the version may be incremented twice - once in Update()
433
- // and then here. This is normal.
434
- ExpectedAnalysisVersion ++ ;
435
- _analysisTcs = _analysisTcs ?? new TaskCompletionSource < IDocumentAnalysis > ( ) ;
442
+ // current analysis since one of the dependencies changed. If text
443
+ // buffer changed then the notification won't come since the analyzer
444
+ // filters out original initiator of the analysis.
445
+ ExpectNewAnalysis ( ) ;
436
446
//Log?.Log(TraceEventType.Verbose, $"Analysis pending: {Name}");
437
447
}
438
448
}
@@ -448,10 +458,11 @@ public virtual bool NotifyAnalysisComplete(IDocumentAnalysis analysis) {
448
458
// to perform additional actions on the completed analysis such
449
459
// as declare additional variables, etc.
450
460
OnAnalysisComplete ( ) ;
461
+ ContentState = State . Analyzed ;
451
462
452
- _analysisTcs . TrySetResult ( analysis ) ;
463
+ var tcs = _analysisTcs ;
453
464
_analysisTcs = null ;
454
- ContentState = State . Analyzed ;
465
+ tcs . TrySetResult ( analysis ) ;
455
466
456
467
NewAnalysis ? . Invoke ( this , EventArgs . Empty ) ;
457
468
return true ;
@@ -477,6 +488,11 @@ public Task<IDocumentAnalysis> GetAnalysisAsync(CancellationToken cancellationTo
477
488
}
478
489
#endregion
479
490
491
+ private void ExpectNewAnalysis ( ) {
492
+ ExpectedAnalysisVersion ++ ;
493
+ _analysisTcs = _analysisTcs ?? new TaskCompletionSource < IDocumentAnalysis > ( ) ;
494
+ }
495
+
480
496
private string TryGetDocFromModuleInitFile ( ) {
481
497
if ( string . IsNullOrEmpty ( FilePath ) || ! FileSystem . FileExists ( FilePath ) ) {
482
498
return string . Empty ;
0 commit comments