From 8ce70292cd6087dff52a3770189a8f103089b320 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sun, 19 Jan 2020 14:00:47 -0800 Subject: [PATCH] Calculate aliases at the start of analysis --- .../Analyzers/TypeSyntaxSimplifierWalker.cs | 53 ++++++++++++++++--- .../Analyzers/TypeSyntaxSimplifierWalker.vb | 37 ++++++++++--- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs index ac971fb6151..968b66c63d0 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs @@ -15,6 +15,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames { internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker { + private static readonly ImmutableHashSet s_emptyAliasedNames = ImmutableHashSet.Create(StringComparer.Ordinal); + /// /// This set contains the full names of types that have equivalent predefined names in the language. /// @@ -48,7 +50,7 @@ internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker /// This is used so we can easily tell if we should try to simplify some identifier to an /// alias when we encounter it. /// - private ImmutableHashSet _aliasedNames = ImmutableHashSet.Create(StringComparer.Ordinal); + private readonly ImmutableHashSet _aliasedNames; public List Diagnostics { get; } = new List(); @@ -59,23 +61,58 @@ public TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer anal _semanticModel = semanticModel; _optionSet = optionSet; _cancellationToken = cancellationToken; + + var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); + _aliasedNames = GetAliasedNames(root as CompilationUnitSyntax); } - public override void VisitUsingDirective(UsingDirectiveSyntax node) + private static ImmutableHashSet GetAliasedNames(CompilationUnitSyntax? compilationUnit) { - if (node.Alias is object) + var aliasedNames = s_emptyAliasedNames; + if (compilationUnit is null) + return aliasedNames; + + foreach (var usingDirective in compilationUnit.Usings) { - if (node.Name.GetRightmostName() is IdentifierNameSyntax identifierName) + AddAliasedName(usingDirective); + } + + foreach (var member in compilationUnit.Members) + { + if (member is NamespaceDeclarationSyntax namespaceDeclaration) + AddAliasedNames(namespaceDeclaration); + } + + return aliasedNames; + + void AddAliasedName(UsingDirectiveSyntax usingDirective) + { + if (usingDirective.Alias is object) { - var identifierAlias = identifierName.Identifier.ValueText; - if (!RoslynString.IsNullOrEmpty(identifierAlias)) + if (usingDirective.Name.GetRightmostName() is IdentifierNameSyntax identifierName) { - ImmutableInterlocked.Update(ref _aliasedNames, (set, alias) => set.Add(alias), identifierAlias); + var identifierAlias = identifierName.Identifier.ValueText; + if (!RoslynString.IsNullOrEmpty(identifierAlias)) + { + aliasedNames = aliasedNames.Add(identifierAlias); + } } } } - base.VisitUsingDirective(node); + void AddAliasedNames(NamespaceDeclarationSyntax namespaceDeclaration) + { + foreach (var usingDirective in namespaceDeclaration.Usings) + { + AddAliasedName(usingDirective); + } + + foreach (var member in namespaceDeclaration.Members) + { + if (member is NamespaceDeclarationSyntax memberNamespace) + AddAliasedNames(memberNamespace); + } + } } public override void VisitQualifiedName(QualifiedNameSyntax node) diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb index 4b22156eaca..2361f0694ea 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.vb @@ -9,6 +9,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Friend Class TypeSyntaxSimplifierWalker Inherits VisualBasicSyntaxWalker + Private Shared ReadOnly s_emptyAliasedNames As ImmutableHashSet(Of String) = ImmutableHashSet.Create(Of String)(CaseInsensitiveComparison.Comparer) + Private Shared ReadOnly s_predefinedTypeMetadataNames As ImmutableHashSet(Of String) = ImmutableHashSet.Create( CaseInsensitiveComparison.Comparer, NameOf([Boolean]), @@ -39,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames ''' This is used so we can easily tell if we should try to simplify some identifier to an ''' alias when we encounter it. ''' - Private _aliasedNames As ImmutableHashSet(Of String) = ImmutableHashSet.Create(Of String)(CaseInsensitiveComparison.Comparer) + Private ReadOnly _aliasedNames As ImmutableHashSet(Of String) Public ReadOnly Property Diagnostics As List(Of Diagnostic) = New List(Of Diagnostic)() @@ -51,22 +53,43 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames _optionSet = optionSet _cancellationToken = cancellationToken + Dim root = semanticModel.SyntaxTree.GetRoot(cancellationToken) + _aliasedNames = GetAliasedNames(TryCast(root, CompilationUnitSyntax)) + For Each aliasSymbol In semanticModel.Compilation.AliasImports() _aliasedNames = _aliasedNames.Add(aliasSymbol.Target.Name) Next End Sub - Public Overrides Sub VisitSimpleImportsClause(node As SimpleImportsClauseSyntax) - If node.Alias IsNot Nothing Then - Dim identifierName = TryCast(node.Name.GetRightmostName(), IdentifierNameSyntax) + Private Shared Function GetAliasedNames(compilationUnit As CompilationUnitSyntax) As ImmutableHashSet(Of String) + Dim aliasedNames = s_emptyAliasedNames + If compilationUnit Is Nothing Then + Return aliasedNames + End If + + For Each importsStatement In compilationUnit.Imports + For Each importsClause In importsStatement.ImportsClauses + Dim simpleImportsClause = TryCast(importsClause, SimpleImportsClauseSyntax) + If simpleImportsClause Is Nothing Then + Continue For + End If + + AddAliasedName(aliasedNames, simpleImportsClause) + Next + Next + + Return aliasedNames + End Function + + Private Shared Sub AddAliasedName(ByRef aliasedNames As ImmutableHashSet(Of String), simpleImportsClause As SimpleImportsClauseSyntax) + If simpleImportsClause.Alias IsNot Nothing Then + Dim identifierName = TryCast(simpleImportsClause.Name.GetRightmostName(), IdentifierNameSyntax) If identifierName IsNot Nothing Then If Not String.IsNullOrEmpty(identifierName.Identifier.ValueText) Then - ImmutableInterlocked.Update(_aliasedNames, Function(names, identifier) names.Add(identifier), identifierName.Identifier.ValueText) + aliasedNames = aliasedNames.Add(identifierName.Identifier.ValueText) End If End If End If - - MyBase.VisitSimpleImportsClause(node) End Sub Public Overrides Sub VisitQualifiedName(node As QualifiedNameSyntax) -- GitLab