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

New rule S2166: Classes named like "Exception" should extend "Exception" or a subclass #6727

Merged
merged 21 commits into from Feb 9, 2023

Conversation

zsolt-kolbay-sonarsource
Copy link
Contributor

Copy link
Contributor

@antonioaversa antonioaversa left a comment

Choose a reason for hiding this comment

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

LGTM, just some indenting to fix. The rest are just suggestions.

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using Microsoft.CodeAnalysis.CSharp;
Copy link
Contributor

Choose a reason for hiding this comment

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

This using seems unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Removed it.

if (Language.Syntax.NodeIdentifier(c.Node) is { IsMissing: false } classIdentifier
&& classIdentifier.ValueText.EndsWith("Exception", StringComparison.InvariantCultureIgnoreCase)
&& c.SemanticModel.GetDeclaredSymbol(c.Node) is INamedTypeSymbol { } classSymbol
&& !classSymbol.IsStatic
Copy link
Contributor

Choose a reason for hiding this comment

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

Feel free to ignore this remark if you disagree.

If I understand well, this disables the rule for static classes.

Why would you think it's appropriate, for static classes, to have a name ending in Exception? To me, that seems to violate the principle of least astonishment.

As for addressing the issue in this scenario: while you can't inherit from Exception, you can still rename the class and remove the suffix.

The same reasoning would also apply to Module, in my opinion.

As for struct, enum and record struct: seems OK to me to not consider them in this rule, as it mentions class in its title (although the other languages for which the rule is implemented, namely Java and PHP, don't have to distinguish on such cases).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. I changed the test cases to reflect this.

private readonly VerifierBuilder builderVB = new VerifierBuilder<VB.ClassNamedException>();

[TestMethod]
public void ClassNamedException_CS() => builderCS
Copy link
Contributor

Choose a reason for hiding this comment

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

builderCS should go to the new line.

Same in lines below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved them to new lines.

@Corniel
Copy link
Contributor

Corniel commented Feb 7, 2023

I would suggest to add two fixes: on that removes the suffix, and one that inherits from exception. (That can be a follow-up PR).

c.ReportIssue(Diagnostic.Create(Rule, classIdentifier.GetLocation()));
}
},
AnalyzedSyntaxKinds);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are these not in the Language.SyntaxKinds?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to cover static classes with this rule. In C# both regular classes and static classes are covered by SyntaxKind.ClassDeclaration. In VB.NET the equivalent of static classes are Modules*, so if I want to cover both classes and modules, I need to use SyntaxKind.ClassBlock and SyntaxKind.ModuleBlock. I couldn't come up with any good name for this in Language.SyntaxKinds (ClassOrStaticClassDeclaration?), so I ended up adding it to the rule class itself.
What do you think would be the right name for this declaration?

Thank you for the suggestion, we'll consider it in a follow-up PR.

* there's a nice debate here whether that's actually accurate, but they generate the same IL code, so I consider them equivalent

Copy link
Contributor

Choose a reason for hiding this comment

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

@zsolt-kolbay-sonarsource Modules are a pain in the @$$ indeed. That being said, the C# equivalent also triggers on the declaration of static classes, so why not the VB.NET one?

After all, if you have a base rule both for C# and VB.NET that does not apply on static classes/modules, you need to deal with that anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough. And we might need in the future for other rules which need both C# and VB.NET implementation.
I've added it to Language.SyntaxKind as ClassAndModuleDeclarations.

Copy link
Contributor

@antonioaversa antonioaversa left a comment

Choose a reason for hiding this comment

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

LGTM, just a single comment about empty line.

Approving even though it requires a second review.

After the comment by @Corniel has been addressed, the PR can go to @andrei-epure-sonarsource.


Public Class S2166
Public Class CustomException ' Noncompliant (S2166)

Copy link
Contributor

Choose a reason for hiding this comment

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

This empty line can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed it.

@andrei-epure-sonarsource
Copy link
Contributor

(also please check the minor code smell on SonarCloud)

@@ -29,6 +31,7 @@ internal sealed class CSharpSyntaxKindFacade : ISyntaxKindFacade<SyntaxKind>
SyntaxKindEx.RecordClassDeclaration,
};
public SyntaxKind ClassDeclaration => SyntaxKind.ClassDeclaration;
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: now ClassDeclaration is between ClassAndRecordDeclaration and ClassAndModuleDeclarations, which for me makes it a bit harder to read

Could you move ClassDeclaration above ClassAndRecordDeclaration? (also in interface etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved it.

Copy link
Contributor

Choose a reason for hiding this comment

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

note: by "(also in interface etc)" I meant in all files where this applies

Copy link
Contributor

@andrei-epure-sonarsource andrei-epure-sonarsource left a comment

Choose a reason for hiding this comment

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

LGTM, please address last comments and you can merge after.

@@ -26,6 +26,7 @@ public interface ISyntaxKindFacade<out TSyntaxKind>
abstract TSyntaxKind Attribute { get; }
abstract TSyntaxKind[] ClassAndRecordDeclaration { get; }
abstract TSyntaxKind ClassDeclaration { get; }
Copy link
Contributor

Choose a reason for hiding this comment

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

please move ClassDeclaration above ClassAndRecordDeclaration

@@ -25,6 +25,11 @@ internal sealed class VisualBasicSyntaxKindFacade : ISyntaxKindFacade<SyntaxKind
public SyntaxKind Attribute => SyntaxKind.Attribute;
public SyntaxKind[] ClassAndRecordDeclaration => new[] { SyntaxKind.ClassBlock };
public SyntaxKind ClassDeclaration => SyntaxKind.ClassBlock;
Copy link
Contributor

Choose a reason for hiding this comment

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

please move ClassDeclaration above ClassAndRecordDeclaration

@@ -29,6 +31,7 @@ internal sealed class CSharpSyntaxKindFacade : ISyntaxKindFacade<SyntaxKind>
SyntaxKindEx.RecordClassDeclaration,
};
public SyntaxKind ClassDeclaration => SyntaxKind.ClassDeclaration;
Copy link
Contributor

Choose a reason for hiding this comment

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

note: by "(also in interface etc)" I meant in all files where this applies

.AddPaths("ClassNamedException.vb")
.Verify();

#if NETFRAMEWORK
Copy link
Contributor

Choose a reason for hiding this comment

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

please add an empty line after #if and before #endif

see https://github.com/SonarSource/sonar-dotnet/blob/master/docs/coding-style.md#code-structure

Each compiler directive outside method body (namely #if/#endif) should be preceded and followed by an empty line.

(off-topic - this could be a rule in https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SpacingRules.md)

@sonarcloud
Copy link

sonarcloud bot commented Feb 9, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@sonarcloud
Copy link

sonarcloud bot commented Feb 9, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource merged commit b9f87fd into master Feb 9, 2023
@zsolt-kolbay-sonarsource zsolt-kolbay-sonarsource deleted the Zsolt/S2166-class-named-exception branch February 9, 2023 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New rule S2166: Classes named like "Exception" should extend "Exception" or a subclass
4 participants