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 S6588 FN: Rule should cover case with epoch ticks #7550

Merged
merged 8 commits into from
Jul 10, 2023

Conversation

cristian-ambrosini-sonarsource
Copy link
Contributor

Fixes #7547

Copy link
Contributor

@zsolt-kolbay-sonarsource zsolt-kolbay-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
Added some polishing comments

var literalsArguments = Language.Syntax.ArgumentExpressions(c.Node).OfType<TLiteralExpression>();
if (!literalsArguments.Any(x => IsValueEqualTo(x, EpochYear) || literalsArguments.Count(x => IsValueEqualTo(x, EpochMonth)) != 2))
var arguments = Language.Syntax.ArgumentExpressions(c.Node);
var literalsArguments = arguments?.OfType<TLiteralExpression>();
Copy link
Contributor

Choose a reason for hiding this comment

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

If arguments can be null then literalsArguments needs to be checked before calling Any() on it in the if statement. Otherwise the ?. must be changed to .

if (type.IsAny(TypesWithUnixEpochField) && IsEpochCtor(c.Node, c.SemanticModel))
else if (arguments.Count() == 1
&& ((literalsArguments.Count() == 1 && IsValueEqualTo(literalsArguments.First(), EpochTicks))
|| (Language.FindConstantValue(c.SemanticModel, arguments.First()) is long ticks && ticks == EpochTicks))
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this extra check is necessary. The previous check is more than enough. If someone gives the Epoch ticks in hexa or binary format, then I think we can live with that 😎

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The previous check is just for the hardcoded number:

_ = new DateTime(621355968000000000); // Noncompliant

while this check is actually looking for constants through the tracker:

private const long EpochTicks = 621355968000000000;
...
_ = new DateTime(EpochTicks); // Noncompliant

var arguments = Language.Syntax.ArgumentExpressions(c.Node);
var literalsArguments = arguments?.OfType<TLiteralExpression>();

if (literalsArguments.Any(x => IsValueEqualTo(x, EpochYear)
Copy link
Contributor

Choose a reason for hiding this comment

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

The two if statements can be merged if you move CheckAndGetTypeName to the end of the conditions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, the conditions are different: the first one is checking whether you have 3 literals (2 with number 1, 1 with number 1970) and then proceeds to check the type and constructor.
The second one is only searching for the constructor with a single argument of 621355968000000000 or pointing at a const with that value, and then proceeds to check semantically the type (not the constructor, since we have only 1 ctor with 1 argument for DateTime/DateTimeOffset).
Although it's feasible to merge everything in a single if statement, all the variants I tried are really cumbersome to read and understand. Happy to discuss it further

var type = c.SemanticModel.GetTypeInfo(c.Node).Type;
if (type.IsAny(TypesWithUnixEpochField) && IsEpochCtor(c.Node, c.SemanticModel))
else if (arguments.Count() == 1
&& ((literalsArguments.Count() == 1 && IsValueEqualTo(literalsArguments.First(), EpochTicks))
Copy link
Contributor

Choose a reason for hiding this comment

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

This can also be done inside the IsEpochCtor method:

|| IsParameterExistingAndLiteralEqualTo("ticks", EpochYear, lookup)

Copy link
Contributor

@csaba-sagi-sonarsource csaba-sagi-sonarsource left a comment

Choose a reason for hiding this comment

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

Left a few nitpick comments. Once you address them I am fine with merging it.

@@ -33,7 +33,8 @@ public abstract class UseUnixEpochBase<TSyntaxKind, TLiteralExpression, TMemberA
where TLiteralExpression : SyntaxNode
where TMemberAccessExpression : SyntaxNode
{
private const int EpochYear = 1970;
private const long EpochTicks = 0x89F7FF5F7B58000;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you change this to hexa? In my opinion it is more understandable in decimal. We use that value more often than hexa numbers.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should go with decimal with underscores: 621_355_968_000_000_000

@@ -33,7 +33,8 @@ public abstract class UseUnixEpochBase<TSyntaxKind, TLiteralExpression, TMemberA
where TLiteralExpression : SyntaxNode
where TMemberAccessExpression : SyntaxNode
{
private const int EpochYear = 1970;
private const long EpochTicks = 0x89F7FF5F7B58000;
private const int EpochYear = 1970; // 621_355_968_000_000_000
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this comment at the year? That is the number of ticks. If we want to add that as a comment it should go with the ticks. However, I think it is not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment was about not forgetting to add once again it in decimal. I failed :D. Thanks for noticing it I'll fix it immediately

@sonarcloud
Copy link

sonarcloud bot commented Jul 10, 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 Jul 10, 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

@cristian-ambrosini-sonarsource cristian-ambrosini-sonarsource deleted the cristian/fix-S6588-FN branch July 10, 2023 12:24
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.

Fix S6588 FN: Rule should cover case with epoch ticks
4 participants