-
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
Improve support for documentation comments in Replace Property with Methods #18243
Conversation
75240d7
to
2e213a5
Compare
Tagging @dotnet/roslyn-ide for review |
|
||
private static bool IsValueName(XmlNameSyntax name) | ||
=> name.Prefix == null && | ||
name.LocalName.ValueText == "value"; |
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.
move to CSharpReplacePropertyWithMethodsService since both rewriters need it.
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 get the equivalent one in VB as well.
|
||
return node.ReplaceNode(node.Name, ConvertToParam(node.Name)) | ||
.AddAttributes(SyntaxFactory.XmlNameAttribute("value")); | ||
} |
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:follow pattern of VisitXmlElementEndTag
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 was going to if it (the longer return
statement's expression) fit on one line, but the additional call to AddAttributes
seemed to pass a complexity line where the "light" syntax wasn't feeling so light anymore.
cancellationToken: cancellationToken)); | ||
} | ||
|
||
var setMethod = property.SetMethod; | ||
if (setMethod != null) | ||
{ | ||
// Set-method only gets the leading trivia of the property if we didn't copy | ||
// that trivia to the get-method. |
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.
We need some amount of logic to ensure that we don't copy all trivia from the method to both the getter and the setter. For example of there is a #pp directive on hte method, then it should only be copied to the first generated member.
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.
➡️ Directive trivia, including #region
, results in the analyzer not reporting a diagnostic.
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.
can you comment the code as such to explain that this falls out becuase of that?
|
||
return methodDeclaration; | ||
var leadingTrivia = propertyDeclaration.GetLeadingTrivia(); | ||
return methodDeclaration.WithLeadingTrivia(leadingTrivia.Select(trivia => ConvertTrivia(trivia, documentationCommentRewriter))); |
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.
general nit: wrap lines longer than github width. It makes reviewing easier.
protected override NameMemberCrefSyntax TryGetCrefSyntax(IdentifierNameSyntax identifierName) | ||
{ | ||
return identifierName.Parent as NameMemberCrefSyntax; | ||
} |
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: =>
protected override NameMemberCrefSyntax CreateCrefSyntax(NameMemberCrefSyntax originalCref, SyntaxToken identifierToken, SyntaxNode parameterType) | ||
{ | ||
CrefParameterListSyntax parameterList; | ||
if (parameterType is TypeSyntax) |
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.
if (paramterType is TypeSyntax typeSyntax)
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.
➡️ typeSyntax
is not used if I do this. The cast is on a different value.
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.
On second look, the generic method may eliminate the need for the cast... looking again.
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.
you could also choose to use typeSyntax :)
{ | ||
case SyntaxKind.LessThanToken: | ||
case SyntaxKind.GreaterThanToken: | ||
string newText = rewrittenToken.IsKind(SyntaxKind.LessThanToken) ? "{" : "}"; |
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.
sounds like we're fixing something up after the fact. Is there a reason we're not just generating the right syntax in the first place?
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 source node is generated by SyntaxGenerator.TypeExpression
. If there's an equivalent method which I can use that knows we're in a documentation comment I could use that instead.
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 best way to handle this would be to have an overload that allows the caller to specify they want cref syntax for the type. This method would call into that with '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.
Currently the replacement is implemented for general code in SyntaxFactory.XmlCrefAttribute
. It seems more appropriate to handle it at the point where the CrefSyntax
is created, but that's in the generated code portion. As a workaround, I could use XmlCrefAttribute
to translate the syntax, and then return just the CrefSyntax
it contains.
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.
Sorry, i'm finding the above confusing. Could you clarify what it is you intend to change?
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 removed the current ReplaceBraceTokenForDocumentation
method and just do this instead:
// XmlCrefAttribute replaces <T> with {T}, which is required for C# documentation comments
var crefAttribute = SyntaxFactory.XmlCrefAttribute(
SyntaxFactory.NameMemberCref(SyntaxFactory.IdentifierName(identifierToken), parameterList));
return (NameMemberCrefSyntax)crefAttribute.Cref;
_editor.ReplaceNode( | ||
_cref, | ||
GetCrefReference(_cref)); | ||
} |
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 method seems unnecessary (very simple, called in just one location). Can you just inline?
CrefParameterListSyntax parameterList; | ||
if (parameterType is TypeSyntax typeSyntax) | ||
{ | ||
CrefParameterSyntax parameter = SyntaxFactory.CrefParameter(typeSyntax); |
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: use var.
Dim signature As CrefSignatureSyntax | ||
Dim parameterSyntax = TryCast(parameterType, TypeSyntax) | ||
If parameterSyntax IsNot Nothing Then | ||
signature = SyntaxFactory.CrefSignature(SyntaxFactory.CrefSignaturePart(Nothing, parameterSyntax)) |
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.
named parameters for 'nothing'.
typeReference = qualifiedType.ReplaceNode(qualifiedType.GetLastDottedName(), typeReference) | ||
End If | ||
|
||
Return SyntaxFactory.CrefReference(typeReference, signature, 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.
here as well.
f733ae4
to
c273150
Compare
@CyrusNajmabadi Rebased to fix the merge conflict, then added c273150 to address the latest comments. |
@MattGertz for ask mode |
cref
references to the property under refactoringAsk Mode
Customer scenario
Use the Convert Property to Method refactoring on a property which contains documentation comments.
Bugs this fixes:
#18234 (substantial improvement to previous fix)
Workarounds, if any
Manually convert the property, or fix the comments after the conversion.
Risk
Low, this change includes a substantial number of additional tests and is limited to the refactoring operation behavior.
Performance impact
Negligible. There is no impact except when the user explicitly requests this operation to occur, and is only slower in cases where the behavior was previously incorrect.
Is this a regression from a previous update?
No.
Root cause analysis:
Failure to account for related edge cases when fixing an overly-specific bug report.
How was the bug found?
Manual testing of edge cases related to (but not identical to) a filed bug.