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

Add analyzer/fixer to recommend updating stackalloc expressions to use collection expressions. #69414

Merged

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Aug 5, 2023

Part of #69132.

Followup to #69407. That should be reviewed and go in first.

Supports cases like:

ReadOnlySpan<int> x = stackalloc int[] { 1, 2, 3 };

// And converts it to:
ReadOnlySpan<int> x = [1, 2, 3];

Also supports;

ReadOnlySpan<int> x = stackalloc int[3];
x[0] = a;
x[1] = b;
x[2] = c;

// And converts it to
ReadOnlySpan<int> x = [a, b, c];

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner August 5, 2023 21:09
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Aug 5, 2023
@CyrusNajmabadi CyrusNajmabadi marked this pull request as draft August 5, 2023 21:54
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review August 7, 2023 16:42
@CyrusNajmabadi
Copy link
Member Author

@akhera99 @genlu @Cosifne this is ready for review now that #69407 has gone in.

@@ -45,25 +45,23 @@ public CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer()
}

protected override void InitializeWorker(AnalysisContext context)
=> context.RegisterCompilationStartAction(OnCompilationStart);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review with whitespace off.

this is just a method inline.

context.RegisterSyntaxNodeAction(
context => AnalyzeMemberAccess(context),
SyntaxKind.SimpleMemberAccessExpression);
});
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a method inline.

originalTypeInfo.ConvertedType.OriginalDefinition.Equals(compilation.ReadOnlySpanOfTType());
if (!isOk)
return false;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code is saying: it's ok if using a collection expression would produce Span<T> if the original code was ReadONlySpan<T>. That's because the former is trivially implicitly convertible to the latter, despite being different types.

@@ -588,5 +588,36 @@ static IEnumerable<SyntaxNode> GetElementComponents(StatementSyntax statement)

static StatementSyntax UnwrapEmbeddedStatement(StatementSyntax statement)
=> statement is BlockSyntax { Statements: [var innerStatement] } ? innerStatement : statement;

static ExpressionSyntax ConvertExpression(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this moved from common code to be specific to collection-expressions and specific to colleciton-initializers. it turned out sharing just was not possible. Especially because if you had x[a] = b then collection expressions would add this as just b whereas collection initializers would add it as [a] = b.

Given that, it would be too many contortions to try to share. so i just pulled out for eahc.

@@ -39,7 +39,7 @@ protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic)

public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
RegisterCodeFix(context, CSharpCodeFixesResources.Use_collection_expression, nameof(CSharpCodeFixesResources.Use_collection_expression));
RegisterCodeFix(context, CSharpCodeFixesResources.Use_collection_expression, IDEDiagnosticIds.UseCollectionExpressionForEmptyDiagnosticId);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want different equivalence keys so that we don't wrong the wrong fixers on the wrong diagnostics.

@@ -2123,7 +2123,7 @@ public class Goo
public void M()
{
int lastItem;
List<int> list = [(lastItem = 5)];
List<int> list = [lastItem = 5];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an improvement. the latter is legal in a collection expression (but was not legal in a collection initializer). No longer sharing code between the two improved this.

var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var semanticDocument = await SemanticDocument.CreateAsync(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swithcing to SemanticDOcument moved us from 4 local variables to 1.

semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
semanticDocument = await semanticDocument.WithSyntaxRootAsync(
subEditor.GetChangedRoot(), cancellationToken).ConfigureAwait(false);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only one variable to update versus 4.

@CyrusNajmabadi CyrusNajmabadi merged commit 1505317 into dotnet:main Aug 8, 2023
@ghost ghost added this to the Next milestone Aug 8, 2023
@CyrusNajmabadi CyrusNajmabadi deleted the useCollectionExpressionStackAlloc branch August 8, 2023 22:04
@dibarbet dibarbet modified the milestones: Next, 17.8 P2 Aug 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants