diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/SyntaxTreeHelpers.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/SyntaxTreeHelpers.cs index ff0b17281..9e2470720 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/SyntaxTreeHelpers.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/SyntaxTreeHelpers.cs @@ -6,7 +6,8 @@ namespace StyleCop.Analyzers.Helpers { using System; - using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Diagnostics; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -23,18 +24,17 @@ internal static class SyntaxTreeHelpers /// This allows many analyzers that run on every token in the file to avoid checking /// the same state in the document repeatedly. /// - private static Tuple, ConcurrentDictionary> usingAliasCache - = Tuple.Create(new WeakReference(null), default(ConcurrentDictionary)); + private static Tuple, IReadOnlyDictionary> usingAliasCache + = Tuple.Create(new WeakReference(null), default(IReadOnlyDictionary)); - public static ConcurrentDictionary GetOrCreateUsingAliasCache(this Compilation compilation) + public static IReadOnlyDictionary GetOrCreateUsingAliasCache(this Compilation compilation) { var cache = usingAliasCache; Compilation cachedCompilation; if (!cache.Item1.TryGetTarget(out cachedCompilation) || cachedCompilation != compilation) { - var containsGlobalUsingAlias = ContainsGlobalUsingAliasNoCache(compilation); - var replacementDictionary = containsGlobalUsingAlias ? null : new ConcurrentDictionary(); + var replacementDictionary = CreateDictionary(compilation); var replacementCache = Tuple.Create(new WeakReference(compilation), replacementDictionary); while (true) @@ -75,7 +75,7 @@ public static bool IsWhitespaceOnly(this SyntaxTree tree, CancellationToken canc && TriviaHelper.IndexOfFirstNonWhitespaceTrivia(firstToken.LeadingTrivia) == -1; } - internal static bool ContainsUsingAlias(this SyntaxTree tree, ConcurrentDictionary cache) + internal static bool ContainsUsingAlias(this SyntaxTree tree, IReadOnlyDictionary cache) { if (tree == null) { @@ -88,35 +88,39 @@ internal static bool ContainsUsingAlias(this SyntaxTree tree, ConcurrentDictiona return true; } - bool result; - if (cache.TryGetValue(tree, out result)) + if (cache.TryGetValue(tree, out var result)) { return result; } - bool generated = ContainsUsingAliasNoCache(tree); - cache.TryAdd(tree, generated); - return generated; + Debug.Assert(false, "This should not happen. Syntax tree could not be found in cache!"); + return false; } - private static bool ContainsUsingAliasNoCache(SyntaxTree tree) + private static IReadOnlyDictionary CreateDictionary(Compilation compilation) { - var nodes = tree.GetRoot().DescendantNodes(node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration) || node.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration)); + var result = new Dictionary(); - return nodes.OfType().Any(x => x.Alias != null); - } + foreach (var tree in compilation.SyntaxTrees) + { + CheckUsingAliases(tree, out var containsUsingAlias, out var containsGlobalUsingAlias); + if (containsGlobalUsingAlias) + { + return null; + } - private static bool ContainsGlobalUsingAliasNoCache(Compilation compilation) - { - return compilation.SyntaxTrees.Any(ContainsGlobalUsingAliasNoCache); + result.Add(tree, containsUsingAlias); + } + + return result; } - private static bool ContainsGlobalUsingAliasNoCache(SyntaxTree tree) + private static void CheckUsingAliases(SyntaxTree tree, out bool containsUsingAlias, out bool containsGlobalUsingAlias) { - var nodes = tree.GetRoot().DescendantNodes(node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration) || node.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration)); - - var relevantNodes = nodes.OfType().ToArray(); - return relevantNodes.Any(x => x.Alias != null && !x.GlobalKeyword().IsKind(SyntaxKind.None)); + var usingNodes = tree.GetRoot().DescendantNodes(node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration) || node.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration)).OfType(); + var usingAliasNodes = usingNodes.Where(x => x.Alias != null).ToList(); + containsUsingAlias = usingAliasNodes.Any(); + containsGlobalUsingAlias = usingAliasNodes.Any(x => !x.GlobalKeyword().IsKind(SyntaxKind.None)); } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1404CodeAnalysisSuppressionMustHaveJustification.cs b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1404CodeAnalysisSuppressionMustHaveJustification.cs index 10b7e65d2..b0d1d8d5d 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1404CodeAnalysisSuppressionMustHaveJustification.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1404CodeAnalysisSuppressionMustHaveJustification.cs @@ -6,7 +6,7 @@ namespace StyleCop.Analyzers.MaintainabilityRules { using System; - using System.Collections.Concurrent; + using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; @@ -78,7 +78,7 @@ private static void HandleCompilationStart(CompilationStartAnalysisContext conte /// private sealed class AnalyzerInstance { - private readonly ConcurrentDictionary usingAliasCache; + private readonly IReadOnlyDictionary usingAliasCache; /// /// A lazily-initialized reference to within the context of a @@ -86,7 +86,7 @@ private sealed class AnalyzerInstance /// private INamedTypeSymbol suppressMessageAttribute; - public AnalyzerInstance(ConcurrentDictionary usingAliasCache) + public AnalyzerInstance(IReadOnlyDictionary usingAliasCache) { this.usingAliasCache = usingAliasCache; } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1121UseBuiltInTypeAlias.cs b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1121UseBuiltInTypeAlias.cs index 8f86c7322..6c820eddd 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1121UseBuiltInTypeAlias.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1121UseBuiltInTypeAlias.cs @@ -6,7 +6,7 @@ namespace StyleCop.Analyzers.ReadabilityRules { using System; - using System.Collections.Concurrent; + using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -159,9 +159,9 @@ private static void HandleCompilationStart(CompilationStartAnalysisContext conte private sealed class Analyzer { - private readonly ConcurrentDictionary usingAliasCache; + private readonly IReadOnlyDictionary usingAliasCache; - public Analyzer(ConcurrentDictionary usingAliasCache) + public Analyzer(IReadOnlyDictionary usingAliasCache) { this.usingAliasCache = usingAliasCache; }