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

Rule S4015: Inherited member visibility should not be decreased #399

Merged
merged 6 commits into from
Jun 14, 2017

Conversation

michalb-sonar
Copy link
Contributor

Fix #350

Copy link
Contributor

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

I would rewrite the message.

public sealed class DoNotDecreaseMemberVisibility : SonarDiagnosticAnalyzer
{
internal const string DiagnosticId = "S4015";
private const string MessageFormat = "Make this member non-private or the class sealed.";
Copy link
Contributor

Choose a reason for hiding this comment

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

The message seems weirdo (especially the end part of it).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks ok to me, but happy to adjust. Do you have a suggestion on how to improve?

Copy link
Contributor

Choose a reason for hiding this comment

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

Forget about this comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we say member but care only about methods?

return false;
}

if (classType.BaseType
Copy link
Contributor

Choose a reason for hiding this comment

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

I would extract this from the if condition and make it a meaningful variable.

Copy link
Contributor

@valhristov valhristov left a comment

Choose a reason for hiding this comment

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

LGTM, see comment

private bool HasSameParameters(IMethodSymbol methodCandidate, IMethodSymbol methodSymbol)
{
var methodCandidateParams = methodCandidate.Parameters.ToList();
var methodParams = methodSymbol.Parameters.ToList();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need to copy immutable arrays?

Copy link
Contributor

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

Few more minor changes (we can discuss about the class vs method declaration part).

return false;
}

bool baseClassHasMatchingPublicMethod = classType.BaseType
Copy link
Contributor

Choose a reason for hiding this comment

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

I would use a name like: isHiddingBaseClassMethod

public sealed class DoNotDecreaseMemberVisibility : SonarDiagnosticAnalyzer
{
internal const string DiagnosticId = "S4015";
private const string MessageFormat = "Make this member non-private or the class sealed.";
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we say member but care only about methods?

var methodSymbol = c.SemanticModel.GetDeclaredSymbol(methodDeclaration);
var classType = methodSymbol?.ContainingType;

if (classType != null &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't know why I missed it on first review but here again I would extract the big if into a meaningful variable (isDecreasingMethodAccessibility for example).

c.ReportDiagnostic(Diagnostic.Create(rule, methodDeclaration.Identifier.GetLocation()));
}
},
SyntaxKind.MethodDeclaration);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure it would change a lot about performances but I am wondering if it's not better to subscribe to class declaration so we don't have to walk through all base methods for every sub methods (what is currently done).

using Microsoft.CodeAnalysis.Diagnostics;
using SonarAnalyzer.Common;
using SonarAnalyzer.Helpers;
using System.Collections.Generic;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you really set up the reordering of the using. I am commenting this on every PR xD

{
context.RegisterSyntaxNodeActionInNonGenerated(c =>
{
var classDeclaration = c.Node as ClassDeclarationSyntax;
Copy link
Contributor

Choose a reason for hiding this comment

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

You are sure this is a ClassDeclaration so you should use direct cast and not as.

allBaseClassProperties = allBaseClassMembers.OfType<IPropertySymbol>().ToList();
}

private static IEnumerable<ISymbol> GetAllBaseMembers(INamedTypeSymbol classType, Func<ISymbol, bool> filter)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you have a look at SemanticModel.LookupBaseMembers to see if it does the same thing or not?


if (hidingMethod != null)
{
var location = (memberDeclaration as MethodDeclarationSyntax)?.Identifier.GetLocation();
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a preference so you are free to ignore it. I would extract the as cast into another variable. This makes things easier to read.

var hidingProperty = allBaseClassProperties.FirstOrDefault(p => DecreasesPropertyAccess(p, propertySymbol));
if (hidingProperty != null)
{
var location = (memberDeclaration as PropertyDeclarationSyntax).Identifier.GetLocation();
Copy link
Contributor

Choose a reason for hiding this comment

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

I would also extract this cast into a separate variable. Besides you use as cast but you are not checking for null here. Either it can't be null so you should use direct cast or it can and you should check for it.

return Equals(p1.Type.OriginalDefinition, p2.Type.OriginalDefinition);
}

private static bool DecrasesAccess(Accessibility baseAccess, Accessibility memberAccess)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same remark for the name of the method. Besides you made a typo in the name (Decrases instead of Decreases). There is a spell checker extension for VS you might want to use.

return false;
}

bool hasMatchingParameterTypes = CollectionUtils.AreEqual(baseMethod.Parameters, methodSymbol.Parameters,
Copy link
Contributor

Choose a reason for hiding this comment

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

I would return directly the result of the method call.


private static bool AreParameterTypesEqual(IParameterSymbol p1, IParameterSymbol p2)
{
if (p1.Type.TypeKind == TypeKind.TypeParameter)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would rewrite this method using the ? : operator.
return p1.Type.TypeKind == TypeKind.TypeParameter ? p2.Type.TypeKind == TypeKind.TypeParameter : Equals(p1.Type.OriginalDefinition, p2.Type.OriginalDefinition);


private static bool DecrasesAccess(Accessibility baseAccess, Accessibility memberAccess)
{
if (baseAccess == Accessibility.NotApplicable || memberAccess == Accessibility.NotApplicable)
Copy link
Contributor

Choose a reason for hiding this comment

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

You can merge this if and this return. Besides you can simplify it furthermore because memberAccess == Accessibility.NotApplicable returns false is already covered by memberAccess == Accessibility.Private.


private static bool IsMatchingSignature(IMethodSymbol baseMethod, IMethodSymbol methodSymbol)
{
if (baseMethod.Name != methodSymbol.Name ||
Copy link
Contributor

Choose a reason for hiding this comment

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

I would also merge all the method as a single return with 2 ORs (negate the condition of this IF).

@michalb-sonar michalb-sonar merged commit 38c9aad into master Jun 14, 2017
@michalb-sonar michalb-sonar deleted the s4015 branch June 14, 2017 12:33
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.

3 participants