Skip to content

Commit

Permalink
Merge pull request dotnet#10509 from heejaechang/oop2
Browse files Browse the repository at this point in the history
OOP #1 - new analyzer engine that uses CompilerAnalyzer model
  • Loading branch information
heejaechang committed Apr 14, 2016
2 parents b8fbe78 + ba9daa6 commit b06e88d
Show file tree
Hide file tree
Showing 45 changed files with 6,246 additions and 503 deletions.
24 changes: 24 additions & 0 deletions src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,11 @@ private void ExecuteDeclaringReferenceActions(
ImmutableDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind;
if (this.NodeActionsByAnalyzerAndKind.TryGetValue(analyzer, out nodeActionsByKind))
{
if (nodeActionsByKind.IsEmpty)
{
continue;
}

analyzerExecutor.ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind,
analyzer, semanticModel, _getKind, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan,
decl, declarationIndex, symbol, analysisScope, analysisStateOpt, isInGeneratedCode);
Expand Down Expand Up @@ -1610,6 +1615,11 @@ private void ExecuteDeclaringReferenceActions(
ImmutableDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind;
if (this.OperationActionsByAnalyzerAndKind.TryGetValue(analyzer, out operationActionsByKind))
{
if (operationActionsByKind.IsEmpty)
{
continue;
}

analyzerExecutor.ExecuteOperationActions(operationsToAnalyze, operationActionsByKind,
analyzer, semanticModel, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan,
decl, declarationIndex, symbol, analysisScope, analysisStateOpt, isInGeneratedCode);
Expand All @@ -1621,6 +1631,13 @@ private void ExecuteDeclaringReferenceActions(
{
foreach (var analyzerActions in codeBlockActions)
{
if (analyzerActions.OperationBlockStartActions.IsEmpty &&
analyzerActions.OperationBlockActions.IsEmpty &&
analyzerActions.OpererationBlockEndActions.IsEmpty)
{
continue;
}

analyzerExecutor.ExecuteOperationBlockActions(
analyzerActions.OperationBlockStartActions, analyzerActions.OperationBlockActions,
analyzerActions.OpererationBlockEndActions, analyzerActions.Analyzer, declarationAnalysisData.TopmostNodeForAnalysis, symbol,
Expand All @@ -1639,6 +1656,13 @@ private void ExecuteDeclaringReferenceActions(
{
foreach (var analyzerActions in codeBlockActions)
{
if (analyzerActions.CodeBlockStartActions.IsEmpty &&
analyzerActions.CodeBlockActions.IsEmpty &&
analyzerActions.CodeBlockEndActions.IsEmpty)
{
continue;
}

analyzerExecutor.ExecuteCodeBlockActions(
analyzerActions.CodeBlockStartActions, analyzerActions.CodeBlockActions,
analyzerActions.CodeBlockEndActions, analyzerActions.Analyzer, declarationAnalysisData.TopmostNodeForAnalysis, symbol,
Expand Down
291 changes: 291 additions & 0 deletions src/EditorFeatures/Test/Diagnostics/DiagnosticDataSerializerTests.cs
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);
}
}
}
}
}
}
Loading

0 comments on commit b06e88d

Please sign in to comment.