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 S2234 FN nullable argument value #3880

Closed

Conversation

H4pH
Copy link

@H4pH H4pH commented Dec 30, 2020

Fixes #3879

Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

Hi @H4pH, thank you for the contribution. I left some comments to address.

Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

Final polishing

@pavel-mikula-sonarsource
Copy link
Contributor

/azp run Sonar.Net.External

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@pavel-mikula-sonarsource
Copy link
Contributor

Hi @H4pH, CI run failed on .NET Integration tests and that's actually a good thing - new issue was found in akka.net project. To address this situation, please:

  • run analyzers\its\regression-test.ps1 -ruleId S2234 -project akka.net
  • run analyzers\its\update-expected.ps1 -project akka.net
  • commit the json file that will be added/changed

@H4pH
Copy link
Author

H4pH commented Feb 2, 2021

Hi @pavel-mikula-sonarsource, I tried running your script but it fails when processing the results:

================================================
Initializing the environment
================================================
Initializing the actual issues folder with the expected result
Removing existing folder 'actual'
Initializing the output folder
Removing existing folder 'output'
Running ITs with only rule S2234 turned on.
The rule set we use is .\output\AllSonarAnalyzerRules.ruleset.
Build skipped: AnalyzeGenerated
Build skipped: AnalyzeGeneratedVb

================================================
Restoring NuGet packages for Akka.sln
================================================
Trying to find 'msbuild.exe' using 'MSBUILD_PATH' environment variable
Using Msbuild from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin'.
Все пакеты, перечисленные в packages.config, уже установлены.
Using Msbuild from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin'.
Все пакеты, перечисленные в packages.config, уже установлены.

================================================
Building solution Akka.sln
================================================
Trying to find 'msbuild.exe' using 'MSBUILD_PATH' environment variable
Microsoft (R) Build Engine версии 16.8.3+39993bd9d для .NET Framework
(C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены.


Сборка успешно завершена.
    Предупреждений: 145
    Ошибок: 0

Прошло времени 00:00:50.33
Microsoft (R) Build Engine версии 16.8.3+39993bd9d для .NET Framework
(C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены.


Сборка успешно завершена.
    Предупреждений: 145
    Ошибок: 0

Прошло времени 00:00:50.33
Build skipped: Automapper
Build skipped: Ember-MM
Build skipped: ManuallyAddedNoncompliantIssues
Build skipped: ManuallyAddedNoncompliantIssuesVB
Build skipped: Nancy
Build skipped: SkipGenerated
Build skipped: SkipGeneratedVb
Build skipped: NetCore31
Build skipped: Net5

================================================
Processing analyzer results
================================================
Check differences for internal projects
Normalizing the SARIF reports
Could not load type 'System.Web.UI.WebResourceAttribute' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
System.TypeLoadException: Could not load type 'System.Web.UI.WebResourceAttribute' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
   at System.ModuleHandle.ResolveType(QCallModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
   at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctorWithParameters, Boolean& isVarArg)
   at System.Reflection.CustomAttribute.AddCustomAttributes(ListBuilder`1& attributes, RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1 derivedAttributes)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType)
   at System.Reflection.RuntimeAssembly.GetCustomAttributes(Type attributeType, Boolean inherit)
   at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit)
   at System.Reflection.CustomAttributeExtensions.GetCustomAttributes(Assembly element, Type attributeType)
   at System.Management.Automation.Language.PSInvokeMemberBinder.InvokeDotNetMethod(CallInfo callInfo, String name, PSMethodInvocationConstraints psMethodInvocationConstraints, MethodInvocationType methodInvocationType, DynamicMetaObject target, DynamicMetaObject[] args, BindingRestrictions restrictions, MethodInformation[] mi, Type errorExceptionType)
   at System.Management.Automation.Language.PSInvokeMemberBinder.FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
   at System.Dynamic.InvokeMemberBinder.FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args)
   at System.Management.Automation.PSObject.PSDynamicMetaObject.BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
   at System.Dynamic.InvokeMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
   at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
   at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at GetActualIssues, C:\Users\User\Documents\GitHub\sonar-dotnet-local\analyzers\its\create-issue-reports.ps1: line 65
at New-IssueReports, C:\Users\User\Documents\GitHub\sonar-dotnet-local\analyzers\its\create-issue-reports.ps1: line 122
at <ScriptBlock>, C:\Users\User\Documents\GitHub\sonar-dotnet-local\analyzers\its\regression-test.ps1: line 505
at <ScriptBlock>, C:\Users\User\Documents\GitHub\sonar-dotnet-local\analyzers\its\regression-test.ps1: line 505
at <ScriptBlock>, <No file>: line 1

@pavel-mikula-sonarsource
Copy link
Contributor

@H4pH, Ah OK, please address the comments and I'll run it afterwards and provide a commit to deal with it.

@pavel-mikula-sonarsource
Copy link
Contributor

Hi @H4pH,

will you have time to finish this PR? It was close to being merged.

@H4pH
Copy link
Author

H4pH commented Sep 13, 2021

Hi @H4pH,

will you have time to finish this PR? It was close to being merged.

Hi, @pavel-mikula-sonarsource,
finally I've found a time and was able to handle all test cases, let's finish with this

@pavel-mikula-sonarsource
Copy link
Contributor

Hi @H4pH, thanks for taking a look. I'll try to check it next week. Can you please rebase your PR meanwhile? There's a merge conflict.

@H4pH
Copy link
Author

H4pH commented Sep 28, 2021

Hi @H4pH, thanks for taking a look. I'll try to check it next week. Can you please rebase your PR meanwhile? There's a merge conflict.

i've done it, but now github shows all commits from master as PR commits :(

@pavel-mikula-sonarsource
Copy link
Contributor

Something went wrong, it looks that you've merged master into your branch instead of rebasing on top of `master. This should fix it:

  • Checkout S2234-fn-nullable-argument-value
  • In VS Git Repository tab: right clickon master branch and choose Rebase S2234-fn-nullable-argument-value onto master
  • Solve rebase conflicts
  • Push changes.

In local commit history, you should see your PR commits on top of master tag.

@H4pH H4pH force-pushed the S2234-fn-nullable-argument-value branch from ed21c18 to 4bd6a1f Compare November 16, 2021 17:34
@H4pH
Copy link
Author

H4pH commented Jan 10, 2022

Hi @pavel-mikula-sonarsource, congratulations on the first year of my pull request :)
Are there any more changes required?

Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

Hi @H4pH, I'll try to prioritize this PR now.

Comment on lines +133 to +136
bool IdentifierWithSameNameAndTypeExistsLater(ArgumentIdentifier argumentIdentifier, int index) =>
argumentIdentifiers.Skip(index + 1)
.Any(ia => string.Equals(ia.IdentifierName, argumentIdentifier.IdentifierName, StringComparison.OrdinalIgnoreCase)
&& ArgumentTypesAreSame(ia.ArgumentSyntax, argumentIdentifier.ArgumentSyntax));
Copy link
Contributor

Choose a reason for hiding this comment

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

What was the motivation for having this method? AFAICT it prevents the issue from being raised twice when arguments are swapped. For sake of simplicity, I'd say it's fine to raise twice and we can remove this check.

Copy link
Author

Choose a reason for hiding this comment

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

Without this method there is different result for same test. Example is passing one var to both params, see TestCases\ParametersCorrectOrder.cs line 97 and 101. (pass "a" and "b" to both params of m(int a, int b))
I think, that if argument was passed at correct place once, we shouldn't rise

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, that makes sense. And at the same time, if b was passed to both, we would have an equal scenario and we would raise and we shouldn't, right?
So we need to know if the argument was passed on the correct location at least once (no matter if before or after). This sounds complicated to do in a clean way to me. To keep this PR focused, I would be fine with creating a new issue for that case, fix it in another PR and here just document those two cases m(a, a) and m(b, b) as ' Noncompliant FP with a link to that new issue.

Comment on lines +106 to +114
private static SyntaxToken? GetValueAccessIdentifier(MemberAccessExpressionSyntax expression, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext) =>
expression.Name.ToString() == "Value" && IsNullableValueAccess(expression, syntaxNodeAnalysisContext)
? GetExpressionSyntaxIdentifier(expression.Expression, syntaxNodeAnalysisContext)
: expression.Name.Identifier;

private static bool IsNullableValueAccess(MemberAccessExpressionSyntax expression, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext)
{
var typeInfo = syntaxNodeAnalysisContext.SemanticModel.GetTypeInfo(expression.Expression);
var type = typeInfo.ConvertedType;
var nullableT = syntaxNodeAnalysisContext.Compilation.GetTypeByMetadataName(typeof(Nullable<>).FullName);
return type.OriginalDefinition.DerivesOrImplements(nullableT);
}
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 be simplified a lot using the KnownType.

You actually don't need SyntaxNodeAnalysisContext and using SemanticModel model everywhere is enough.

Suggested change
private static SyntaxToken? GetValueAccessIdentifier(MemberAccessExpressionSyntax expression, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext) =>
expression.Name.ToString() == "Value" && IsNullableValueAccess(expression, syntaxNodeAnalysisContext)
? GetExpressionSyntaxIdentifier(expression.Expression, syntaxNodeAnalysisContext)
: expression.Name.Identifier;
private static bool IsNullableValueAccess(MemberAccessExpressionSyntax expression, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext)
{
var typeInfo = syntaxNodeAnalysisContext.SemanticModel.GetTypeInfo(expression.Expression);
var type = typeInfo.ConvertedType;
var nullableT = syntaxNodeAnalysisContext.Compilation.GetTypeByMetadataName(typeof(Nullable<>).FullName);
return type.OriginalDefinition.DerivesOrImplements(nullableT);
}
private static SyntaxToken? GetValueAccessIdentifier(MemberAccessExpressionSyntax expression, SemanticModel model) =>
expression.Name.ToString() == "Value" && model.GetTypeInfo(expression.Expression).ConvertedType.DerivesOrImplements(KnownType.System_Nullable_T)
? GetExpressionSyntaxIdentifier(expression.Expression, model)
: expression.Name.Identifier;

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for VB

@pavel-mikula-sonarsource
Copy link
Contributor

/azp run Sonar.Net

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@sonarcloud
Copy link

sonarcloud bot commented Jan 21, 2022

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 Jan 21, 2022

SonarCloud Quality Gate failed.    Quality Gate failed

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

94.8% 94.8% Coverage
13.3% 13.3% Duplication

@pavel-mikula-sonarsource
Copy link
Contributor

pavel-mikula-sonarsource commented Jan 21, 2022

IT results have changed, please rerun the PowerShell scripts again to update the JSON as described above after your changes.

@@ -87,10 +88,32 @@ protected override void Initialize(SonarAnalysisContext context)
protected override Location GetMethodDeclarationIdentifierLocation(SyntaxNode syntaxNode) =>
(syntaxNode as BaseMethodDeclarationSyntax)?.FindIdentifierLocation();

protected override SyntaxToken? GetArgumentIdentifier(ArgumentSyntax argument) =>
(argument.Expression as IdentifierNameSyntax)?.Identifier;
protected override SyntaxToken? GetArgumentIdentifier(ArgumentSyntax argument, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext) => GetExpressionSyntaxIdentifier(argument?.Expression, syntaxNodeAnalysisContext);
Copy link
Contributor

Choose a reason for hiding this comment

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

The body should be on the next line, it will also fix the issue about too long line

Suggested change
protected override SyntaxToken? GetArgumentIdentifier(ArgumentSyntax argument, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext) => GetExpressionSyntaxIdentifier(argument?.Expression, syntaxNodeAnalysisContext);
protected override SyntaxToken? GetArgumentIdentifier(ArgumentSyntax argument, SyntaxNodeAnalysisContext syntaxNodeAnalysisContext) =>
GetExpressionSyntaxIdentifier(argument?.Expression, syntaxNodeAnalysisContext);

Nikolay Musikhin added 5 commits July 20, 2022 14:30
- VB.NET implementation
- more cases and tests
- added better nullable recognising
- added better same arguments check
@cristian-ambrosini-sonarsource
Copy link
Contributor

This Pull Request, along with the subsequent one #6748, has been decided to be closed as we are preparing to merge PR #8238.
The original implementation has been entirely rewritten, as detailed in the PR description, rendering the modifications in this PR incompatible with the new structure. #3879 will remain open and will be fixed as soon as possible. Nullable value types are just one of the many conversions that the rule does not support, the proposed solution will be to write a helper to cover them all.

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.

Improve S2234: Detect nullable values
3 participants