diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs index ecc821bb676709be9ef5cac405563c6a0cc4c1f1..7b685137224d99b2ea1ed7a79e4c678e70480eed 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -1133,5 +1133,75 @@ class D Diagnostic(CSharpCodeBlockObjectCreationAnalyzer.DiagnosticDescriptor.Id, "new C()").WithLocation(5, 18) }); } + + private static Compilation GetCompilationWithConcurrentBuildEnabled(string source) + { + var compilation = CreateCompilationWithMscorlib45(source); + + // NOTE: We set the concurrentBuild option to true after creating the compilation as CreateCompilationWithMscorlib + // always sets concurrentBuild to false if debugger is attached, even if we had passed options with concurrentBuild = true to that API. + // We want the tests using GetCompilationWithConcurrentBuildEnabled to have identical behavior with and without debugger being attached. + var options = compilation.Options.WithConcurrentBuild(true); + return compilation.WithOptions(options); + } + + [Fact, WorkItem(6737, "https://github.com/dotnet/roslyn/issues/6737")] + public void TestNonConcurrentAnalyzer() + { + var source = string.Empty; + var typeCount = 100; + for (int i = 1; i <= typeCount; i++) + { + var typeName = $"C{i}"; + source = source + $"\r\nclass {typeName} {{ }}"; + } + + var analyzers = new DiagnosticAnalyzer[] { new NonConcurrentAnalyzer() }; + + // Verify no diagnostics. + var compilation = GetCompilationWithConcurrentBuildEnabled(source); + compilation.VerifyDiagnostics(); + compilation.VerifyAnalyzerDiagnostics(analyzers); + } + + [Fact, WorkItem(6737, "https://github.com/dotnet/roslyn/issues/6737")] + public void TestConcurrentAnalyzer() + { + if (Environment.ProcessorCount <= 1) + { + // Don't test for non-concurrent environment. + return; + } + + var source = string.Empty; + var typeCount = 100; + var typeNames = new string[typeCount]; + for (int i = 1; i <= typeCount; i++) + { + var typeName = $"C{i}"; + typeNames[i - 1] = typeName; + source = source + $"\r\nclass {typeName} {{ }}"; + } + + var compilation = GetCompilationWithConcurrentBuildEnabled(source); + compilation.VerifyDiagnostics(); + + // Verify analyzer diagnostics for Concurrent analyzer only. + var analyzers = new DiagnosticAnalyzer[] { new ConcurrentAnalyzer(typeNames) }; + var expected = new DiagnosticDescription[typeCount]; + for (int i = 0; i < typeCount; i++) + { + var typeName = $"C{i + 1}"; + expected[i] = Diagnostic(ConcurrentAnalyzer.Descriptor.Id, typeName) + .WithArguments(typeName) + .WithLocation(i + 2, 7); + } + + compilation.VerifyAnalyzerDiagnostics(analyzers, expected: expected); + + // Verify analyzer diagnostics for Concurrent and NonConcurrent analyzer together (latter reports diagnostics only for error cases). + analyzers = new DiagnosticAnalyzer[] { new ConcurrentAnalyzer(typeNames), new NonConcurrentAnalyzer() }; + compilation.VerifyAnalyzerDiagnostics(analyzers, expected: expected); + } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index db793c9033d95722db7ca31b0cfc2014dfca774e..52270a3fd3f04e9a42e58bd8886e19d02b21f0f8 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -38,6 +38,11 @@ internal abstract partial class AnalyzerDriver : IDisposable private ImmutableDictionary> _compilationActionsMap; private ImmutableDictionary> _compilationEndActionsMap; + /// + /// Map from non-concurrent analyzers to the gate guarding callback into the analyzer. + /// + private ImmutableDictionary _analyzerGateMap = ImmutableDictionary.Empty; + /// /// Driver task which initializes all analyzers. /// This task is initialized and executed only once at start of analysis. @@ -98,7 +103,8 @@ private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagn var analyzerActionsTask = GetAnalyzerActionsAsync(analyzers, analyzerManager, analyzerExecutor); _initializeTask = analyzerActionsTask.ContinueWith(t => { - this.analyzerActions = t.Result; + this.analyzerActions = t.Result.Item1; + this._analyzerGateMap = t.Result.Item2; _symbolActionsByKind = MakeSymbolActionsByKind(); _semanticModelActionsMap = MakeSemanticModelActionsByAnalyzer(); _syntaxTreeActionsMap = MakeSyntaxTreeActionsByAnalyzer(); @@ -158,9 +164,6 @@ private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagn newOnAnalyzerException = (ex, analyzer, diagnostic) => addDiagnostic(diagnostic); } - // Assume all analyzers are non-thread safe. - var singleThreadedAnalyzerToGateMap = ImmutableDictionary.CreateRange(analyzers.Select(a => KeyValuePair.Create(a, new SemaphoreSlim(initialCount: 1)))); - if (analysisOptions.LogAnalyzerExecutionTime) { // If we are reporting detailed analyzer performance numbers, then do a dummy invocation of Compilation.GetTypeByMetadataName API upfront. @@ -168,13 +171,26 @@ private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagn var unused = compilation.GetTypeByMetadataName("System.Object"); } - Func getAnalyzerGate = analyzer => singleThreadedAnalyzerToGateMap[analyzer]; var analyzerExecutor = AnalyzerExecutor.Create(compilation, analysisOptions.Options ?? AnalyzerOptions.Empty, addDiagnostic, newOnAnalyzerException, IsCompilerAnalyzer, - analyzerManager, getAnalyzerGate, analysisOptions.LogAnalyzerExecutionTime, addLocalDiagnosticOpt, addNonLocalDiagnosticOpt, cancellationToken); + analyzerManager, GetAnalyzerGate, analysisOptions.LogAnalyzerExecutionTime, addLocalDiagnosticOpt, addNonLocalDiagnosticOpt, cancellationToken); Initialize(analyzerExecutor, diagnosticQueue, cancellationToken); } + private SemaphoreSlim GetAnalyzerGate(DiagnosticAnalyzer analyzer) + { + SemaphoreSlim gate; + if (_analyzerGateMap.TryGetValue(analyzer, out gate)) + { + // Non-concurrent analyzer, needs all the callbacks guarded by a gate. + Debug.Assert(gate != null); + return gate; + } + + // Concurrent analyzer. + return null; + } + /// /// Attaches a pre-populated event queue to the driver and processes all events in the queue. /// @@ -396,7 +412,7 @@ public async Task> GetDiagnosticsAsync(Compilation co if (reportSuppressedDiagnostics || !d.IsSuppressed) { allDiagnostics.Add(d); - } + } } return allDiagnostics.ToReadOnlyAndFree(); @@ -530,7 +546,7 @@ private async Task ProcessCompilationEventsAsync(AnalysisScope analysisScope, An var workerTasks = new Task[workerCount]; for (int i = 0; i < workerCount; i++) { - workerTasks[i] = ProcessCompilationEventsCoreAsync(analysisScope, analysisStateOpt, prePopulatedEventQueue, cancellationToken); + workerTasks[i] = Task.Run(async() => await ProcessCompilationEventsCoreAsync(analysisScope, analysisStateOpt, prePopulatedEventQueue, cancellationToken).ConfigureAwait(false)); } cancellationToken.ThrowIfCancellationRequested(); @@ -635,7 +651,7 @@ private async Task ProcessEventAsync(CompilationEvent e, AnalysisScope analysisS if (analysisStateOpt != null) { await analysisStateOpt.OnCompilationEventProcessedAsync(e, analysisScope, cancellationToken).ConfigureAwait(false); - } + } } private async Task ProcessEventCoreAsync(CompilationEvent e, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) @@ -845,35 +861,66 @@ private static Diagnostic GetFilteredDiagnostic(Diagnostic diagnostic, Compilati return compilation.Options.FilterDiagnostic(diagnostic); } - private static Task GetAnalyzerActionsAsync( + private static Task>> GetAnalyzerActionsAsync( ImmutableArray analyzers, AnalyzerManager analyzerManager, AnalyzerExecutor analyzerExecutor) { return Task.Run(async () => { - AnalyzerActions allAnalyzerActions = new AnalyzerActions(); + var allAnalyzerActions = new AnalyzerActions(); + var concurrentAnalyzers = new HashSet(); foreach (var analyzer in analyzers) { if (!IsDiagnosticAnalyzerSuppressed(analyzer, analyzerExecutor.Compilation.Options, analyzerManager, analyzerExecutor)) { - var analyzerActions = await analyzerManager.GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); + var tuple = await analyzerManager.GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); + var analyzerActions = tuple.Item1; if (analyzerActions != null) { allAnalyzerActions = allAnalyzerActions.Append(analyzerActions); + + var isConcurrentAnalyzer = tuple.Item2; + if (isConcurrentAnalyzer) + { + concurrentAnalyzers.Add(analyzer); + } } } } - return allAnalyzerActions; + var analyzerGateMap = GetAnalyzerGateMap(analyzers, concurrentAnalyzers); + return Tuple.Create(allAnalyzerActions, analyzerGateMap); }, analyzerExecutor.CancellationToken); } + private static ImmutableDictionary GetAnalyzerGateMap(ImmutableArray allAnalyzers, HashSet concurrentAnalyzers) + { + // Non-concurrent analyzers need their action callbacks from the analyzer drive to be guarded by a gate. + if (allAnalyzers.Length == concurrentAnalyzers.Count) + { + // All concurrent analyzers, so we need no gates. + return ImmutableDictionary.Empty; + } + + var builder = ImmutableDictionary.CreateBuilder(); + foreach (var analyzer in allAnalyzers) + { + if (!concurrentAnalyzers.Contains(analyzer)) + { + var gate = new SemaphoreSlim(initialCount: 1); + builder.Add(analyzer, gate); + } + } + + return builder.ToImmutable(); + } + internal async Task GetAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) { var executor = analyzerExecutor.WithCancellationToken(cancellationToken); var analyzerActions = await analyzerManager.GetAnalyzerActionsAsync(analyzer, executor).ConfigureAwait(false); - return AnalyzerActionCounts.Create(analyzerActions); + return AnalyzerActionCounts.Create(analyzerActions.Item1); } /// @@ -991,14 +1038,14 @@ internal AnalyzerDriver(ImmutableArray analyzers, Func>.Empty; } builder.Add(analyzerAndActions.Key, actionsByKind); - } + } analyzerActionsByKind = builder.ToImmutable(); } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs index f103d24ed842c68e09ca15cd19cfdac83cd6a1f8..438f5fa12f5cdcdf60fb8b297c50b86c7245cf43 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs @@ -132,20 +132,27 @@ internal partial class AnalyzerManager } /// - /// Get all the analyzer actions to execute for the given analyzer against a given compilation. + /// Get tuple with: + /// (a) All the analyzer actions to execute for the given analyzer against a given compilation and + /// (b) A flag indicating if these actions can be executed concurrently. /// The returned actions include the actions registered during method as well as /// the actions registered during for the given compilation. /// - public async Task GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) + public async Task> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); + AnalyzerActions allActions; if (sessionScope.CompilationStartActions.Length > 0 && analyzerExecutor.Compilation != null) { var compilationScope = await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor).ConfigureAwait(false); - return compilationScope.GetAnalyzerActions(analyzer); + allActions = compilationScope.GetAnalyzerActions(analyzer); + } + else + { + allActions = sessionScope.GetAnalyzerActions(analyzer); } - return sessionScope.GetAnalyzerActions(analyzer); + return Tuple.Create(allActions, sessionScope.IsConcurrentAnalyzer(analyzer)); } /// diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs index 60f01c6b9ad42fcf9976aa5b8df55d8d39ced90a..27dee599c45808c296048d89bee8e43dfa882578 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs @@ -162,6 +162,18 @@ public void RegisterOperationAction(Action action, par /// Action to be executed at completion of semantic analysis of an . /// Action will be executed only if an 's Kind matches one of the operation kind values. public abstract void RegisterOperationAction(Action action, ImmutableArray operationKinds); + + /// + /// Register for concurrent execution of analyzer actions registered by this analyzer. + /// An analyzer that registers for concurrent execution should be more performant then a non-concurrent analyzer. + /// However, such analyzers must ensure that its actions are implemented in a thread-safe manner. + /// + /// + /// Even when an analyzer registers for concurrent execution, certain related actions are *never* executed concurrently. + /// For example, end actions registered on any analysis unit (compilation, code block, operation block, etc.) are by definition semantically dependent on analysis from non-end actions registered on the same analysis unit. + /// Hence, end actions are never executed concurrently with non-end actions operating on the same analysis unit. + /// + public abstract void RegisterConcurrentExecution(); } /// diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs index ae57e9777cbf0b561737fb9dac8eddde9c09d226..cdd6ed575d223f8af564ff3cd94017472a0b0036 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs @@ -74,19 +74,24 @@ public override void RegisterSyntaxNodeAction(Action action, ImmutableArray operationKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds); - _scope.RegisterOperationAction(this._analyzer, action, operationKinds); + _scope.RegisterOperationAction(_analyzer, action, operationKinds); } public override void RegisterOperationBlockStartAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockStartAction(this._analyzer, action); + _scope.RegisterOperationBlockStartAction(_analyzer, action); } public override void RegisterOperationBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockAction(this._analyzer, action); + _scope.RegisterOperationBlockAction(_analyzer, action); + } + + public override void RegisterConcurrentExecution() + { + _scope.RegisterConcurrentExecution(_analyzer); } } @@ -226,18 +231,29 @@ public override void RegisterOperationAction(Action ac internal sealed class HostSessionStartAnalysisScope : HostAnalysisScope { private ImmutableArray _compilationStartActions = ImmutableArray.Empty; + private ImmutableHashSet _concurrentAnalyzers = ImmutableHashSet.Empty; public ImmutableArray CompilationStartActions { get { return _compilationStartActions; } } + public bool IsConcurrentAnalyzer(DiagnosticAnalyzer analyzer) + { + return _concurrentAnalyzers.Contains(analyzer); + } + public void RegisterCompilationStartAction(DiagnosticAnalyzer analyzer, Action action) { CompilationStartAnalyzerAction analyzerAction = new CompilationStartAnalyzerAction(action, analyzer); this.GetOrCreateAnalyzerActions(analyzer).AddCompilationStartAction(analyzerAction); _compilationStartActions = _compilationStartActions.Add(analyzerAction); } + + public void RegisterConcurrentExecution(DiagnosticAnalyzer analyzer) + { + _concurrentAnalyzers = _concurrentAnalyzers.Add(analyzer); + } } /// @@ -567,6 +583,7 @@ public void RegisterOperationBlockAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray operationKinds) { OperationAnalyzerAction analyzerAction = new OperationAnalyzerAction(action, operationKinds, analyzer); @@ -766,7 +783,7 @@ internal void AddOperationBlockEndAction(OperationBlockAnalyzerAction action) internal void AddOperationAction(OperationAnalyzerAction action) { - this._operationActions = this._operationActions.Add(action); + _operationActions = _operationActions.Add(action); } /// diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 0a776d33421d4aeeaf36cf9c4db376e499270d08..e00ac9c327c044f86ff669fcacdbc5275ccfd3f6 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -76,6 +76,7 @@ virtual Microsoft.CodeAnalysis.MetadataReferenceResolver.ResolveMissingAssembly( virtual Microsoft.CodeAnalysis.SourceReferenceResolver.ReadText(string resolvedPath) -> Microsoft.CodeAnalysis.Text.SourceText Microsoft.CodeAnalysis.SemanticModel.GetOperation(Microsoft.CodeAnalysis.SyntaxNode node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Semantics.IOperation abstract Microsoft.CodeAnalysis.SemanticModel.GetOperationCore(Microsoft.CodeAnalysis.SyntaxNode node, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Semantics.IOperation +abstract Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.RegisterConcurrentExecution() -> void Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.RegisterOperationAction(System.Action action, params Microsoft.CodeAnalysis.Semantics.OperationKind[] operationKinds) -> void Microsoft.CodeAnalysis.Diagnostics.CompilationStartAnalysisContext.RegisterOperationAction(System.Action action, params Microsoft.CodeAnalysis.Semantics.OperationKind[] operationKinds) -> void abstract Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.RegisterOperationAction(System.Action action, System.Collections.Immutable.ImmutableArray operationKinds) -> void diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/project.lock.json b/src/ExpressionEvaluator/Core/Test/ResultProvider/project.lock.json index ae8901df7a5edf8c2d3f08b7ab6ed02386e42bc5..25085f4320c8ba286243d8894acf05802fbf71ea 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/project.lock.json +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/project.lock.json @@ -3,6 +3,23 @@ "version": 1, "targets": { ".NETFramework,Version=v4.5": { + "Microsoft.CodeAnalysis.Test.Resources.Proprietary/1.2.0-beta-20151016-11": { + "compile": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + }, + "runtime": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + } + }, + "Microsoft.DiaSymReader/1.0.6": { + "compile": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + }, + "runtime": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + } + }, + "Microsoft.DiaSymReader.Native/1.3.3": {}, "System.Collections/4.0.0": { "compile": { "ref/net45/_._": {} @@ -45,6 +62,14 @@ "lib/net45/_._": {} } }, + "System.IO/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, "System.Linq/4.0.0": { "compile": { "ref/net45/_._": {} @@ -53,6 +78,54 @@ "lib/net45/_._": {} } }, + "System.Reflection/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Metadata/1.1.0": { + "dependencies": { + "System.Collections": "[4.0.0, )", + "System.Collections.Immutable": "[1.1.37, )", + "System.Diagnostics.Debug": "[4.0.0, )", + "System.IO": "[4.0.0, )", + "System.Reflection": "[4.0.0, )", + "System.Reflection.Extensions": "[4.0.0, )", + "System.Reflection.Primitives": "[4.0.0, )", + "System.Resources.ResourceManager": "[4.0.0, )", + "System.Runtime": "[4.0.0, )", + "System.Runtime.Extensions": "[4.0.0, )", + "System.Runtime.InteropServices": "[4.0.0, )", + "System.Text.Encoding": "[4.0.0, )", + "System.Text.Encoding.Extensions": "[4.0.0, )", + "System.Threading": "[4.0.0, )" + }, + "compile": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + }, + "runtime": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + } + }, + "System.Reflection.Primitives/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, "System.Resources.ResourceManager/4.0.0": { "compile": { "ref/net45/_._": {} @@ -77,6 +150,30 @@ "lib/net45/_._": {} } }, + "System.Runtime.InteropServices/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, "System.Threading/4.0.0": { "compile": { "ref/net45/_._": {} @@ -138,6 +235,48 @@ } }, "libraries": { + "Microsoft.CodeAnalysis.Test.Resources.Proprietary/1.2.0-beta-20151016-11": { + "sha512": "zsE8FvVez0iaoyWutVewackGkJsJXjavomMMdme5NZTXS2/5aG6gdLuaFvGeslq/XMsh4CqIgdvMOOFr5TmpFQ==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll", + "Microsoft.CodeAnalysis.Test.Resources.Proprietary.nuspec", + "package/services/metadata/core-properties/f64bfc9a6f91426492917a4c8a1b955e.psmdcp" + ] + }, + "Microsoft.DiaSymReader/1.0.6": { + "sha512": "ai2eBJrXlHa0hecUKnEyacH0iXxGNOMpc9X0s7VAeqqh5TSTW70QMhTRZ0FNCtf3R/W67K4a+uf3R7MASmAjrg==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/net20/Microsoft.DiaSymReader.dll", + "lib/net20/Microsoft.DiaSymReader.xml", + "lib/portable-net45+win8/Microsoft.DiaSymReader.dll", + "lib/portable-net45+win8/Microsoft.DiaSymReader.xml", + "Microsoft.DiaSymReader.nuspec", + "package/services/metadata/core-properties/ead7dc5d4bf24fbe8708f348725a9b02.psmdcp" + ] + }, + "Microsoft.DiaSymReader.Native/1.3.3": { + "sha512": "mjATkm+L2UlP35gO/ExNutLDfgX4iiwz1l/8sYVoeGHp5WnkEDu0NfIEsC4Oy/pCYeRw0/6SGB+kArJVNNvENQ==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "build/Microsoft.DiaSymReader.Native.props", + "Microsoft.DiaSymReader.Native.nuspec", + "package/services/metadata/core-properties/fdc58d35421849398d4c224d791a4bc4.psmdcp", + "runtimes/win/native/Microsoft.DiaSymReader.Native.amd64.dll", + "runtimes/win/native/Microsoft.DiaSymReader.Native.arm.dll", + "runtimes/win/native/Microsoft.DiaSymReader.Native.x86.dll", + "runtimes/win8-arm/native/Microsoft.DiaSymReader.Native.arm.dll", + "runtimes/win-x64/native/Microsoft.DiaSymReader.Native.amd64.dll", + "runtimes/win-x86/native/Microsoft.DiaSymReader.Native.x86.dll" + ] + }, "System.Collections/4.0.0": { "sha512": "i2vsGDIEbWdHcUSNDPKZP/ZWod6o740el7mGTCy0dqbCxQh74W4QoC+klUwPEtGEFuvzJ7bJgvwJqscosVNyZQ==", "type": "Package", @@ -299,6 +438,55 @@ "System.Globalization.nuspec" ] }, + "System.IO/4.0.0": { + "sha512": "MoCHQ0u5n0OMwUS8OX4Gl48qKiQziSW5cXvt82d+MmAcsLq9OL90+ihnu/aJ1h6OOYcBswrZAEuApfZha9w2lg==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/93bf03c6f6d24eaf9a358a72856daa5f.psmdcp", + "ref/dotnet/de/System.IO.xml", + "ref/dotnet/es/System.IO.xml", + "ref/dotnet/fr/System.IO.xml", + "ref/dotnet/it/System.IO.xml", + "ref/dotnet/ja/System.IO.xml", + "ref/dotnet/ko/System.IO.xml", + "ref/dotnet/ru/System.IO.xml", + "ref/dotnet/System.IO.dll", + "ref/dotnet/System.IO.xml", + "ref/dotnet/zh-hans/System.IO.xml", + "ref/dotnet/zh-hant/System.IO.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.IO.xml", + "ref/netcore50/es/System.IO.xml", + "ref/netcore50/fr/System.IO.xml", + "ref/netcore50/it/System.IO.xml", + "ref/netcore50/ja/System.IO.xml", + "ref/netcore50/ko/System.IO.xml", + "ref/netcore50/ru/System.IO.xml", + "ref/netcore50/System.IO.dll", + "ref/netcore50/System.IO.xml", + "ref/netcore50/zh-hans/System.IO.xml", + "ref/netcore50/zh-hant/System.IO.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.IO.nuspec" + ] + }, "System.Linq/4.0.0": { "sha512": "r6Hlc+ytE6m/9UBr+nNRRdoJEWjoeQiT3L3lXYFDHoXk3VYsRBCDNXrawcexw7KPLaH0zamQLiAb6avhZ50cGg==", "type": "Package", @@ -332,6 +520,137 @@ "System.Linq.nuspec" ] }, + "System.Reflection/4.0.0": { + "sha512": "g96Rn8XuG7y4VfxPj/jnXroRJdQ8L3iN3k3zqsuzk4k3Nq4KMXARYiIO4BLW4GwX06uQpuYwRMcAC/aF117knQ==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/1e935117d401458384a90c2c69f60bd2.psmdcp", + "ref/dotnet/de/System.Reflection.xml", + "ref/dotnet/es/System.Reflection.xml", + "ref/dotnet/fr/System.Reflection.xml", + "ref/dotnet/it/System.Reflection.xml", + "ref/dotnet/ja/System.Reflection.xml", + "ref/dotnet/ko/System.Reflection.xml", + "ref/dotnet/ru/System.Reflection.xml", + "ref/dotnet/System.Reflection.dll", + "ref/dotnet/System.Reflection.xml", + "ref/dotnet/zh-hans/System.Reflection.xml", + "ref/dotnet/zh-hant/System.Reflection.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Reflection.xml", + "ref/netcore50/es/System.Reflection.xml", + "ref/netcore50/fr/System.Reflection.xml", + "ref/netcore50/it/System.Reflection.xml", + "ref/netcore50/ja/System.Reflection.xml", + "ref/netcore50/ko/System.Reflection.xml", + "ref/netcore50/ru/System.Reflection.xml", + "ref/netcore50/System.Reflection.dll", + "ref/netcore50/System.Reflection.xml", + "ref/netcore50/zh-hans/System.Reflection.xml", + "ref/netcore50/zh-hant/System.Reflection.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Reflection.nuspec" + ] + }, + "System.Reflection.Extensions/4.0.0": { + "sha512": "dbYaZWCyFAu1TGYUqR2n+Q+1casSHPR2vVW0WVNkXpZbrd2BXcZ7cpvpu9C98CTHtNmyfMWCLpCclDqly23t6A==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Reflection.Extensions.dll", + "lib/net45/_._", + "lib/netcore50/System.Reflection.Extensions.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "package/services/metadata/core-properties/0bcc335e1ef540948aef9032aca08bb2.psmdcp", + "ref/dotnet/de/System.Reflection.Extensions.xml", + "ref/dotnet/es/System.Reflection.Extensions.xml", + "ref/dotnet/fr/System.Reflection.Extensions.xml", + "ref/dotnet/it/System.Reflection.Extensions.xml", + "ref/dotnet/ja/System.Reflection.Extensions.xml", + "ref/dotnet/ko/System.Reflection.Extensions.xml", + "ref/dotnet/ru/System.Reflection.Extensions.xml", + "ref/dotnet/System.Reflection.Extensions.dll", + "ref/dotnet/System.Reflection.Extensions.xml", + "ref/dotnet/zh-hans/System.Reflection.Extensions.xml", + "ref/dotnet/zh-hant/System.Reflection.Extensions.xml", + "ref/net45/_._", + "ref/netcore50/System.Reflection.Extensions.dll", + "ref/netcore50/System.Reflection.Extensions.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Reflection.Extensions.dll", + "System.Reflection.Extensions.nuspec" + ] + }, + "System.Reflection.Metadata/1.1.0": { + "sha512": "a8VsRm/B0Ik1o5FumSMWmpwbG7cvIIajAYhzTTy9VB9XItByJDQHGZkQTIAdsvVJ6MI5O3uH/lb0izgQDlDIWA==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/dotnet5.2/System.Reflection.Metadata.dll", + "lib/dotnet5.2/System.Reflection.Metadata.xml", + "lib/portable-net45+win8/System.Reflection.Metadata.dll", + "lib/portable-net45+win8/System.Reflection.Metadata.xml", + "package/services/metadata/core-properties/644d6c945e3d43e2806bf6892201a6ef.psmdcp", + "System.Reflection.Metadata.nuspec" + ] + }, + "System.Reflection.Primitives/4.0.0": { + "sha512": "n9S0XpKv2ruc17FSnaiX6nV47VfHTZ1wLjKZlAirUZCvDQCH71mVp+Ohabn0xXLh5pK2PKp45HCxkqu5Fxn/lA==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/DNXCore50/System.Reflection.Primitives.dll", + "lib/net45/_._", + "lib/netcore50/System.Reflection.Primitives.dll", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "package/services/metadata/core-properties/7070509f3bfd418d859635361251dab0.psmdcp", + "ref/dotnet/de/System.Reflection.Primitives.xml", + "ref/dotnet/es/System.Reflection.Primitives.xml", + "ref/dotnet/fr/System.Reflection.Primitives.xml", + "ref/dotnet/it/System.Reflection.Primitives.xml", + "ref/dotnet/ja/System.Reflection.Primitives.xml", + "ref/dotnet/ko/System.Reflection.Primitives.xml", + "ref/dotnet/ru/System.Reflection.Primitives.xml", + "ref/dotnet/System.Reflection.Primitives.dll", + "ref/dotnet/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hans/System.Reflection.Primitives.xml", + "ref/dotnet/zh-hant/System.Reflection.Primitives.xml", + "ref/net45/_._", + "ref/netcore50/System.Reflection.Primitives.dll", + "ref/netcore50/System.Reflection.Primitives.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "runtimes/win8-aot/lib/netcore50/System.Reflection.Primitives.dll", + "System.Reflection.Primitives.nuspec" + ] + }, "System.Resources.ResourceManager/4.0.0": { "sha512": "qmqeZ4BJgjfU+G2JbrZt4Dk1LsMxO4t+f/9HarNY6w8pBgweO6jT+cknUH7c3qIrGvyUqraBhU45Eo6UtA0fAw==", "type": "Package", @@ -464,6 +783,151 @@ "System.Runtime.Extensions.nuspec" ] }, + "System.Runtime.InteropServices/4.0.0": { + "sha512": "J8GBB0OsVuKJXR412x6uZdoyNi4y9OMjjJRHPutRHjqujuvthus6Xdxn/i8J1lL2PK+2jWCLpZp72h8x73hkLg==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/cb937f04833048a9948507c9ef331a18.psmdcp", + "ref/dotnet/de/System.Runtime.InteropServices.xml", + "ref/dotnet/es/System.Runtime.InteropServices.xml", + "ref/dotnet/fr/System.Runtime.InteropServices.xml", + "ref/dotnet/it/System.Runtime.InteropServices.xml", + "ref/dotnet/ja/System.Runtime.InteropServices.xml", + "ref/dotnet/ko/System.Runtime.InteropServices.xml", + "ref/dotnet/ru/System.Runtime.InteropServices.xml", + "ref/dotnet/System.Runtime.InteropServices.dll", + "ref/dotnet/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hans/System.Runtime.InteropServices.xml", + "ref/dotnet/zh-hant/System.Runtime.InteropServices.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Runtime.InteropServices.xml", + "ref/netcore50/es/System.Runtime.InteropServices.xml", + "ref/netcore50/fr/System.Runtime.InteropServices.xml", + "ref/netcore50/it/System.Runtime.InteropServices.xml", + "ref/netcore50/ja/System.Runtime.InteropServices.xml", + "ref/netcore50/ko/System.Runtime.InteropServices.xml", + "ref/netcore50/ru/System.Runtime.InteropServices.xml", + "ref/netcore50/System.Runtime.InteropServices.dll", + "ref/netcore50/System.Runtime.InteropServices.xml", + "ref/netcore50/zh-hans/System.Runtime.InteropServices.xml", + "ref/netcore50/zh-hant/System.Runtime.InteropServices.xml", + "ref/win8/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Runtime.InteropServices.nuspec" + ] + }, + "System.Text.Encoding/4.0.0": { + "sha512": "AMxFNOXpA6Ab8swULbXuJmoT2K5w6TnV3ObF5wsmEcIHQUJghoZtDVfVHb08O2wW15mOSI1i9Wg0Dx0pY13o8g==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/8740abce9d6a472db9f21ed43f2fb149.psmdcp", + "ref/dotnet/de/System.Text.Encoding.xml", + "ref/dotnet/es/System.Text.Encoding.xml", + "ref/dotnet/fr/System.Text.Encoding.xml", + "ref/dotnet/it/System.Text.Encoding.xml", + "ref/dotnet/ja/System.Text.Encoding.xml", + "ref/dotnet/ko/System.Text.Encoding.xml", + "ref/dotnet/ru/System.Text.Encoding.xml", + "ref/dotnet/System.Text.Encoding.dll", + "ref/dotnet/System.Text.Encoding.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Text.Encoding.xml", + "ref/netcore50/es/System.Text.Encoding.xml", + "ref/netcore50/fr/System.Text.Encoding.xml", + "ref/netcore50/it/System.Text.Encoding.xml", + "ref/netcore50/ja/System.Text.Encoding.xml", + "ref/netcore50/ko/System.Text.Encoding.xml", + "ref/netcore50/ru/System.Text.Encoding.xml", + "ref/netcore50/System.Text.Encoding.dll", + "ref/netcore50/System.Text.Encoding.xml", + "ref/netcore50/zh-hans/System.Text.Encoding.xml", + "ref/netcore50/zh-hant/System.Text.Encoding.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Text.Encoding.nuspec" + ] + }, + "System.Text.Encoding.Extensions/4.0.0": { + "sha512": "FktA77+2DC0S5oRhgM569pbzFrcA45iQpYiI7+YKl68B6TfI2N5TQbXqSWlh2YXKoFXHi2RFwPMha2lxiFJZ6A==", + "type": "Package", + "files": [ + "[Content_Types].xml", + "_rels/.rels", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/_._", + "lib/win8/_._", + "lib/wp80/_._", + "lib/wpa81/_._", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "License.rtf", + "package/services/metadata/core-properties/c37aa1347f574e6c8df522449486a4d2.psmdcp", + "ref/dotnet/de/System.Text.Encoding.Extensions.xml", + "ref/dotnet/es/System.Text.Encoding.Extensions.xml", + "ref/dotnet/fr/System.Text.Encoding.Extensions.xml", + "ref/dotnet/it/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ja/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ko/System.Text.Encoding.Extensions.xml", + "ref/dotnet/ru/System.Text.Encoding.Extensions.xml", + "ref/dotnet/System.Text.Encoding.Extensions.dll", + "ref/dotnet/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/dotnet/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/_._", + "ref/netcore50/de/System.Text.Encoding.Extensions.xml", + "ref/netcore50/es/System.Text.Encoding.Extensions.xml", + "ref/netcore50/fr/System.Text.Encoding.Extensions.xml", + "ref/netcore50/it/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ja/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ko/System.Text.Encoding.Extensions.xml", + "ref/netcore50/ru/System.Text.Encoding.Extensions.xml", + "ref/netcore50/System.Text.Encoding.Extensions.dll", + "ref/netcore50/System.Text.Encoding.Extensions.xml", + "ref/netcore50/zh-hans/System.Text.Encoding.Extensions.xml", + "ref/netcore50/zh-hant/System.Text.Encoding.Extensions.xml", + "ref/win8/_._", + "ref/wp80/_._", + "ref/wpa81/_._", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "System.Text.Encoding.Extensions.nuspec" + ] + }, "System.Threading/4.0.0": { "sha512": "H6O/9gUrjPDNYanh/7OFGAZHjVXvEuITD0RcnjfvIV04HOGrOPqUBU0kmz9RIX/7YGgCQn1o1S2DX6Cuv8kVGQ==", "type": "Package", diff --git a/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs b/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs index 3918917b0ac8a6b99f2af6abaf9ab52471fdc04d..f3fae2cc10a087e81cafe91c6700e6dc01afdf76 100644 --- a/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs +++ b/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs @@ -4,10 +4,11 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Utilities; -using System.IO; +using Xunit; namespace Microsoft.CodeAnalysis { @@ -479,5 +480,120 @@ private void OnCompilation(CompilationAnalysisContext context) } } } + + /// + /// This analyzer is intended to be used only when concurrent execution is enabled for analyzers. + /// This analyzer will deadlock if the driver runs analyzers on a single thread OR takes a lock around callbacks into this analyzer to prevent concurrent analyzer execution + /// Former indicates a bug in the test using this analyzer and the latter indicates a bug in the analyzer driver. + /// + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public class ConcurrentAnalyzer : DiagnosticAnalyzer + { + private readonly ImmutableHashSet _symbolNames; + private int _token; + + public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor( + "ConcurrentAnalyzerId", + "Title", + "ConcurrentAnalyzerMessage for symbol '{0}'", + "Category", + DiagnosticSeverity.Warning, + true); + + public ConcurrentAnalyzer(IEnumerable symbolNames) + { + Assert.True(Environment.ProcessorCount > 1, "This analyzer is intended to be used only in a concurrent environment."); + _symbolNames = symbolNames.ToImmutableHashSet(); + _token = 0; + } + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + public override void Initialize(AnalysisContext context) + { + context.RegisterCompilationStartAction(this.OnCompilationStart); + + // Register concurrent action callbacks on analyzer. + context.RegisterConcurrentExecution(); + } + + private void OnCompilationStart(CompilationStartAnalysisContext context) + { + Assert.True(context.Compilation.Options.ConcurrentBuild, "This analyzer is intended to be used only when concurrent build is enabled."); + + var pendingSymbols = new ConcurrentSet(); + foreach (var type in context.Compilation.GlobalNamespace.GetTypeMembers()) + { + if (_symbolNames.Contains(type.Name)) + { + pendingSymbols.Add(type); + } + } + + context.RegisterSymbolAction(symbolContext => + { + if (!pendingSymbols.Remove((INamedTypeSymbol)symbolContext.Symbol)) + { + return; + } + + var myToken = Interlocked.Increment(ref _token); + if (myToken == 1) + { + // Wait for all symbol callbacks to execute. + // This analyzer will deadlock if the driver doesn't attempt concurrent callbacks. + while (pendingSymbols.Any()) + { + Thread.Sleep(10); + } + } + + // ok, now report diagnostic on the symbol. + var diagnostic = Diagnostic.Create(Descriptor, symbolContext.Symbol.Locations[0], symbolContext.Symbol.Name); + symbolContext.ReportDiagnostic(diagnostic); + }, SymbolKind.NamedType); + } + } + + /// + /// This analyzer will report diagnostics only if it receives any concurrent action callbacks, which would be a + /// bug in the analyzer driver as this analyzer doesn't invoke . + /// + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public class NonConcurrentAnalyzer : DiagnosticAnalyzer + { + public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor( + "NonConcurrentAnalyzerId", + "Title", + "Analyzer driver made concurrent action callbacks, when analyzer didn't register for concurrent execution", + "Category", + DiagnosticSeverity.Warning, + true); + private const int registeredActionCounts = 1000; + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + public override void Initialize(AnalysisContext context) + { + SemaphoreSlim gate = new SemaphoreSlim(initialCount: registeredActionCounts); + for (var i = 0; i < registeredActionCounts; i++) + { + context.RegisterSymbolAction(symbolContext => + { + using (gate.DisposableWait(symbolContext.CancellationToken)) + { + ReportDiagnosticIfActionInvokedConcurrently(gate, symbolContext); + } + }, SymbolKind.NamedType); + } + } + + private void ReportDiagnosticIfActionInvokedConcurrently(SemaphoreSlim gate, SymbolAnalysisContext symbolContext) + { + if (gate.CurrentCount != registeredActionCounts - 1) + { + var diagnostic = Diagnostic.Create(Descriptor, symbolContext.Symbol.Locations[0]); + symbolContext.ReportDiagnostic(diagnostic); + } + } + } } } \ No newline at end of file diff --git a/src/Test/Utilities/Portable.FX45/project.lock.json b/src/Test/Utilities/Portable.FX45/project.lock.json index a735d62555081adb126d5a638c2bb12f738b1dd6..d6c11856d5fe6107695e80400f8e9338a857d825 100644 --- a/src/Test/Utilities/Portable.FX45/project.lock.json +++ b/src/Test/Utilities/Portable.FX45/project.lock.json @@ -233,6 +233,468 @@ } } }, + ".NETFramework,Version=v4.5/osx.10.10": { + "Microsoft.CodeAnalysis.Test.Resources.Proprietary/1.2.0-beta-20151016-11": { + "compile": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + }, + "runtime": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + } + }, + "Microsoft.DiaSymReader/1.0.6": { + "compile": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + }, + "runtime": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + } + }, + "Microsoft.DiaSymReader.Native/1.3.3": {}, + "System.Collections/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Collections.Immutable/1.1.37": { + "dependencies": { + "System.Collections": "[4.0.0, )", + "System.Diagnostics.Debug": "[4.0.0, )", + "System.Globalization": "[4.0.0, )", + "System.Linq": "[4.0.0, )", + "System.Resources.ResourceManager": "[4.0.0, )", + "System.Runtime": "[4.0.0, )", + "System.Runtime.Extensions": "[4.0.0, )", + "System.Threading": "[4.0.0, )" + }, + "compile": { + "lib/dotnet/System.Collections.Immutable.dll": {} + }, + "runtime": { + "lib/dotnet/System.Collections.Immutable.dll": {} + } + }, + "System.Diagnostics.Debug/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Globalization/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.IO/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Linq/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Metadata/1.1.0": { + "dependencies": { + "System.Collections": "[4.0.0, )", + "System.Collections.Immutable": "[1.1.37, )", + "System.Diagnostics.Debug": "[4.0.0, )", + "System.IO": "[4.0.0, )", + "System.Reflection": "[4.0.0, )", + "System.Reflection.Extensions": "[4.0.0, )", + "System.Reflection.Primitives": "[4.0.0, )", + "System.Resources.ResourceManager": "[4.0.0, )", + "System.Runtime": "[4.0.0, )", + "System.Runtime.Extensions": "[4.0.0, )", + "System.Runtime.InteropServices": "[4.0.0, )", + "System.Text.Encoding": "[4.0.0, )", + "System.Text.Encoding.Extensions": "[4.0.0, )", + "System.Threading": "[4.0.0, )" + }, + "compile": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + }, + "runtime": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + } + }, + "System.Reflection.Primitives/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Resources.ResourceManager/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime.InteropServices/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Threading/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "xunit/2.1.0": { + "dependencies": { + "xunit.assert": "[2.1.0, 2.1.0]", + "xunit.core": "[2.1.0, 2.1.0]" + } + }, + "xunit.abstractions/2.0.0": { + "compile": { + "lib/net35/xunit.abstractions.dll": {} + }, + "runtime": { + "lib/net35/xunit.abstractions.dll": {} + } + }, + "xunit.assert/2.1.0": { + "compile": { + "lib/dotnet/xunit.assert.dll": {} + }, + "runtime": { + "lib/dotnet/xunit.assert.dll": {} + } + }, + "xunit.core/2.1.0": { + "dependencies": { + "xunit.extensibility.core": "[2.1.0, 2.1.0]", + "xunit.extensibility.execution": "[2.1.0, 2.1.0]" + } + }, + "xunit.extensibility.core/2.1.0": { + "dependencies": { + "xunit.abstractions": "[2.0.0, 2.0.0]" + }, + "compile": { + "lib/dotnet/xunit.core.dll": {} + }, + "runtime": { + "lib/dotnet/xunit.core.dll": {} + } + }, + "xunit.extensibility.execution/2.1.0": { + "dependencies": { + "xunit.extensibility.core": "[2.1.0, 2.1.0]" + }, + "compile": { + "lib/net45/xunit.execution.desktop.dll": {} + }, + "runtime": { + "lib/net45/xunit.execution.desktop.dll": {} + } + } + }, + ".NETFramework,Version=v4.5/osx.10.10-anycpu": { + "Microsoft.CodeAnalysis.Test.Resources.Proprietary/1.2.0-beta-20151016-11": { + "compile": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + }, + "runtime": { + "lib/net45/Microsoft.CodeAnalysis.Test.Resources.Proprietary.dll": {} + } + }, + "Microsoft.DiaSymReader/1.0.6": { + "compile": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + }, + "runtime": { + "lib/net20/Microsoft.DiaSymReader.dll": {} + } + }, + "Microsoft.DiaSymReader.Native/1.3.3": {}, + "System.Collections/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Collections.Immutable/1.1.37": { + "dependencies": { + "System.Collections": "[4.0.0, )", + "System.Diagnostics.Debug": "[4.0.0, )", + "System.Globalization": "[4.0.0, )", + "System.Linq": "[4.0.0, )", + "System.Resources.ResourceManager": "[4.0.0, )", + "System.Runtime": "[4.0.0, )", + "System.Runtime.Extensions": "[4.0.0, )", + "System.Threading": "[4.0.0, )" + }, + "compile": { + "lib/dotnet/System.Collections.Immutable.dll": {} + }, + "runtime": { + "lib/dotnet/System.Collections.Immutable.dll": {} + } + }, + "System.Diagnostics.Debug/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Globalization/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.IO/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Linq/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Reflection.Metadata/1.1.0": { + "dependencies": { + "System.Collections": "[4.0.0, )", + "System.Collections.Immutable": "[1.1.37, )", + "System.Diagnostics.Debug": "[4.0.0, )", + "System.IO": "[4.0.0, )", + "System.Reflection": "[4.0.0, )", + "System.Reflection.Extensions": "[4.0.0, )", + "System.Reflection.Primitives": "[4.0.0, )", + "System.Resources.ResourceManager": "[4.0.0, )", + "System.Runtime": "[4.0.0, )", + "System.Runtime.Extensions": "[4.0.0, )", + "System.Runtime.InteropServices": "[4.0.0, )", + "System.Text.Encoding": "[4.0.0, )", + "System.Text.Encoding.Extensions": "[4.0.0, )", + "System.Threading": "[4.0.0, )" + }, + "compile": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + }, + "runtime": { + "lib/dotnet5.2/System.Reflection.Metadata.dll": {} + } + }, + "System.Reflection.Primitives/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Resources.ResourceManager/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Runtime.InteropServices/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Text.Encoding.Extensions/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "System.Threading/4.0.0": { + "compile": { + "ref/net45/_._": {} + }, + "runtime": { + "lib/net45/_._": {} + } + }, + "xunit/2.1.0": { + "dependencies": { + "xunit.assert": "[2.1.0, 2.1.0]", + "xunit.core": "[2.1.0, 2.1.0]" + } + }, + "xunit.abstractions/2.0.0": { + "compile": { + "lib/net35/xunit.abstractions.dll": {} + }, + "runtime": { + "lib/net35/xunit.abstractions.dll": {} + } + }, + "xunit.assert/2.1.0": { + "compile": { + "lib/dotnet/xunit.assert.dll": {} + }, + "runtime": { + "lib/dotnet/xunit.assert.dll": {} + } + }, + "xunit.core/2.1.0": { + "dependencies": { + "xunit.extensibility.core": "[2.1.0, 2.1.0]", + "xunit.extensibility.execution": "[2.1.0, 2.1.0]" + } + }, + "xunit.extensibility.core/2.1.0": { + "dependencies": { + "xunit.abstractions": "[2.0.0, 2.0.0]" + }, + "compile": { + "lib/dotnet/xunit.core.dll": {} + }, + "runtime": { + "lib/dotnet/xunit.core.dll": {} + } + }, + "xunit.extensibility.execution/2.1.0": { + "dependencies": { + "xunit.extensibility.core": "[2.1.0, 2.1.0]" + }, + "compile": { + "lib/net45/xunit.execution.desktop.dll": {} + }, + "runtime": { + "lib/net45/xunit.execution.desktop.dll": {} + } + } + }, ".NETFramework,Version=v4.5/ubuntu.14.04": { "Microsoft.CodeAnalysis.Test.Resources.Proprietary/1.2.0-beta-20151016-11": { "compile": {