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

Improve support for documentation comments in Replace Property with Methods #18243

Merged
merged 6 commits into from
May 8, 2017

Conversation

sharwell
Copy link
Member

@sharwell sharwell commented Mar 28, 2017

  • Expand refactoring test cases to cover docs for generated setters
  • Expand refactoring test cases to cover cref references to the property under refactoring
  • Update refactoring to preserve documentation in cases revealed by new tests

Ask 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.

@sharwell sharwell added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Mar 28, 2017
@sharwell sharwell force-pushed the document-setters branch 2 times, most recently from 75240d7 to 2e213a5 Compare March 28, 2017 21:06
@sharwell sharwell removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Mar 28, 2017
@sharwell
Copy link
Member Author

Tagging @dotnet/roslyn-ide for review


private static bool IsValueName(XmlNameSyntax name)
=> name.Prefix == null &&
name.LocalName.ValueText == "value";
Copy link
Member

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.

Copy link
Member Author

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"));
}
Copy link
Member

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

Copy link
Member Author

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.
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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)));
Copy link
Member

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;
}
Copy link
Member

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)
Copy link
Member

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)

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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) ? "{" : "}";
Copy link
Member

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?

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 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.

Copy link
Member

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'.

Copy link
Member Author

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.

Copy link
Member

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?

Copy link
Member Author

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));
}
Copy link
Member

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);
Copy link
Member

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))
Copy link
Member

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)
Copy link
Member

Choose a reason for hiding this comment

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

here as well.

@sharwell
Copy link
Member Author

@CyrusNajmabadi Rebased to fix the merge conflict, then added c273150 to address the latest comments.

@sharwell
Copy link
Member Author

sharwell commented May 8, 2017

@MattGertz for ask mode

@sharwell sharwell added this to the 15.3 milestone May 8, 2017
@sharwell sharwell merged commit 2f23f3b into dotnet:master May 8, 2017
@sharwell sharwell deleted the document-setters branch May 8, 2017 23:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants