-
Notifications
You must be signed in to change notification settings - Fork 4k
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 feature to allow converting from a tuple to a named-struct. #28257
Conversation
Tagging @jcouv @sharwell @jinujoseph @kuhlenh @dotnet/roslyn-ide Note: not quite ready for review. I will ping when it is. |
{ | ||
refactoringSuggestedActions.Add(new CodeRefactoringSuggestedAction( | ||
_owner, workspace, _subjectBuffer, refactoring.Provider, action)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needed to support refactorings with nested options. Up till now we've never had any of those.
I would not review this until #28066 goes in. This PR depends on a lot of the changes in that PR. So there would be a lot of duplication currently. |
Tagging @jcouv @sharwell @jinujoseph @kuhlenh @dotnet/roslyn-ide This is ready for review. |
} | ||
} | ||
|
||
private bool InfoProbablyContainsTupleFieldNames(SyntaxTreeIndex info, ImmutableArray<string> tupleFieldNames) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InfoProbablyContainsTupleFieldNames [](start = 21, length = 35)
static?
Then maybe callers might be made static too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
}); | ||
} | ||
|
||
private async Task<Solution> ApplyChangesAsync( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static here as well? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
}); | ||
} | ||
|
||
private SeparatedSyntaxList<TArgumentSyntax> ConvertArguments(ISyntaxFactsService syntaxFacts, SyntaxGenerator generator, SeparatedSyntaxList<TArgumentSyntax> arguments) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConvertArguments [](start = 53, length = 16)
One of the two Hum, it's good to double-check, but I think they are both used after all. #ClosedConvertArguments
overloads may be unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both are used. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the second is called by the first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks (iteration 34).
@jcouv Thanks. I will ping when ready to go in! |
test windows_debug_vs-integration_prtest |
@jcouv @ivanbasov this can be merged in now. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with review pass (iteration 38)
@jcouv I don't know what your Traits.cs comment refers to... |
@jcouv i also do not understand the Featuresresources.resx comment... |
I did a diff in CodeFlow between iterations 34 and 38, and saw an addition of: And in the resx, it shows an addition of Not sure what's going on. |
Hum, if I just look at iteration 38, then those additions do not appear. CodeFlow must be confused by the merge from master... LGTM (iteration 38) |
Thanks! |
Note: this is a WIP. There are several parts to complete. But i wanted to send this out for early review.
This is a sibling PR to Convert Anonymous Type to Class and Convert Anonymous Type to Tuple.
it should probably go in once those go in. This feature is most similar to 'Convert Anonymous Type to Class'. However, it has a lot more complexity in it due to the nature of Tuples versus Anonymous-Types. Specifically, Anonymous Types are simpler to manage because their types cannot 'leak' out of the containing method. Indeed, their types cannot actually be uttered in source. Tuples are far different. Their types can spread all over a codebase.
Before continuing on that issue, first let me show a picture of what this looks like:
--
First: note the concept of 'scopes' that the refactoring will apply to. Specifically, when you invoke it, we ask you to let us know how broadly you want us to search for matching types to convert to the new type you're introducing. The scopes are:
This approach gives you control of how wide you want the update to go. This is necessary because it's quite possible to use the same tuple type in several places in a project and want (or not want) to update all those places. For example, one part of a codebase may use it's own
(int x, int y)
tuple in some code. And that type may show up far elsewhere. It's not necessarily the case that when you are updating the first, that you want the other area to be affected.--
Second: Note that the struct we generate has far more parts than the standard anonymous-type-to-class conversion. Specifically, on top of all the standard constructor/Equals/GetHashCode that we generate. We also generate conversion to/from tuples, as well as a Deconstruct method. This allows this type to seamlessly be used even when working with external APIs (or other APIs in your own code) that have not been updated. For example, say you have:
Here we have two distinct tuple types. The one with the names 'x' and 'y' in it, and the anonymous one. If you introduce a type for
(x: 0, y: 1)
this will produce:And this code will continue to work because NewStruct is implicitly convertible to
(int, int)
.--
Third: When replacing, we only replace tuple types that exactly match the starting type. So, if you rename and reassign tuple members in code, we will consdier that a different type that we will not fixup. This is necessary so that we don't end up deciding to replace all 2-tuples in the world any time you're just trying to fixup your particular 2-tuple with your specific names.
--
Finally, there are some caveats here we can't really do anything about (Esp. as analyzers can't do global analysis). For example, if a tuple is used with a
==
expression, that has special meaning in the language that only tuples can support. This means that such code will break when converting to tuples.--
TODO: