Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull out syntax helpers used in 'create collection initializer/collection' into utility types #69526

Merged
merged 2 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionExpression\CSharpUseCollectionExpressionForCreateDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionExpression\CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionExpression\UseCollectionExpressionHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\CSharpUpdateExpressionSyntaxHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\CSharpUseCollectionInitializerAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\CSharpUseCompoundAssignmentDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\CSharpUseCompoundCoalesceAssignmentDiagnosticAnalyzer.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.UseCollectionInitializer;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer;

internal sealed class CSharpUpdateExpressionSyntaxHelper : IUpdateExpressionSyntaxHelper<ExpressionSyntax, StatementSyntax>
{
public static readonly CSharpUpdateExpressionSyntaxHelper Instance = new();

public void GetPartsOfForeachStatement(
StatementSyntax statement,
out SyntaxToken identifier,
out ExpressionSyntax expression,
out IEnumerable<StatementSyntax> statements)
{
var foreachStatement = (ForEachStatementSyntax)statement;
identifier = foreachStatement.Identifier;
expression = foreachStatement.Expression;
statements = ExtractEmbeddedStatements(foreachStatement.Statement);
}

public void GetPartsOfIfStatement(
StatementSyntax statement,
out ExpressionSyntax condition,
out IEnumerable<StatementSyntax> whenTrueStatements,
out IEnumerable<StatementSyntax>? whenFalseStatements)
{
var ifStatement = (IfStatementSyntax)statement;
condition = ifStatement.Condition;
whenTrueStatements = ExtractEmbeddedStatements(ifStatement.Statement);
whenFalseStatements = ifStatement.Else != null ? ExtractEmbeddedStatements(ifStatement.Else.Statement) : null;
}

private static IEnumerable<StatementSyntax> ExtractEmbeddedStatements(StatementSyntax embeddedStatement)
=> embeddedStatement is BlockSyntax block ? block.Statements : SpecializedCollections.SingletonEnumerable(embeddedStatement);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// 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.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.UseCollectionInitializer;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer;

Expand All @@ -16,11 +14,12 @@ internal sealed class CSharpUseCollectionInitializerAnalyzer : AbstractUseCollec
MemberAccessExpressionSyntax,
InvocationExpressionSyntax,
ExpressionStatementSyntax,
ForEachStatementSyntax,
IfStatementSyntax,
VariableDeclaratorSyntax,
CSharpUseCollectionInitializerAnalyzer>
{
protected override IUpdateExpressionSyntaxHelper<ExpressionSyntax, StatementSyntax> SyntaxHelper
=> CSharpUpdateExpressionSyntaxHelper.Instance;

protected override bool IsComplexElementInitializer(SyntaxNode expression)
=> expression.IsKind(SyntaxKind.ComplexElementInitializerExpression);

Expand All @@ -34,29 +33,4 @@ protected override bool HasExistingInvalidInitializerForCollection(BaseObjectCre
Expressions.Count: > 0,
};
}

protected override void GetPartsOfForeachStatement(
ForEachStatementSyntax statement,
out SyntaxToken identifier,
out ExpressionSyntax expression,
out IEnumerable<StatementSyntax> statements)
{
identifier = statement.Identifier;
expression = statement.Expression;
statements = ExtractEmbeddedStatements(statement.Statement);
}

protected override void GetPartsOfIfStatement(
IfStatementSyntax statement,
out ExpressionSyntax condition,
out IEnumerable<StatementSyntax> whenTrueStatements,
out IEnumerable<StatementSyntax>? whenFalseStatements)
{
condition = statement.Condition;
whenTrueStatements = ExtractEmbeddedStatements(statement.Statement);
whenFalseStatements = statement.Else != null ? ExtractEmbeddedStatements(statement.Else.Statement) : null;
}

private static IEnumerable<StatementSyntax> ExtractEmbeddedStatements(StatementSyntax embeddedStatement)
=> embeddedStatement is BlockSyntax block ? block.Statements : SpecializedCollections.SingletonEnumerable(embeddedStatement);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ internal sealed class CSharpUseCollectionInitializerDiagnosticAnalyzer :
MemberAccessExpressionSyntax,
InvocationExpressionSyntax,
ExpressionStatementSyntax,
ForEachStatementSyntax,
IfStatementSyntax,
VariableDeclaratorSyntax,
CSharpUseCollectionInitializerAnalyzer>
{
Expand Down
1 change: 1 addition & 0 deletions src/Analyzers/Core/Analyzers/Analyzers.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\AbstractObjectCreationExpressionAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\AbstractUseCollectionInitializerDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\AbstractUseCollectionInitializerAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\IUpdateExpressionSyntaxHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\UseCollectionInitializerHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\AbstractUseCompoundAssignmentDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\UseCompoundAssignmentUtilities.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer<
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TForeachStatementSyntax,
TIfStatementSyntax,
TVariableDeclaratorSyntax,
TAnalyzer> : AbstractObjectCreationExpressionAnalyzer<
TExpressionSyntax,
Expand All @@ -36,8 +34,6 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer<
where TMemberAccessExpressionSyntax : TExpressionSyntax
where TInvocationExpressionSyntax : TExpressionSyntax
where TExpressionStatementSyntax : TStatementSyntax
where TForeachStatementSyntax : TStatementSyntax
where TIfStatementSyntax : TStatementSyntax
where TVariableDeclaratorSyntax : SyntaxNode
where TAnalyzer : AbstractUseCollectionInitializerAnalyzer<
TExpressionSyntax,
Expand All @@ -46,8 +42,6 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer<
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TForeachStatementSyntax,
TIfStatementSyntax,
TVariableDeclaratorSyntax,
TAnalyzer>, new()
{
Expand All @@ -56,8 +50,7 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer<
protected abstract bool IsComplexElementInitializer(SyntaxNode expression);
protected abstract bool HasExistingInvalidInitializerForCollection(TObjectCreationExpressionSyntax objectCreation);

protected abstract void GetPartsOfForeachStatement(TForeachStatementSyntax statement, out SyntaxToken identifier, out TExpressionSyntax expression, out IEnumerable<TStatementSyntax> statements);
protected abstract void GetPartsOfIfStatement(TIfStatementSyntax statement, out TExpressionSyntax condition, out IEnumerable<TStatementSyntax> whenTrueStatements, out IEnumerable<TStatementSyntax>? whenFalseStatements);
protected abstract IUpdateExpressionSyntaxHelper<TExpressionSyntax, TStatementSyntax> SyntaxHelper { get; }

public static TAnalyzer Allocate()
=> s_pool.Allocate();
Expand Down Expand Up @@ -158,13 +151,13 @@ protected override bool TryAddMatches(ArrayBuilder<Match<TStatementSyntax>> matc
{
continue;
}
else if (extractedChild is TForeachStatementSyntax foreachStatement &&
TryProcessForeachStatement(foreachStatement))
else if (_syntaxFacts.IsForEachStatement(extractedChild) &&
TryProcessForeachStatement((TStatementSyntax)extractedChild))
{
continue;
}
else if (extractedChild is TIfStatementSyntax ifStatement &&
TryProcessIfStatement(ifStatement))
else if (_syntaxFacts.IsIfStatement(extractedChild) &&
TryProcessIfStatement((TStatementSyntax)extractedChild))
{
continue;
}
Expand Down Expand Up @@ -222,13 +215,13 @@ bool TryProcessExpressionStatement(TExpressionStatementSyntax expressionStatemen
return false;
}

bool TryProcessForeachStatement(TForeachStatementSyntax foreachStatement)
bool TryProcessForeachStatement(TStatementSyntax foreachStatement)
{
// if we're not producing a collection expression, then we cannot convert any foreach'es into
// `[..expr]` elements.
if (_analyzeForCollectionExpression)
{
this.GetPartsOfForeachStatement(foreachStatement, out var identifier, out _, out var foreachStatements);
this.SyntaxHelper.GetPartsOfForeachStatement(foreachStatement, out var identifier, out _, out var foreachStatements);
// must be of the form:
//
// foreach (var x in expr)
Expand All @@ -253,7 +246,7 @@ bool TryProcessForeachStatement(TForeachStatementSyntax foreachStatement)
return false;
}

bool TryProcessIfStatement(TIfStatementSyntax ifStatement)
bool TryProcessIfStatement(TStatementSyntax ifStatement)
{
if (!_analyzeForCollectionExpression)
return false;
Expand All @@ -270,7 +263,7 @@ bool TryProcessIfStatement(TIfStatementSyntax ifStatement)
// else
// expr.Add(z)

this.GetPartsOfIfStatement(ifStatement, out _, out var whenTrue, out var whenFalse);
this.SyntaxHelper.GetPartsOfIfStatement(ifStatement, out _, out var whenTrue, out var whenFalse);
var whenTrueStatements = whenTrue.ToImmutableArray();

if (whenTrueStatements is [TExpressionStatementSyntax trueChildStatement] &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ internal abstract partial class AbstractUseCollectionInitializerDiagnosticAnalyz
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TForeachStatementSyntax,
TIfStatementSyntax,
TVariableDeclaratorSyntax,
TAnalyzer>
: AbstractBuiltInCodeStyleDiagnosticAnalyzer
Expand All @@ -50,8 +48,6 @@ internal abstract partial class AbstractUseCollectionInitializerDiagnosticAnalyz
where TMemberAccessExpressionSyntax : TExpressionSyntax
where TInvocationExpressionSyntax : TExpressionSyntax
where TExpressionStatementSyntax : TStatementSyntax
where TForeachStatementSyntax : TStatementSyntax
where TIfStatementSyntax : TStatementSyntax
where TVariableDeclaratorSyntax : SyntaxNode
where TAnalyzer : AbstractUseCollectionInitializerAnalyzer<
TExpressionSyntax,
Expand All @@ -60,8 +56,6 @@ internal abstract partial class AbstractUseCollectionInitializerDiagnosticAnalyz
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TForeachStatementSyntax,
TIfStatementSyntax,
TVariableDeclaratorSyntax,
TAnalyzer>, new()
{
Expand Down Expand Up @@ -266,7 +260,7 @@ private void FadeOutCode(
properties));
}
}
else if (match is TForeachStatementSyntax)
else if (syntaxFacts.IsForEachStatement(match))
{
// For a `foreach (var x in expr) ...` statement, fade out the parts before and after `expr`.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Collections.Generic;

namespace Microsoft.CodeAnalysis.UseCollectionInitializer;

internal interface IUpdateExpressionSyntaxHelper<
TExpressionSyntax,
TStatementSyntax>
where TExpressionSyntax : SyntaxNode
where TStatementSyntax : SyntaxNode
{
void GetPartsOfForeachStatement(TStatementSyntax statement, out SyntaxToken identifier, out TExpressionSyntax expression, out IEnumerable<TStatementSyntax> statements);
void GetPartsOfIfStatement(TStatementSyntax statement, out TExpressionSyntax condition, out IEnumerable<TStatementSyntax> whenTrueStatements, out IEnumerable<TStatementSyntax>? whenFalseStatements);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ internal abstract class AbstractUseCollectionInitializerCodeFixProvider<
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TForeachStatementSyntax,
TIfStatementSyntax,
TVariableDeclaratorSyntax,
TAnalyzer>, new()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer
MemberAccessExpressionSyntax,
InvocationExpressionSyntax,
ExpressionStatementSyntax,
ForEachStatementSyntax,
IfStatementSyntax,
VariableDeclaratorSyntax,
VisualBasicCollectionInitializerAnalyzer)

Protected Overrides Sub GetPartsOfForeachStatement(statement As ForEachStatementSyntax, ByRef identifier As SyntaxToken, ByRef expression As ExpressionSyntax, ByRef statements As IEnumerable(Of StatementSyntax))
' Only called for collection expressions, which VB does not support
Throw ExceptionUtilities.Unreachable()
End Sub

Protected Overrides Sub GetPartsOfIfStatement(statement As IfStatementSyntax, ByRef condition As ExpressionSyntax, ByRef whenTrueStatements As IEnumerable(Of StatementSyntax), ByRef whenFalseStatements As IEnumerable(Of StatementSyntax))
' Only called for collection expressions, which VB does not support
Throw ExceptionUtilities.Unreachable()
End Sub
Protected Overrides ReadOnly Property SyntaxHelper As IUpdateExpressionSyntaxHelper(Of ExpressionSyntax, StatementSyntax) =
VisualBasicUpdateExpressionSyntaxHelper.Instance

Protected Overrides Function IsComplexElementInitializer(expression As SyntaxNode) As Boolean
' Only called for collection expressions, which VB does not support
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.

Imports Microsoft.CodeAnalysis.UseCollectionInitializer
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax

Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer
Friend NotInheritable Class VisualBasicUpdateExpressionSyntaxHelper
Implements IUpdateExpressionSyntaxHelper(Of ExpressionSyntax, StatementSyntax)

Public Shared ReadOnly Instance As New VisualBasicUpdateExpressionSyntaxHelper()

Public Sub GetPartsOfForeachStatement(statement As StatementSyntax, ByRef identifier As SyntaxToken, ByRef expression As ExpressionSyntax, ByRef statements As IEnumerable(Of StatementSyntax)) Implements IUpdateExpressionSyntaxHelper(Of ExpressionSyntax, StatementSyntax).GetPartsOfForeachStatement
' Only called for collection expressions, which VB does not support
Throw ExceptionUtilities.Unreachable()
End Sub

Public Sub GetPartsOfIfStatement(statement As StatementSyntax, ByRef condition As ExpressionSyntax, ByRef whenTrueStatements As IEnumerable(Of StatementSyntax), ByRef whenFalseStatements As IEnumerable(Of StatementSyntax)) Implements IUpdateExpressionSyntaxHelper(Of ExpressionSyntax, StatementSyntax).GetPartsOfIfStatement
' Only called for collection expressions, which VB does not support
Throw ExceptionUtilities.Unreachable()
End Sub
End Class
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer
MemberAccessExpressionSyntax,
InvocationExpressionSyntax,
ExpressionStatementSyntax,
ForEachStatementSyntax,
IfStatementSyntax,
VariableDeclaratorSyntax,
VisualBasicCollectionInitializerAnalyzer)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<Compile Include="$(MSBuildThisFileDirectory)UseCoalesceExpression\VisualBasicUseCoalesceExpressionForTernaryConditionalCheckDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCoalesceExpression\VisualBasicUseCoalesceExpressionForNullableTernaryConditionalCheckDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\VisualBasicCollectionInitializerAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\VisualBasicUpdateExpressionSyntaxHelper.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\VisualBasicUseCollectionInitializerDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\Utilities.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UseCompoundAssignment\VisualBasicUseCompoundAssignmentDiagnosticAnalyzer.vb" />
Expand Down