-
Notifications
You must be signed in to change notification settings - Fork 468
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
Implement IdentifiersShouldNotContainUnderscoresFixer #3706
Conversation
private static async Task<Document> RenameWithoutUnderscores(Document document, ISymbol symbol, CancellationToken cancellationToken) | ||
{ | ||
Solution newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, symbol, symbol.Name.Replace("_", ""), null, cancellationToken).ConfigureAwait(false); | ||
return newSolution.GetDocument(document.Id); |
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 is written just like this.
But I'm getting a null-reference warning:
Why a warning is emitted here but not there? I can't get the difference.
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.
GetDocument can return a null value if the document ID does not belong to the solution. You should add a !
suppression here. We should consider adding GetRequiredXXX extension methods to our repo similar to the ones in Roslyn: https://github.com/dotnet/roslyn/blob/bc2d6a2597d07a574be4e292f9dbd9c8f975fd7f/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ISolutionExtensions.cs#L36-L68
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.
@mavasani Thanks. I didn't see the !
there 😆
That makes sense now.
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.
Should I add the extension methods in this PR? or leave it as another task?
A small question: why the ISolutionExtensions
is made internal in roslyn? I can't see an obvious problem with exposing these extensions to be public.
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 think there is possible a pending work item to make these public with API review approval. @CyrusNajmabadi do you know?
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.
Should I add the extension methods in this PR? or leave it as another task?
A separate PR might get in quicker.
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 think there is possible a pending work item to make these public with API review approval. @CyrusNajmabadi do you know?
Don't know what we're planning there. It's a pretty awful situation all around. i'd prefer we just break these to throw.
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
@mavasani Any thing left except unit test? |
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
Codecov Report
@@ Coverage Diff @@
## main #3706 +/- ##
=========================================
Coverage 95.54% 95.55%
=========================================
Files 1185 1205 +20
Lines 272465 279213 +6748
Branches 16428 17835 +1407
=========================================
+ Hits 260338 266794 +6456
- Misses 10001 10256 +255
- Partials 2126 2163 +37 |
I think there is something wrong in the way I wrote the test causing it to fail. @mavasani, Can you check please? |
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
CA1707 analyzer uses multiple descriptors with same rule ID (see here), but different messages. So the test framework cannot implicitly deduce which descriptor/message is expected from markup. You need to explicitly provide which descriptor to use, see an example test below: Lines 17 to 36 in 03d8e7d
|
...oft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscoresTests.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...etAnalyzers/Core/Microsoft.CodeQuality.Analyzers/MicrosoftCodeQualityAnalyzersResources.resx
Outdated
Show resolved
Hide resolved
@Evangelink Thanks for your review. 💯 |
|
||
private static async Task<Solution> RenameWithoutUnderscoresAsync(Document document, ISymbol symbol, string newName, CancellationToken cancellationToken) | ||
{ | ||
return await Renamer.RenameSymbolAsync(document.Project.Solution, symbol, newName, null, 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.
Can we just inline this call and avoid an await?
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.
Overall looks good. Please add some more tests to cover all scenarios. Thanks!
@mavasani, I've added an equivalent VB test to the test I previously added. edit: A two possible cases that came to my mind and will likely fail with the current approach are:
Are these the kind of cases you'd like to see? |
The current test failure is due to the identifier being a reserved word after renaming. My_class is renaming to MyClass, which is invalid due to MyClass being a VB keyword. /cc @Evangelink Mentioning as your PR (#3352) was based on renaming too. Did you handle such case? |
@Youssef1313 I am not handling this case so I have the same issue as you do. I would have expected the symbol renamer to handle this case. I can see a couple of implementations to workaround that but let's wait for @mavasani's feedback. |
Sorry for the delay on this one. I've updated it locally to put
However, I see that the input has |
...eQuality.Analyzers/ApiDesignGuidelines/CSharpIdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...eQuality.Analyzers/ApiDesignGuidelines/CSharpIdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Outdated
Show resolved
Hide resolved
public enum DoesNotMatterEnum | ||
{ | ||
{|#2:_EnumWithUnderscore|}, | ||
{|#3:_|} |
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 would probably not report on this case.
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 thought about that at first, but preferred to keep the warning in this case without a code fix.
But after a second thought, it would probably be okay if we don't report on this case. It's really a very edge case. Almost no one will write something like that 😄
@mavasani, would you be okay if we don't report on this case?
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.
Yes, I don't really care if we report a diagnostic on _
or not.
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 the second thought I also think reporting or not are both valid options.
...oft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscoresTests.cs
Outdated
Show resolved
Hide resolved
...oft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscoresTests.cs
Show resolved
Hide resolved
...eQuality.Analyzers/ApiDesignGuidelines/CSharpIdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
@Youssef1313 Let me know if I haven't provided enough info for you to move forward on this PR. |
@Youssef1313 Do you mind if I push a commit on your PR? |
@Evangelink You can push anytime :) Does that require giving you write access on my fork? |
@Youssef1313 Don't bother! I thought I found something to unlock but it's not the case... To sum-up my local changes:
C#: protected override SyntaxNode GetDeclarationNode(SyntaxNode node)
=> node.IsKind(SyntaxKind.IdentifierName)
? node.Parent
: node; VB.NET: Protected Overrides Function GetDeclarationNode(node As SyntaxNode) As SyntaxNode
If node.IsKind(SyntaxKind.IdentifierName) Then
Return node.Parent
Else
Return node
End If
End Function
|
@Evangelink Thanks for the great help you provided here. I opened an issue in dotnet/roslyn for the problem with |
...oft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscoresTests.cs
Show resolved
Hide resolved
What should the expected behavior be for a case like the following (which is far away from a real scenario)? public class My_Class { }
public class My__Class { } Another case that comes to mind also: public class Base
{
public void My_Method() { }
}
public class Derived : Base
{
new public void My_Method() { }
} For the above case, if the user chose to fix all, then it's simple. But if the user chose to fix in only one of them, the "new" keyword should be removed. (I'm not aware of how this would be implemented, nor how it would be tested) |
...oft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscoresTests.cs
Outdated
Show resolved
Hide resolved
Public Class ImplementI1 | ||
Implements I1 | ||
' No diagnostic | ||
Public Event E_ As System.EventHandler Implements I1.E_ | ||
Public Event E2_ As System.EventHandler | ||
Public Event {|#3:E2_|} As System.EventHandler | ||
End Class | ||
|
||
Public Class Derives | ||
Inherits ImplementI1 | ||
|
||
Public Shadows Event {|#4:E2_|} As System.EventHandler |
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.
When renaming E2_
in Derives
class, the new name "E2" is detected as a clashing, most probably because E2
already exists inImplementI1
. However, we indeed want to rename it. It's marked with Shadows and is meant to shadow the member in ImplementI1
.
My opinion is that the analyzer don't report for the "Shadows" case, and RenameSymbolAsync gets it updated when dotnet/roslyn#46663 is fixed.
@mavasani @Evangelink What are your opinions?
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 seems that there is a compiler warning when there is a member shadowing a non-existing member so I think that's fine if the code-fix misses renaming this case.
Tagging @mavasani for confirmation.
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.
Yes, I am fine to keep it as-is for now to reduce the scope of this PR. If required, this can be tackled in a follow-up issue/PR.
@Youssef1313 are you able to fix the tests here? Anything else remaining for this PR? |
@@ -19,7 +19,7 @@ public class IdentifiersShouldNotContainUnderscoresTests | |||
{ | |||
#region CSharp Tests | |||
[Fact] | |||
public async Task CA1707_ForAssembly_CSharp() | |||
public async Task CA1707_ForAssembly_CSharp() // TODO: How to test the code fixer for this? |
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.
Shall we skip the codefix for the assembly level then?
...eQuality.Analyzers/ApiDesignGuidelines/CSharpIdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
...ft.CodeQuality.Analyzers/ApiDesignGuidelines/IdentifiersShouldNotContainUnderscores.Fixer.cs
Show resolved
Hide resolved
Co-authored-by: Amaury Levé <amaury.leve@gmail.com>
@Youssef1313 Could you fix this little conflict and the few open comments? |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
Thanks @Youssef1313 and sorry for the delay in getting this merged. |
No problem. |
Fixes #444