-
Notifications
You must be signed in to change notification settings - Fork 4.2k
OOP #1 - new analyzer engine that uses CompilerAnalyzer model #10509
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
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
aa6d5fa
split things in multiple files.
heejaechang f8491ab
doing more basic arrangement for oop
heejaechang 2c86c83
fixed merge conflict from master
heejaechang 2e819f9
made solution to build after merge
heejaechang fec6319
fixed merge conflict
heejaechang c632be8
made solution to compile without v1 engine.
heejaechang 3cd50f0
made argsId to be shared between engine v1 and v2
heejaechang f161613
removed unused usings
heejaechang 82c9de9
full implementation of engine v2
heejaechang 1362e5b
added unit tests for diagnostic data serializer
heejaechang 6185f75
made all test pass
heejaechang 7e4d071
use compilation based concurrency (async) rather than driver based on…
heejaechang 11199c4
some clean up
heejaechang 27c20e4
fixed merge issue upstream/master
heejaechang eb3aa8d
fixed merge issue 2
heejaechang 96a13f4
PR feedback
heejaechang 96ace4c
GetEffectiveDiagnostics is not needed for CompilationWithAnalyzer API
heejaechang c18332f
added comment for AddExternalDiagnostics
heejaechang 2a436df
PR feedback.
heejaechang 060de6a
use semantic based IsCompilerAnalyzer rather than the hacky string ba…
heejaechang 7fb3292
CR feedback.
heejaechang 2920c15
CR feedback.
heejaechang 60e41b2
added comment based on PR.
heejaechang 5122239
added some comment
heejaechang 1410c34
make analyzer driver won't get into action execution when there is ac…
heejaechang ef26030
CR feedback.
heejaechang e8dde0d
Merge branch 'master' of https://github.com/dotnet/roslyn into oop2
heejaechang ba9daa6
restore +x
heejaechang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
291 changes: 291 additions & 0 deletions
291
src/EditorFeatures/Test/Diagnostics/DiagnosticDataSerializerTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,291 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using System.Composition; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.CodeAnalysis.CSharp; | ||
| using Microsoft.CodeAnalysis.Diagnostics; | ||
| using Microsoft.CodeAnalysis.Diagnostics.EngineV2; | ||
| using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; | ||
| using Microsoft.CodeAnalysis.Host; | ||
| using Microsoft.CodeAnalysis.Host.Mef; | ||
| using Microsoft.CodeAnalysis.Text; | ||
| using Roslyn.Test.Utilities; | ||
| using Roslyn.Utilities; | ||
| using Xunit; | ||
| using Traits = Microsoft.CodeAnalysis.Test.Utilities.Traits; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics | ||
| { | ||
| public class DiagnosticDataSerializerTests : TestBase | ||
| { | ||
| [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] | ||
| public async Task SerializationTest_Document() | ||
| { | ||
| using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic, workspaceKind: "DiagnosticDataSerializerTest")) | ||
| { | ||
| var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", ""); | ||
|
|
||
| var diagnostics = new[] | ||
| { | ||
| new DiagnosticData( | ||
| "test1", "Test", "test1 message", "test1 message format", | ||
| DiagnosticSeverity.Info, DiagnosticSeverity.Info, false, 1, | ||
| ImmutableArray<string>.Empty, ImmutableDictionary<string, string>.Empty, | ||
| workspace, document.Project.Id, new DiagnosticDataLocation(document.Id, | ||
| new TextSpan(10, 20), "originalFile1", 30, 30, 40, 40, "mappedFile1", 10, 10, 20, 20)), | ||
| new DiagnosticData( | ||
| "test2", "Test", "test2 message", "test2 message format", | ||
| DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 0, | ||
| ImmutableArray.Create<string>("Test2"), ImmutableDictionary<string, string>.Empty.Add("propertyKey", "propertyValue"), | ||
| workspace, document.Project.Id, new DiagnosticDataLocation(document.Id, | ||
| new TextSpan(30, 40), "originalFile2", 70, 70, 80, 80, "mappedFile2", 50, 50, 60, 60), title: "test2 title", description: "test2 description", helpLink: "http://test2link"), | ||
| new DiagnosticData( | ||
| "test3", "Test", "test3 message", "test3 message format", | ||
| DiagnosticSeverity.Error, DiagnosticSeverity.Warning, true, 2, | ||
| ImmutableArray.Create<string>("Test3", "Test3_2"), ImmutableDictionary<string, string>.Empty.Add("p1Key", "p1Value").Add("p2Key", "p2Value"), | ||
| workspace, document.Project.Id, new DiagnosticDataLocation(document.Id, | ||
| new TextSpan(50, 60), "originalFile3", 110, 110, 120, 120, "mappedFile3", 90, 90, 100, 100), title: "test3 title", description: "test3 description", helpLink: "http://test3link"), | ||
| }.ToImmutableArray(); | ||
|
|
||
| var utcTime = DateTime.UtcNow; | ||
| var analyzerVersion = VersionStamp.Create(utcTime); | ||
| var version = VersionStamp.Create(utcTime.AddDays(1)); | ||
|
|
||
| var key = "document"; | ||
| var serializer = new DiagnosticDataSerializer(analyzerVersion, version); | ||
|
|
||
| Assert.True(await serializer.SerializeAsync(document, key, diagnostics, CancellationToken.None).ConfigureAwait(false)); | ||
| var recovered = await serializer.DeserializeAsync(document, key, CancellationToken.None); | ||
|
|
||
| AssertDiagnostics(diagnostics, recovered); | ||
| } | ||
| } | ||
|
|
||
| [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] | ||
| public async Task SerializationTest_Project() | ||
| { | ||
| using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic, workspaceKind: "DiagnosticDataSerializerTest")) | ||
| { | ||
| var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", ""); | ||
|
|
||
| var diagnostics = new[] | ||
| { | ||
| new DiagnosticData( | ||
| "test1", "Test", "test1 message", "test1 message format", | ||
| DiagnosticSeverity.Info, DiagnosticSeverity.Info, false, 1, | ||
| ImmutableArray<string>.Empty, ImmutableDictionary<string, string>.Empty, | ||
| workspace, document.Project.Id, description: "test1 description", helpLink: "http://test1link"), | ||
| new DiagnosticData( | ||
| "test2", "Test", "test2 message", "test2 message format", | ||
| DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 0, | ||
| ImmutableArray.Create<string>("Test2"), ImmutableDictionary<string, string>.Empty.Add("p1Key", "p2Value"), | ||
| workspace, document.Project.Id), | ||
| new DiagnosticData( | ||
| "test3", "Test", "test3 message", "test3 message format", | ||
| DiagnosticSeverity.Error, DiagnosticSeverity.Warning, true, 2, | ||
| ImmutableArray.Create<string>("Test3", "Test3_2"), ImmutableDictionary<string, string>.Empty.Add("p2Key", "p2Value").Add("p1Key", "p1Value"), | ||
| workspace, document.Project.Id, description: "test3 description", helpLink: "http://test3link"), | ||
| }.ToImmutableArray(); | ||
|
|
||
| var utcTime = DateTime.UtcNow; | ||
| var analyzerVersion = VersionStamp.Create(utcTime); | ||
| var version = VersionStamp.Create(utcTime.AddDays(1)); | ||
|
|
||
| var key = "project"; | ||
| var serializer = new DiagnosticDataSerializer(analyzerVersion, version); | ||
|
|
||
| Assert.True(await serializer.SerializeAsync(document, key, diagnostics, CancellationToken.None).ConfigureAwait(false)); | ||
| var recovered = await serializer.DeserializeAsync(document, key, CancellationToken.None); | ||
|
|
||
| AssertDiagnostics(diagnostics, recovered); | ||
| } | ||
| } | ||
|
|
||
| [WorkItem(6104, "https://github.com/dotnet/roslyn/issues/6104")] | ||
| [Fact] | ||
| public void DiagnosticEquivalence() | ||
| { | ||
| #if DEBUG | ||
| var source = | ||
| @"class C | ||
| { | ||
| static int F(string s) { return 1; } | ||
| static int x = F(new { }); | ||
| static int y = F(new { A = 1 }); | ||
| }"; | ||
| var tree = SyntaxFactory.ParseSyntaxTree(source); | ||
| var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false); | ||
| var compilation = CSharpCompilation.Create(GetUniqueName(), new[] { tree }, new[] { MscorlibRef }, options); | ||
| var model = compilation.GetSemanticModel(tree); | ||
|
|
||
| // Each call to GetDiagnostics will bind field initializers | ||
| // (see https://github.com/dotnet/roslyn/issues/6264). | ||
| var diagnostics1 = model.GetDiagnostics().ToArray(); | ||
| var diagnostics2 = model.GetDiagnostics().ToArray(); | ||
|
|
||
| diagnostics1.Verify( | ||
| // (4,22): error CS1503: Argument 1: cannot convert from '<empty anonymous type>' to 'string' | ||
| // static int x = F(new { }); | ||
| Diagnostic(1503, "new { }").WithArguments("1", "<empty anonymous type>", "string").WithLocation(4, 22), | ||
| // (5,22): error CS1503: Argument 1: cannot convert from '<anonymous type: int A>' to 'string' | ||
| // static int y = F(new { A = 1 }); | ||
| Diagnostic(1503, "new { A = 1 }").WithArguments("1", "<anonymous type: int A>", "string").WithLocation(5, 22)); | ||
|
|
||
| Assert.NotSame(diagnostics1[0], diagnostics2[0]); | ||
| Assert.NotSame(diagnostics1[1], diagnostics2[1]); | ||
| Assert.Equal(diagnostics1, diagnostics2); | ||
| Assert.True(DiagnosticIncrementalAnalyzer.AreEquivalent(diagnostics1, diagnostics2)); | ||
|
|
||
| // Verify that not all collections are treated as equivalent. | ||
| diagnostics1 = new[] { diagnostics1[0] }; | ||
| diagnostics2 = new[] { diagnostics2[1] }; | ||
|
|
||
| Assert.NotEqual(diagnostics1, diagnostics2); | ||
| Assert.False(DiagnosticIncrementalAnalyzer.AreEquivalent(diagnostics1, diagnostics2)); | ||
| #endif | ||
| } | ||
|
|
||
| private static void AssertDiagnostics(ImmutableArray<DiagnosticData> items1, ImmutableArray<DiagnosticData> items2) | ||
| { | ||
| Assert.Equal(items1.Length, items2.Length); | ||
|
|
||
| for (var i = 0; i < items1.Length; i++) | ||
| { | ||
| AssertDiagnostics(items1[i], items2[i]); | ||
| } | ||
| } | ||
|
|
||
| private static void AssertDiagnostics(DiagnosticData item1, DiagnosticData item2) | ||
| { | ||
| Assert.Equal(item1.Id, item2.Id); | ||
| Assert.Equal(item1.Category, item2.Category); | ||
| Assert.Equal(item1.Message, item2.Message); | ||
| Assert.Equal(item1.ENUMessageForBingSearch, item2.ENUMessageForBingSearch); | ||
| Assert.Equal(item1.Severity, item2.Severity); | ||
| Assert.Equal(item1.IsEnabledByDefault, item2.IsEnabledByDefault); | ||
| Assert.Equal(item1.WarningLevel, item2.WarningLevel); | ||
| Assert.Equal(item1.DefaultSeverity, item2.DefaultSeverity); | ||
|
|
||
| Assert.Equal(item1.CustomTags.Count, item2.CustomTags.Count); | ||
| for (var j = 0; j < item1.CustomTags.Count; j++) | ||
| { | ||
| Assert.Equal(item1.CustomTags[j], item2.CustomTags[j]); | ||
| } | ||
|
|
||
| Assert.Equal(item1.Properties.Count, item2.Properties.Count); | ||
| Assert.True(item1.Properties.SetEquals(item2.Properties)); | ||
|
|
||
| Assert.Equal(item1.Workspace, item2.Workspace); | ||
| Assert.Equal(item1.ProjectId, item2.ProjectId); | ||
| Assert.Equal(item1.DocumentId, item2.DocumentId); | ||
|
|
||
| Assert.Equal(item1.HasTextSpan, item2.HasTextSpan); | ||
| if (item1.HasTextSpan) | ||
| { | ||
| Assert.Equal(item1.TextSpan, item2.TextSpan); | ||
| } | ||
|
|
||
| Assert.Equal(item1.DataLocation?.MappedFilePath, item2.DataLocation?.MappedFilePath); | ||
| Assert.Equal(item1.DataLocation?.MappedStartLine, item2.DataLocation?.MappedStartLine); | ||
| Assert.Equal(item1.DataLocation?.MappedStartColumn, item2.DataLocation?.MappedStartColumn); | ||
| Assert.Equal(item1.DataLocation?.MappedEndLine, item2.DataLocation?.MappedEndLine); | ||
| Assert.Equal(item1.DataLocation?.MappedEndColumn, item2.DataLocation?.MappedEndColumn); | ||
|
|
||
| Assert.Equal(item1.DataLocation?.OriginalFilePath, item2.DataLocation?.OriginalFilePath); | ||
| Assert.Equal(item1.DataLocation?.OriginalStartLine, item2.DataLocation?.OriginalStartLine); | ||
| Assert.Equal(item1.DataLocation?.OriginalStartColumn, item2.DataLocation?.OriginalStartColumn); | ||
| Assert.Equal(item1.DataLocation?.OriginalEndLine, item2.DataLocation?.OriginalEndLine); | ||
| Assert.Equal(item1.DataLocation?.OriginalEndColumn, item2.DataLocation?.OriginalEndColumn); | ||
|
|
||
| Assert.Equal(item1.Description, item2.Description); | ||
| Assert.Equal(item1.HelpLink, item2.HelpLink); | ||
| } | ||
|
|
||
| [ExportWorkspaceServiceFactory(typeof(IPersistentStorageService), "DiagnosticDataSerializerTest"), Shared] | ||
| public class PersistentStorageServiceFactory : IWorkspaceServiceFactory | ||
| { | ||
| public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) | ||
| { | ||
| return new Service(); | ||
| } | ||
|
|
||
| public class Service : IPersistentStorageService | ||
| { | ||
| private readonly Storage _instance = new Storage(); | ||
|
|
||
| IPersistentStorage IPersistentStorageService.GetStorage(Solution solution) | ||
| { | ||
| return _instance; | ||
| } | ||
|
|
||
| internal class Storage : IPersistentStorage | ||
| { | ||
| private readonly Dictionary<object, Stream> _map = new Dictionary<object, Stream>(); | ||
|
|
||
| public Task<Stream> ReadStreamAsync(string name, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| var stream = _map[name]; | ||
| stream.Position = 0; | ||
|
|
||
| return Task.FromResult(stream); | ||
| } | ||
|
|
||
| public Task<Stream> ReadStreamAsync(Project project, string name, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| var stream = _map[Tuple.Create(project, name)]; | ||
| stream.Position = 0; | ||
|
|
||
| return Task.FromResult(stream); | ||
| } | ||
|
|
||
| public Task<Stream> ReadStreamAsync(Document document, string name, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| var stream = _map[Tuple.Create(document, name)]; | ||
| stream.Position = 0; | ||
|
|
||
| return Task.FromResult(stream); | ||
| } | ||
|
|
||
| public Task<bool> WriteStreamAsync(string name, Stream stream, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| _map[name] = new MemoryStream(); | ||
| stream.CopyTo(_map[name]); | ||
|
|
||
| return SpecializedTasks.True; | ||
| } | ||
|
|
||
| public Task<bool> WriteStreamAsync(Project project, string name, Stream stream, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| _map[Tuple.Create(project, name)] = new MemoryStream(); | ||
| stream.CopyTo(_map[Tuple.Create(project, name)]); | ||
|
|
||
| return SpecializedTasks.True; | ||
| } | ||
|
|
||
| public Task<bool> WriteStreamAsync(Document document, string name, Stream stream, CancellationToken cancellationToken = default(CancellationToken)) | ||
| { | ||
| _map[Tuple.Create(document, name)] = new MemoryStream(); | ||
| stream.CopyTo(_map[Tuple.Create(document, name)]); | ||
|
|
||
| return SpecializedTasks.True; | ||
| } | ||
|
|
||
| protected virtual void Dispose(bool disposing) | ||
| { | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| Dispose(true); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep