Introduce 'use recursive patterns' refactoring feature #53553
Introduce 'use recursive patterns' refactoring feature #53553CyrusNajmabadi merged 24 commits intodotnet:mainfrom
Conversation
src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs
Outdated
Show resolved
Hide resolved
...res/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs
Outdated
Show resolved
Hide resolved
...ortable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...ortable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs
Show resolved
Hide resolved
...ortable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
...ortable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs
Outdated
Show resolved
Hide resolved
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs
Show resolved
Hide resolved
|
strongly love this. just need a story told through the code to explain what's going on plz. thanks! |
...res/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs
Outdated
Show resolved
Hide resolved
|
@CyrusNajmabadi Ready for review. |
|
|
||
| context.RegisterRefactoring( | ||
| new MyCodeAction( | ||
| "Use recursive patterns", |
There was a problem hiding this comment.
Move to resx for localization?
There was a problem hiding this comment.
Yup. I will get there eventually.
31a6411 to
09f9638
Compare
|
@CyrusNajmabadi I think I've addressed all your feedback. PTAL. |
...res/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs
Outdated
Show resolved
Hide resolved
|
On vacation now. Will do so next week! |
|
A couple of things are intentionally left out for a follow-up:
I think the last two should be done as a reducer to be applied for any simplification run. |
|
tagging @CyrusNajmabadi for review. |
| }; | ||
| } | ||
|
|
||
| if (TryGetCommonReceiver(leftReceiver, rightReceiver, model) is var (commonReceiverOpt, leftNames, rightNames)) |
There was a problem hiding this comment.
so it feels odd that hhis says: TryGetCommonReceiver... but it can return a null common receiver (i.e. commonReceiverOpt), but this is still considered success. can you doc what's going on here?
| { | ||
| var leftSubpattern = CreateSubpattern(leftNames, CreatePattern(leftReceiver, leftTarget, leftFlipped)); | ||
| var rightSubpattern = CreateSubpattern(rightNames, CreatePattern(rightReceiver, rightTarget, rightFlipped)); | ||
| // If the common receiver is null, it's an implicit `this` reference in source. |
There was a problem hiding this comment.
does some code validate that? i.e. that these are actually instance members, and not static members?
| // For instance, `expr && a.b == 1 && a.c == 2` is converted to `expr && a is { b: 1, c: 2 }` | ||
| if (logicalAnd.Left is BinaryExpressionSyntax(LogicalAndExpression) leftExpression) | ||
| replacement = leftExpression.WithRight(replacement); | ||
| return replacement.ConvertToSingleLine().WithAdditionalAnnotations(Formatter.Annotation); |
There was a problem hiding this comment.
this drops trivia... which seems not good.
| private static Func<SyntaxNode, SyntaxNode>? CombineWhenClauseCondition(PatternSyntax switchPattern, ExpressionSyntax condition, SemanticModel model) | ||
| { | ||
| if (TryDetermineReceiver(condition, model, inWhenClause: true) is not var (receiver, target, flipped) || | ||
| TryFindVariableDesignation(switchPattern, receiver, model) is not var (containingPattern, namesOpt)) |
There was a problem hiding this comment.
can you comment these if clauses to state what forms you're looking to match?
|
So my general feedback follows some thigns i've mentione din the past. Namely that the code ends up reading far too cryptically and too cutely. i feel like there's an overemphasis on trying to express thigns in the most compact pattern+tree-tranform form as possible. And i feel like that works because in your head you have a model of the exact tree forms and what you're extracting/combining/reforming. However, it makes the code feel far too dense and unclear as to waht's going on. I'd far prefer a simpler step-by-step recipe-like form where we state what we're looking for, and what we have extracted out, and what we are transforming into. THis is esp. critical to me as it's very hard to otherwise know what's going on, which is important so that reviewer can gauge what might have been missed or what might need work. |
|
@alrz what do you think your next steps will be here? |
I'm not sure exactly what is the request here. I did actually write this in "step-by-step recipe-like form" with a few refactoring to reuse code whenever possible. I have no idea what could be cryptic about that. |
I think part of it is the returning of lambdas that then do the work later. so it's a bit unclear how to distinguish the matching portion from the transform portion. this is not a complaint. it's more an observation that this feels very different from how we generally have shipped refactorigns in the past.
Yes. but not always. For example, if i see: It would be nice to have a general example of what's going on there. -- That said, i think this is fine and i'm going to merge it in :) There were a couple of pieces of feedback not responded to. However, we can see based on if users run into issues with that if we need to do anything here. Thanks much for the awesome contribution :) |
No description provided.