From 8d6979002d0ddf4f33079470ddfbca8a417f0c75 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 15 Aug 2023 10:49:52 -0700 Subject: [PATCH 1/2] Extract a shared helper for walking statements for a few analyzers --- ...bstractUseCollectionInitializerAnalyzer.cs | 39 ++-------------- .../UseCollectionInitializerHelpers.cs | 46 ++++++++++++++++++- .../UseNamedMemberInitializerAnalyzer.cs | 35 ++------------ 3 files changed, 52 insertions(+), 68 deletions(-) diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs index 069fee0b37535..8fef5284f158f 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs @@ -8,9 +8,9 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Analyzers.UseCollectionInitializer; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.UseCollectionInitializer { @@ -99,19 +99,6 @@ public ImmutableArray> Analyze( protected override bool TryAddMatches(ArrayBuilder> matches) { - // If containing statement is inside a block (e.g. method), than we need to iterate through its child statements. - // If containing statement is in top-level code, than we need to iterate through child statements of containing compilation unit. - var containingBlockOrCompilationUnit = _containingStatement.GetRequiredParent(); - - // In case of top-level code parent of the statement will be GlobalStatementSyntax, - // so we need to get its parent in order to get CompilationUnitSyntax - if (_syntaxFacts.IsGlobalStatement(containingBlockOrCompilationUnit)) - { - containingBlockOrCompilationUnit = containingBlockOrCompilationUnit.Parent!; - } - - var foundStatement = false; - var seenInvocation = false; var seenIndexAssignment = false; @@ -135,35 +122,19 @@ protected override bool TryAddMatches(ArrayBuilder> matc if (seenIndexAssignment && _analyzeForCollectionExpression) return false; - foreach (var child in containingBlockOrCompilationUnit.ChildNodesAndTokens()) + foreach (var subsequentStatement in UseCollectionInitializerHelpers.GetSubsequentStatements(_syntaxFacts, _containingStatement)) { - if (child.IsToken) - continue; - - var childNode = child.AsNode(); - var extractedChild = _syntaxFacts.IsGlobalStatement(childNode) ? _syntaxFacts.GetStatementOfGlobalStatement(childNode) : childNode; - - if (!foundStatement) - { - if (extractedChild == _containingStatement) - { - foundStatement = true; - } - - continue; - } - - if (extractedChild is TExpressionStatementSyntax expressionStatement && + if (subsequentStatement is TExpressionStatementSyntax expressionStatement && TryProcessExpressionStatement(expressionStatement)) { continue; } - else if (extractedChild is TForeachStatementSyntax foreachStatement && + else if (subsequentStatement is TForeachStatementSyntax foreachStatement && TryProcessForeachStatement(foreachStatement)) { continue; } - else if (extractedChild is TIfStatementSyntax ifStatement && + else if (subsequentStatement is TIfStatementSyntax ifStatement && TryProcessIfStatement(ifStatement)) { continue; diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs index 2a7f5a6e26f35..c554302068369 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Text; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Analyzers.UseCollectionInitializer; @@ -15,4 +15,46 @@ internal static class UseCollectionInitializerHelpers public static readonly ImmutableDictionary UseCollectionExpressionProperties = ImmutableDictionary.Empty.Add(UseCollectionExpressionName, UseCollectionExpressionName); + + public static IEnumerable GetSubsequentStatements( + ISyntaxFacts syntaxFacts, + TStatementSyntax initialStatement) where TStatementSyntax : SyntaxNode + { + // If containing statement is inside a block (e.g. method), than we need to iterate through its child + // statements. If containing statement is in top-level code, than we need to iterate through child statements of + // containing compilation unit. + var containingBlockOrCompilationUnit = initialStatement.GetRequiredParent(); + + // In case of top-level code parent of the statement will be GlobalStatementSyntax, so we need to get its parent + // in order to get CompilationUnitSyntax + if (syntaxFacts.IsGlobalStatement(containingBlockOrCompilationUnit)) + containingBlockOrCompilationUnit = containingBlockOrCompilationUnit.Parent!; + + var foundStatement = false; + foreach (var child in containingBlockOrCompilationUnit.ChildNodesAndTokens()) + { + if (child.IsToken) + continue; + + var childNode = child.AsNode()!; + var extractedChild = syntaxFacts.IsGlobalStatement(childNode) + ? syntaxFacts.GetStatementOfGlobalStatement(childNode) + : childNode; + + if (!foundStatement) + { + if (extractedChild == initialStatement) + { + foundStatement = true; + } + + continue; + } + + if (extractedChild is not TStatementSyntax childStatement) + break; + + yield return childStatement; + } + } } diff --git a/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs index 1eb985b0a0e60..a52f76036f144 100644 --- a/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading; +using Microsoft.CodeAnalysis.Analyzers.UseCollectionInitializer; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -59,19 +60,6 @@ protected override bool ShouldAnalyze() protected override bool TryAddMatches(ArrayBuilder> matches) { - // If containing statement is inside a block (e.g. method), than we need to iterate through its child statements. - // If containing statement is in top-level code, than we need to iterate through child statements of containing compilation unit. - var containingBlockOrCompilationUnit = _containingStatement.Parent; - - // In case of top-level code parent of the statement will be GlobalStatementSyntax, - // so we need to get its parent in order to get CompilationUnitSyntax - if (_syntaxFacts.IsGlobalStatement(containingBlockOrCompilationUnit)) - { - containingBlockOrCompilationUnit = containingBlockOrCompilationUnit.Parent; - } - - var foundStatement = false; - using var _1 = PooledHashSet.GetInstance(out var seenNames); var initializer = _syntaxFacts.GetInitializerOfBaseObjectCreationExpression(_objectCreationExpression); @@ -87,26 +75,9 @@ protected override bool TryAddMatches(ArrayBuilder Date: Tue, 15 Aug 2023 15:00:08 -0700 Subject: [PATCH 2/2] Fix --- .../AbstractUseCollectionInitializerAnalyzer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs index e4256964629a4..a737b733eb273 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs @@ -122,13 +122,13 @@ protected override bool TryAddMatches(ArrayBuilder> matc { continue; } - else if (_syntaxFacts.IsForEachStatement(extractedChild) && - TryProcessForeachStatement((TStatementSyntax)extractedChild)) + else if (_syntaxFacts.IsForEachStatement(subsequentStatement) && + TryProcessForeachStatement(subsequentStatement)) { continue; } - else if (_syntaxFacts.IsIfStatement(extractedChild) && - TryProcessIfStatement((TStatementSyntax)extractedChild)) + else if (_syntaxFacts.IsIfStatement(subsequentStatement) && + TryProcessIfStatement(subsequentStatement)) { continue; }