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

Detect more fluent cases for converting collection expressions #75267

Merged
merged 26 commits into from
Sep 30, 2024

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Sep 26, 2024

Fixes #72699

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner September 26, 2024 20:39
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Sep 26, 2024
using var _ = ArrayBuilder<CollectionExpressionMatch<ArgumentSyntax>>.GetInstance(out var matchesInReverse);
if (!AnalyzeInvocation(text, state, invocation, addMatches ? matchesInReverse : null, out var existingInitializer, cancellationToken))
using var _1 = ArrayBuilder<CollectionExpressionMatch<ArgumentSyntax>>.GetInstance(out var preMatchesInReverse);
using var _2 = ArrayBuilder<CollectionExpressionMatch<ArgumentSyntax>>.GetInstance(out var postMatchesInReverse);
Copy link
Member Author

Choose a reason for hiding this comment

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

the general idea here is that when converting to a collection expr, there is often:

  1. values that should be inserted into the collection expr prior to the values in any existing initializer.
  2. the values from an existing initializer. (note: the initializer is also used to help determine how to format/shape the collection, so we want to pass it along, not convert it into the matches-array)
  3. values taht should be inserted into the collection expr after any values in the xisting initializer.

This PR updates everything to follow this model.

}

// Add the arguments to the pre-matches. They will execute before the initializer values are added.
AddArgumentsInReverse(preMatchesInReverse, objectCreation.ArgumentList.Arguments, useSpread: true);
Copy link
Member Author

Choose a reason for hiding this comment

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

new logic. if the user wrote new List<...>(someValuesToCopy) we'll create a collection expr starting with [.. someValuesToCopy. Any existing initializer values will be added after this. And any more fluent additions will go after that.

@@ -6,7 +6,7 @@

namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression;

/// <inheritdoc cref="Match{TStatementSyntax}"/>
/// <inheritdoc cref="Match"/>
internal readonly record struct CollectionExpressionMatch<TMatchNode>(
Copy link
Member Author

Choose a reason for hiding this comment

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

note: we have a few match structs that are all about the same. I want to unify them in the future.


private static async Task<ExpressionSyntax> GetNewObjectCreationAsync(
Copy link
Member Author

Choose a reason for hiding this comment

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

inlined this method.

@@ -23,7 +23,7 @@ internal partial class CSharpUseCollectionInitializerCodeFixProvider
{
private static BaseObjectCreationExpressionSyntax CreateObjectInitializerExpression(
BaseObjectCreationExpressionSyntax objectCreation,
ImmutableArray<Match<StatementSyntax>> matches)
Copy link
Member Author

Choose a reason for hiding this comment

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

made non-generic. we wanted to be able to pass along either a Statement or Expression now, so i just typed this as SyntaxNode.

@@ -47,13 +47,18 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer<
TVariableDeclaratorSyntax,
TAnalyzer>, new()
{
public readonly record struct AnalysisResult(
ImmutableArray<Match> PreMatches,
ImmutableArray<Match> PostMatches);
Copy link
Member Author

Choose a reason for hiding this comment

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

similarly, we have a few of these floating around. i'd like to get it down to 1.

@@ -57,7 +58,7 @@ private void AnalyzeArrayCreationExpression(SyntaxNodeAnalysisContext context, I
ReportArrayCreationDiagnostics(context, syntaxTree, option.Notification, arrayCreationExpression, changesSemantics);
}

public static ImmutableArray<CollectionExpressionMatch<StatementSyntax>> TryGetMatches(
public static ImmutableArray<CollectionMatch<StatementSyntax>> TryGetMatches(
Copy link
Member Author

Choose a reason for hiding this comment

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

renamed this and replace another type with this type.

@CyrusNajmabadi
Copy link
Member Author

@akhera99 ptal.

@@ -187,7 +199,7 @@ private static bool AnalyzeInvocation(
// left hand side of the expression. In the inner expressions we can have things like `.Concat/.Append`
// calls as the outer expressions will realize the collection.
if (current is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax currentMemberAccess } currentInvocation &&
IsMatch(state, currentMemberAccess, currentInvocation, allowLinq: true, matchesInReverse, out _, cancellationToken))
IsMatch(state, currentMemberAccess, currentInvocation, allowLinq: true, postMatchesInReverse, out _, cancellationToken))
Copy link
Contributor

Choose a reason for hiding this comment

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

IsMatch

I think this would be easier for me to read if the while loop ended after this if block

Copy link
Member Author

Choose a reason for hiding this comment

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

will make that chnage.

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 got much nicer. thanks.

ArrayBuilder<SyntaxNodeOrToken> nodesAndTokens,
string? preferredIndentation,
bool forceTrailingComma)
bool forceTrailingComma,
bool moreToCome)
Copy link
Contributor

Choose a reason for hiding this comment

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

moreToCome

nit: might be nice if this method and AddCommaIfMissing were consistent on using last or moreToCome

Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

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

:shipit:

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 VSCode
Projects
None yet
Development

Successfully merging this pull request may close these issues.

IDE0028/IDE0090/IDE00300/IDE0305 do not catch some expressions
3 participants