-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Refactoring on inferred tuple names and anonymous type members (VB) #18930
Refactoring on inferred tuple names and anonymous type members (VB) #18930
Conversation
@@ -1827,7 +1827,7 @@ Class C | |||
Const {|Rename:V|} As Integer = 5 | |||
Console.WriteLine(V) | |||
#End ExternalSource | |||
End Sub | |||
End Sub |
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.
Note: This change occurred when I moved complify earlier in the IntroduceVariable logic. I didn't investigate in details.
@@ -392,5 +393,50 @@ where NodeMatchesExpression(originalSemanticModel, currentSemanticModel, syntaxF | |||
.Where(p => p.ContainingSymbol.IsAnonymousFunction()); | |||
return anonymousMethodParameters; | |||
} | |||
|
|||
protected static async Task<(SemanticDocument newSemanticDocument, ISet<TExpressionSyntax> newMatches)> ComplexifyParentingStatements( |
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.
Note: I pulled this method up from the C# derived class. The only change is that ExpressionSyntax
was made generic, using TExpressionSyntax
. #Resolved
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.
nice! #Resolved
|
||
Dim oldOutermostBlock = container | ||
If oldOutermostBlock.IsSingleLineExecutableBlock() Then | ||
oldOutermostBlock = oldOutermostBlock.Parent | ||
End If | ||
|
||
Dim matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken) | ||
|
||
Dim complexified = Await ComplexifyParentingStatements(document, matches, cancellationToken).ConfigureAwait(False) |
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.
Note: Before the change, the complexification was happening after the local was introduced. But that is too late, as we need the original syntax to make names explicit in tuples and anonymous types.
The new flow mirrors the C# implementation of IntroduceVariable. #Resolved
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.
I don't recall why this was done this way in VB. However, matching the flow of C# makes sense to me. #Resolved
@CyrusNajmabadi I'm thinking about what is required to merge the inferred tuple names branch back into master. The crash with IntroduceVariable is probably the biggest issue, but it's also not new. |
Sorry, i'm not sure what this is referring to:
|
@CyrusNajmabadi More context: |
Can you just fix that? |
I should be able to. The only concern is that such fix will become irrelevant once the semantic model is fixed. |
@CyrusNajmabadi That worked. I was debating to put a comment to remove that @DustinCampbell @dotnet/roslyn-ide This PR is ready for review. You will find it very similar to the last one (for C#). Thanks! |
@DustinCampbell @dotnet/roslyn-ide This PR is ready for review. Thanks. |
Sub Main() | ||
Dim a = 1 | ||
Dim t = {|Rename:GetT|}(a) | ||
System.Console.Write(t.a) |
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.
Does this code compile, since the tuple returned by GetT
does not have a
as a member? #Resolved
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.
It won't compile. The refactoring uses VB 15.3 feature, but the project is only VB 15.
My understanding is there is a broader issue to allow making refactorings sensitive to language version. #Resolved
|
||
Dim oldOutermostBlock = container | ||
If oldOutermostBlock.IsSingleLineExecutableBlock() Then | ||
oldOutermostBlock = oldOutermostBlock.Parent | ||
End If | ||
|
||
Dim matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken) | ||
|
||
Dim complexified = Await ComplexifyParentingStatements(document, matches, cancellationToken).ConfigureAwait(False) |
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.
I don't recall why this was done this way in VB. However, matching the flow of C# makes sense to me. #Resolved
@@ -122,7 +139,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification | |||
Return newToken | |||
End Function | |||
|
|||
Protected Function SimplifyExpression(Of TExpression As ExpressionSyntax)( | |||
Protected Function SimplifyExpression(Of TExpression As SyntaxNode)( |
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.
Why was this necessary? It seems a bit weird given the method name, the type parameter name, and the parameter name, expression
.
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.
See corresponding C# implementation of SimplifyExpression. Notice that TExpression
is constrained to SyntaxNode
.
Specifically, the new Reducer (VisualBasicInferredMemberNameReducer.Rewriter
) needs to simplify a SimpleArgumentSyntax
(for tuples) and a NamedFieldInitializerSyntax
(for anonymous types). Copied relevant code below:
Public Overrides Function VisitSimpleArgument(node As SimpleArgumentSyntax) As SyntaxNode
CancellationToken.ThrowIfCancellationRequested()
Dim newNode = MyBase.VisitSimpleArgument(node)
If node.IsParentKind(SyntaxKind.TupleExpression) Then
Return SimplifyExpression(
node,
newNode:=newNode,
simplifier:=AddressOf SimplifyTupleName)
End If
Return newNode
End Function
Public Overrides Function VisitNamedFieldInitializer(node As NamedFieldInitializerSyntax) As SyntaxNode
Dim newNode = MyBase.VisitNamedFieldInitializer(node)
Return SimplifyExpression(
node,
newNode:=newNode,
simplifier:=AddressOf SimplifyNamedFieldInitializer)
End Function
End Class
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.
Then we really need to change the name. SimplifyExpression means to me that it will be getting an expression. I have no problem with you calling this SimplifyExpressionOrSimpleArgumentOrFieldInitializer. Or just having three helpers that each handle a single type.
Thanks @DustinCampbell Do I need to get a second review? |
I'm good with it. @CyrusNajmabadi, did you want to take a look? |
If node.IsParentKind(SyntaxKind.SimpleArgument) AndAlso | ||
node.Parent.IsParentKind(SyntaxKind.TupleExpression) Then | ||
|
||
Return node |
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.
this needs documentation as to why you are explicitly not changing anything in this situatoin. #Resolved
Return node.Parent | ||
End If | ||
|
||
Return Nothing |
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.
this whole method needs commenting to explain what's going on. #Resolved
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.
So, for this one, I'm not really sure. I'll talk to Dustin. #Resolved
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.
newNode:=newNode, | ||
simplifier:=AddressOf SimplifyNamedFieldInitializer) | ||
End Function | ||
|
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.
nit: in general, i do not like extraneous newline between the 'end' statements of VB constructs.
) As SimpleArgumentSyntax | ||
|
||
If node.NameColonEquals Is Nothing OrElse Not node.IsParentKind(SyntaxKind.TupleExpression) Then | ||
Return node |
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.
needs comments.
@dotnet/roslyn-compiler This is the corresponding change for VB to public API change I made last week. It adds |
74122f5
to
47987fb
Compare
47987fb
to
304b908
Compare
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.
Did we get tests for renaming the field being captured by a tuple creation? We've (still 😦) blocked that for anonymous types and a few other places (@dpoeschl knows more), and we might have problems here too.
<Extension> | ||
Public Function TryGetInferredMemberName(expression As ExpressionSyntax) As String | ||
Dim ignore As XmlNameSyntax = Nothing | ||
Dim nameToken As SyntaxToken = expression.ExtractAnonymousTypeMemberName(ignore) |
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.
This will null ref is expression is null.
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.
Added a null check for safety.
@@ -1171,5 +1172,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic | |||
|
|||
Return False | |||
End Function | |||
|
|||
''' <summary> | |||
''' Checks whether the element name Is reserved. |
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.
Not sure why "Is" is capitalized.
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.
Copy and paste from C#, then VB auto-formatting. I'll fix.
Namespace System | ||
Structure ValueTuple(Of T1, T2) | ||
End Structure | ||
End Namespace", TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15)) |
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.
Why aren't we testing with 15.3 then? To be clear, you're OK doing a blanket upgrade of TestOptions.Regular to something higher.
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.
See TestTupleWithInferredNames
above. It uses VB15.3.
node.Parent.IsParentKind(SyntaxKind.TupleExpression) Then | ||
|
||
' Temporaries should not be inlined in the name portion of a named tuple element | ||
' This special case should be removed once https://github.com/dotnet/roslyn/issues/16697 is fixed |
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.
Is fixing #16697 on the docket for this work?
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.
No
BasicReferenceHighlighting.Highlighting failed in both Debug and Release so could be related to the changes. |
''' Checks whether the element name is reserved. | ||
''' | ||
''' For example: | ||
''' "Item3" is reserved (at certain positions). |
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.
What does at certain positions
refer to? It looks like "Item3"
will always return True
.
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.
I'll update the comment. This refers to previous shape of the API (which was returning a position).
<InlineData("M()", "M")> | ||
<InlineData("x.M()", "M")> | ||
<InlineData("TypeOf(x)", Nothing)> | ||
<InlineData("GetType(x)", Nothing)> |
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.
Perhaps test: "Me", "[Me]", "x.Me", "x!y", "-x", "M()()", "New C()"
<InlineData("GetHashCode", True)> | ||
<InlineData("item1", True)> | ||
<InlineData("item10", True)> | ||
<InlineData("Alice", False)> |
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.
"Item01"
Compiler changes LGTM |
APi changes look good. |
Same change as #18726, but for VB.
There are some minor differences: (1) the syntax for anonymous types is a bit different in VB, (2) the identifier comparisons are case-insensitive, and (3) there is no deconstruction in VB.
Note that there is an existing issue with the semantic model on the name of tuple elements in VB (#16697). For instance, in
(i:=i, 2)
, bothi
's are treated as references to the local calledi
.So some InlineTemporary tests are skipped for now.