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

Fix S109 FP: named arguments, constructor calls, single-value attributes #4737

Closed
andrei-epure-sonarsource opened this issue Jul 29, 2021 · 13 comments · Fixed by #5247
Closed
Assignees
Labels
Area: C# C# rules related issues. Type: False Positive Rule IS triggered when it shouldn't be.
Milestone

Comments

@andrei-epure-sonarsource
Copy link
Contributor

andrei-epure-sonarsource commented Jul 29, 2021

As an output of this community post: https://community.sonarsource.com/t/s109-magic-numbers-on-attributes/15784/16

And verifying the implementation of the same rule in our Java analyzer: https://github.com/SonarSource/sonar-java/blob/7.1.0.26670/java-checks/src/main/java/org/sonar/java/checks/MagicNumberCheck.java

We want to ignore magic numbers when used in:

  • attributes (still to discuss whether we should consider just well-known values - like Order)
  • in equality-checks or assignments to Count , Size, Length, Order for single-digit integer values
  • enum values

Also consider (maybe have another internal talk) to tolerate:

  • numbers passed to constructors
  • numbers passed to methods with named parameters
@StingyJack
Copy link

StingyJack commented Jul 31, 2021

We want to ignore magic numbers

We want to ignore literal numbers when used in places where the meaning of them is obvious. Literal numbers where the meaning is obscured or hidden or not obvious is what makes them "magic"

This would mean things like using a literal number in a new DateTime(int year, int month, int day) (or one of the other overloads) does not trigger it, because those are not magic numbers. Also things like Timespan.FromSeconds(double value) shouldn't trigger it because the value is obvious. An attribute parameter named "Order" followed by a literal would be obvious.

Magic numbers are magic in any programming language. That Java check seems equally problematic. I'd define a list of identifiers that can hold a literal, something like

private readonly List<string> _allowedLiterals = new List<string>{ "year", "month", "day", "hour", "minute", "second", "tick", "order", etc};

Then when visiting the usage of each literal number usage in the analyzer see if its being used for a parameter that has a name matching a record in the allowed list or if it matches the plural of an allowed list item, or if its the only parameter and the function name is From + one of the allowed literals or its plural.

Another facet not yet discussed was finding things like const int ONE = 1; and flagging those as magic, which would be probably harder or more tedious to derive all of the alphabetical representations of numbers and compare them with the assignment (so it didnt flag const int ONE_YEAR_IN_SECONDS = 31_557_600;

@Corniel
Copy link
Contributor

Corniel commented Aug 17, 2021

I have some suggestions:

I would argue that magic numbers should be ignored when used in creating a static readonly:

class NoMagicNumber
{
    static readonly SomeClass ReadOnlyClass = new SomeClass(1, 2, 3); // Compliant
    static readonly SomeClass ReadOnlyClassChaine = new SomeClass().Add(3); // Complaint
    static readonly SomeClass ReadOnlyFactory = SomeClass.FromInt(1234); // Compliant
}

When extension methods are used to create value types:

class NoMagicNumber
{
    void ExtensionMethods()
    {
        /* struct */ Percentage percentage = 34.5.Percent(); // Compliant
        TimeSpan duration = 12.Seconds(); // Compliant
    }
}

When value types (as struct) are created:

class NoMagicNumber
{
   void ValueTypes()
   {
       var date = new DateOnly(2017, 06, 11); // Compliant
       var duration = TimeSpan.FromMilliseconds(12.4); // Compliant
       var later = DateTime.NowUtc.Add(new TimeSpan(4, 5, 2)); // Compliant
   } 
}

@Corniel
Copy link
Contributor

Corniel commented Aug 18, 2021

Another case that should be excluded: GetHashcode()

class Hash
{
    public int Value1 { get; }
    public string Value2 { get; }

    public override int GetHashCode()
    {
        var hash1 = value?.GetHashCode() ?? 0;
        return Value1 + (hash2 * 1566083941); // Compliant
    }
    
    public static int GetHashCode(object obj)
    {
        var hash = 1;
        foreach (var prop in obj.GetType().GetProperties())
        {
            hash += prop.GetValue(obj).GetHashCode();
            hash *= 17; // Compliant
        }
        return hash;
    }
}

@StingyJack
Copy link

@andrei-epure-sonarsource the list in the OP doesnt meet the minimum need to reduce FP unless all of the items it mentions are included (attributes and parameters). Anything less than that scope and there probably isnt enough value to to enable the rule again.

@cotzo
Copy link

cotzo commented Aug 18, 2021

What about Protobuf code first serialization where you have to put [ProtoMember(number)] and we have to pollute all our model classes with pragma?

@andrei-epure-sonarsource
Copy link
Contributor Author

andrei-epure-sonarsource commented Sep 3, 2021

Anything less than that scope and there probably isnt enough value to to enable the rule again.

@StingyJack - do you mean if we ignore all numbers inside attributes, the rule wouldn't be useful anymore?

What about Protobuf code first serialization where you have to put [ProtoMember(number)] and we have to pollute all our model classes with pragma?

@cotzo - if we'd ignore all attributes altogether, this issue would be solved. Especially if there's only one parameter OR if named parameters are used.


[Internal] We should look at projects on Peach and see what's noisy categories we can emerge from there.

@andrei-epure-sonarsource
Copy link
Contributor Author

andrei-epure-sonarsource commented Sep 3, 2021

@Corniel - good points!

I would argue that magic numbers should be ignored when used in creating a static readonly:

This is doable at syntax level.

When extension methods are used to create value types:
When value types (as struct) are created:

I would avoid adding semantic calls into this rule because it would be quite costly. I would try to keep the improvements just at syntax level, if possible.

@Corniel
Copy link
Contributor

Corniel commented Sep 3, 2021

@Corniel - good points!

I would argue that magic numbers should be ignored when used in creating a static readonly:

This is doable at syntax level.

When extension methods are used to create value types:
When value types (as struct) are created:

I would avoid adding semantic calls into this rule because it would be quite costly. I would try to keep the improvements just at syntax level, if possible.

I agree. 13.Percent() however should be detectable without semantic calls; any method call on a literal should be a candidate for exclusion, I suppose.

Also, a constructor only containing literals is a save guess, I think.

@StingyJack
Copy link

do you mean if we ignore all numbers inside attributes, the rule wouldn't be useful anymore?

@andrei-epure-sonarsource - i mean that all 5 bullet pointed items need to be implemented for this rule. There isnt much value for me in the first three,

@andrei-epure-sonarsource andrei-epure-sonarsource added Type: False Positive Rule IS triggered when it shouldn't be. and removed Type: Improvement labels Nov 9, 2021
@bcrudolp
Copy link

bcrudolp commented Jan 5, 2022

Hi Andrei,

My name is Benjamin, and my team is very interested in the resolution of this issue for a project we are working on right now. We wish to rid the codebase of its SonarLint warnings, but the attribute false positives really make that impossible or senseless for S109.

What is the likely timeline on this, if any?

Warm Regards,
Benjamin R.

@andrei-epure-sonarsource
Copy link
Contributor Author

@bcrudolp I've started working on it, however I'm not sure what your usecase is.

@bcrudolp
Copy link

bcrudolp commented Jan 7, 2022

Hi Andrei,

We are concerned with the false positives induced by attribute values. We have many of those that are simply indices or allowable ranges for settings, etc.

Thanks!
Benjamin

@andrei-epure-sonarsource
Copy link
Contributor Author

yes the attribute cases in handled in: #5247

mary-georgiou-sonarsource pushed a commit that referenced this issue Jan 12, 2022
…age, "From...()" methods and single digit comparisons for well-known properties (#5247)

Fixes #4737
@andrei-epure-sonarsource andrei-epure-sonarsource added this to the 8.34 milestone Jan 12, 2022
@andrei-epure-sonarsource andrei-epure-sonarsource changed the title S109 - reduce false positives Fix S109 FP: named arguments, constructor calls, single-value attributes Jan 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: C# C# rules related issues. Type: False Positive Rule IS triggered when it shouldn't be.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants