Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OOP #1 - new analyzer engine that uses CompilerAnalyzer model #10509

Merged
merged 28 commits into from
Apr 14, 2016

Conversation

heejaechang
Copy link
Contributor

this is a rewrite of our analyzer engine (V2)

unlike the v1, we no longer tries to do incremental analysis per document (except active/open files) rather we follow compiler model where we do every work in one shot.

we realized implementing this incremental analysis on top of compiler model (which doesn't support this incremental analysis naturally) cost more than just doing everything at once.

this should let us to remove any need to maintain state in compilationWithAnalyzer to track in progress state.

also, this make implementation a bit less complicated than before.

@@ -117,22 +117,20 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Assert.Equal(workspaceDiagnosticAnalyzer.DiagDescriptor.Id, descriptors(0).Id)

' Add an existing workspace analyzer to the project, ensure no duplicate diagnostics.
Dim duplicateProjectAnalyzers = ImmutableArray.Create(Of DiagnosticAnalyzer)(workspaceDiagnosticAnalyzer)
Dim duplicateProjectAnalyzersReference = New AnalyzerImageReference(duplicateProjectAnalyzers)
Dim duplicateProjectAnalyzersReference = diagnosticService.HostAnalyzerReferences.FirstOrDefault()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

our dedup logic is based on reference not analyzer. not sure how it worked before. anyway, made the test to actually test what we dedup.


// REVIEW: more unnecessary allocations just to get diagnostics per analyzer
var oneAnalyzers = ImmutableArray.Create(analyzer);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need new API from compilerWithAnalyzer to not do this. once @mavasani provides me one, I will replace this with new API.

changed test to use GetDiagnosticsAsync rather than GetProjectDiagnosticsAsync

namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{
public class DiagnosticDataSerializerTests : TestBase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these new tests being added? Are they specific to v2 engine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep


foreach (var documentId in lastResult.DocumentIds)
{
var document = project.GetDocument(documentId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for cancellation in the loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

added assert for GetEffectiveDiagnostics
@@ -12,10 +11,14 @@ namespace Microsoft.CodeAnalysis.Diagnostics
/// </summary>
internal abstract class DocumentDiagnosticAnalyzer : DiagnosticAnalyzer
{
// REVIEW: why DocumentDiagnosticAnalyzer doesn't have span based analysis?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the point is to analyze the entire document :)

This is the extension point for other languages (like TS) to plugin and do their analysis of the document. How would we pick the spans with which ot analyze?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

span based analyzer means caller ask span to analyze not analyzer itself determine span to analyze. so if an analyzer has ability to return diagnostics based on given span, it can claim it is span based (or my wording might be wrong that confused you)

continue;
}

// REVIEW: is build diagnostic contains suppressed diagnostics?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build will never report suppressed diagnostics - at least it is not supported right now. If /errorlog is specified to build, the error log will have suppressed diagnostics, but command line output will not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm that means with build/live dedup logic, as soon as user build, user will lose all suppressed errors... I might need to save suppressed diagnostics when we do de-dup.

@CyrusNajmabadi
Copy link
Member

unlike the v1, we no longer tries to do incremental analysis per document (except active/open files) rather we follow compiler model where we do every work in one shot.

Will we at least be able to prioritize analysis? That way we get diagnostics for the files that the user is editing quickly? Thanks!

}
}

private bool ShouldIncludeSuppressedDiagnostic(DiagnosticData diagnostic)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to ShouldIncludeDiagnostic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that one already exist, so I added Suppressed :)

@heejaechang
Copy link
Contributor Author

@CyrusNajmabadi that is still the way it works. active file/open file will get highest priority and analyzed per file as before.

@heejaechang
Copy link
Contributor Author

@dotnet/roslyn-analysis @mattwar can you take a look?

return _diagnosticIds == null || _diagnosticIds.Contains(diagnostic.Id);
}

protected override async Task AppendDiagnosticsAsync(Project project, DocumentId targetDocumentId, IEnumerable<DocumentId> documentIds, CancellationToken cancellationToken)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API seems very weird - it takes project, targetDocument and then also an enumerable of documents. It doesn't seem clear for someone invoking this API what exact set of diagnostics will be appended and which arguments may or may not be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it to use flag instead.

@CyrusNajmabadi
Copy link
Member

@heejaechang Great!

One quesiton though. Say the user is in File A in Compilation A. So we're prioritizing that. Then they jump to File B in compilation B, we can jump to prioritizing that file right? We don't need to wait for Compilation A to finish?

var stateSets = _stateManager.GetOrUpdateStateSets(document.Project);
var analyzerDriverOpt = await _compilationManager.GetAnalyzerDriverAsync(document.Project, stateSets, cancellationToken).ConfigureAwait(false);

foreach (var stateSet in stateSets)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we bail out early for unsuppressed analyzers, just like you do in line 74 below for AnalyzeProjectAsync?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't do that to make sure stateSets is immutable. (since I cache CompilationWithAnalyzer based only on Project snapshot). can IsAnalyzerSuppressed be changed with same project snapshot?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's see whether not filtering those out will cause any perf issue. we can add it later with a bit of precaution later if it affects perf.

@heejaechang
Copy link
Contributor Author

@CyrusNajmabadi depends on how fast compilation A analysis respond to cancellation. when the situation you mentioned happen, we will raise cancellation and as soon as that get cancelled, we will process the active file that is switched. (assuming it has change otherwise, it should already have right diagnostics)

@CyrusNajmabadi
Copy link
Member

Ah, ok. As long as we don't have to unconditionally wait on Compilation A finishing, them i'm fine. I think Cancellation is a reasonable way to accomplish this.

@heejaechang
Copy link
Contributor Author

I am checking this in before branch switch. feature itself is off by default so it shouldn't affect anything. and I got ok from @mavasani offline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants