From 80811f9a76a65c92e4c32cb434094f52db79ed5b Mon Sep 17 00:00:00 2001 From: Zsolt Kolbay <121798625+zsolt-kolbay-sonarsource@users.noreply.github.com> Date: Thu, 30 May 2024 15:57:03 +0200 Subject: [PATCH] Fix S6964 FP: Properties decorated with the [BindNever] attribute (#9361) --- analyzers/rspec/cs/S6964.html | 22 ++++++++++++++----- .../Rules/AspNet/AvoidUnderPosting.cs | 10 +++++---- .../SonarAnalyzer.Common/Helpers/KnownType.cs | 1 + .../TestCases/AspNet/AvoidUnderPosting.cs | 21 ++++++++++++++++++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/analyzers/rspec/cs/S6964.html b/analyzers/rspec/cs/S6964.html index 026d6cbcdc2..503fb1e0722 100644 --- a/analyzers/rspec/cs/S6964.html +++ b/analyzers/rspec/cs/S6964.html @@ -20,14 +20,24 @@

Why is this an issue?

}

Exceptions

-

This rule does not raise an issue when:

+

This rule does not raise an issue when properties are decorated with the following attributes:

+

Additionally, this rule does not raise for properties in model classes that are not in the same project as the Controller class that references +them. This is due to a limitation of Roslyn (see here).

How to fix it

You should mark any model value-type property as nullable, IgnoredAttributes = ImmutableArray.Create( - KnownType.System_Text_Json_Serialization_JsonIgnoreAttribute, - KnownType.System_Text_Json_Serialization_JsonRequiredAttribute, + KnownType.Microsoft_AspNetCore_Mvc_ModelBinding_BindNeverAttribute, KnownType.Newtonsoft_Json_JsonIgnoreAttribute, KnownType.Newtonsoft_Json_JsonRequiredAttribute, - KnownType.System_ComponentModel_DataAnnotations_RangeAttribute); + KnownType.System_ComponentModel_DataAnnotations_RangeAttribute, + KnownType.System_Text_Json_Serialization_JsonIgnoreAttribute, + KnownType.System_Text_Json_Serialization_JsonRequiredAttribute); public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); @@ -157,7 +158,8 @@ private static IEnumerable RelatedTypesToExamine(ITypeSymbol t IArrayTypeSymbol array => RelatedTypesToExamine(array.ElementType, controllerType), INamedTypeSymbol collection when collection.DerivesOrImplements(KnownType.System_Collections_Generic_IEnumerable_T) => collection.TypeArguments.SelectMany(x => RelatedTypesToExamine(x, controllerType)), - INamedTypeSymbol namedType when type.IsInSameAssembly(controllerType) => [namedType], + INamedTypeSymbol namedType when type.IsInSameAssembly(controllerType) && !type.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_ModelBinding_BindNeverAttribute) => + [namedType], _ => [] }; diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs index 4c0d9187b3c..e7e27702090 100644 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs +++ b/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs @@ -101,6 +101,7 @@ public sealed partial class KnownType public static readonly KnownType Microsoft_AspNetCore_Mvc_IActionResult = new("Microsoft.AspNetCore.Mvc.IActionResult"); public static readonly KnownType Microsoft_AspNetCore_Mvc_IgnoreAntiforgeryTokenAttribute = new("Microsoft.AspNetCore.Mvc.IgnoreAntiforgeryTokenAttribute"); public static readonly KnownType Microsoft_AspNetCore_Mvc_Infrastructure_ActionResultObjectValueAttribute = new("Microsoft.AspNetCore.Mvc.Infrastructure.ActionResultObjectValueAttribute"); + public static readonly KnownType Microsoft_AspNetCore_Mvc_ModelBinding_BindNeverAttribute = new("Microsoft.AspNetCore.Mvc.ModelBinding.BindNeverAttribute"); public static readonly KnownType Microsoft_AspNetCore_Mvc_ModelBinding_ModelStateDictionary = new("Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"); public static readonly KnownType Microsoft_AspNetCore_Mvc_ModelBinding_Validation_ValidateNeverAttribute = new("Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidateNeverAttribute"); public static readonly KnownType Microsoft_AspNetCore_Mvc_NonActionAttribute = new("Microsoft.AspNetCore.Mvc.NonActionAttribute"); diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/AvoidUnderPosting.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/AvoidUnderPosting.cs index f7bdf1236b5..5ebf70d2fd9 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/AvoidUnderPosting.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/AvoidUnderPosting.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Newtonsoft.Json; using System.Text.Json.Serialization; @@ -314,3 +315,23 @@ public bool IsProperty // Noncompliant set; } } + +namespace UsingBindNeverAttribute +{ + public class ModelWithBindNeverProperty + { + [BindNever] public int ValueProperty { get; set; } + } + + [BindNever] + public class EntireModelWithBindNeverAttribute + { + public int ValueProperty { get; set; } + } + + public class CustomController : Controller + { + [HttpGet] public IActionResult Get(ModelWithBindNeverProperty model) => View(model); + [HttpPost] public IActionResult Post(EntireModelWithBindNeverAttribute model) => View(model); + } +}