diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs index f8b95468fae75..a737b733eb273 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 { @@ -92,19 +92,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; @@ -128,36 +115,20 @@ 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 (_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; } 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