Skip to content

Commit

Permalink
Rule S4040: Strings should be normalized to uppercase (#445)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amaury Levé authored Jun 15, 2017
1 parent 48e97b4 commit 67fb53a
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "Nancy\src\Nancy\Extensions\StringExtensions.cs",
"region": {
"startLine": 90,
"startColumn": 55,
"endLine": 90,
"endColumn": 71
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\core\Akka\Actor\Address.cs",
"region": {
"startLine": 42,
"startColumn": 41,
"endLine": 42,
"endColumn": 57
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\core\Akka.Remote\RemoteSettings.cs",
"region": {
"startLine": 25,
"startColumn": 52,
"endLine": 25,
"endColumn": 68
}
}
},
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\core\Akka.Remote\RemoteSettings.cs",
"region": {
"startLine": 26,
"startColumn": 52,
"endLine": 26,
"endColumn": 68
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\examples\Chat\ChatClient\Program.cs",
"region": {
"startLine": 52,
"startColumn": 44,
"endLine": 52,
"endColumn": 60
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\examples\Stocks\SymbolLookup\YahooFinance\StockUriHelper.cs",
"region": {
"startLine": 21,
"startColumn": 85,
"endLine": 21,
"endColumn": 101
}
}
},
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\examples\Stocks\SymbolLookup\YahooFinance\StockUriHelper.cs",
"region": {
"startLine": 26,
"startColumn": 83,
"endLine": 26,
"endColumn": 99
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"issues": [
{
"id": "S4040",
"message": "Change this normalization to 'String.ToUpperInvariant()'.",
"location": {
"uri": "akka.net\src\examples\TimeServer\TimeServer\Program.cs",
"region": {
"startLine": 34,
"startColumn": 29,
"endLine": 34,
"endColumn": 45
}
}
}
]
}
12 changes: 12 additions & 0 deletions sonaranalyzer-dotnet/rspec/cs/S4040_c#.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<p>Certain characters, once normalized to lowercase, cannot make a round trip, meaning that they can not be converted from one locale to another and
then accurately restored to their original characters.</p>
<p>It is therefore strongly recommended to normalize strings to uppercase instead.</p>
<h2>Noncompliant Code Example</h2>
<pre>
String s = myString.ToLower(CultureInfo.InvariantCulture); // Noncompliant
</pre>
<h2>Compliant Solution</h2>
<pre>
String s = myString.ToUpper(CultureInfo.InvariantCulture);
</pre>

13 changes: 13 additions & 0 deletions sonaranalyzer-dotnet/rspec/cs/S4040_c#.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"title": "Strings should be normalized to uppercase",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "2min"
},
"tags": [
"pitfall"
],
"defaultSeverity": "Minor"
}
27 changes: 27 additions & 0 deletions sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/RspecStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6849,6 +6849,33 @@
<data name="S4027_Type" xml:space="preserve">
<value>CODE_SMELL</value>
</data>
<data name="S4040_Category" xml:space="preserve">
<value>Sonar Code Smell</value>
</data>
<data name="S4040_Description" xml:space="preserve">
<value>Certain characters, once normalized to lowercase, cannot make a round trip, meaning that they can not be converted from one locale to another and then accurately restored to their original characters.</value>
</data>
<data name="S4040_IsActivatedByDefault" xml:space="preserve">
<value>False</value>
</data>
<data name="S4040_Remediation" xml:space="preserve">
<value>Constant/Issue</value>
</data>
<data name="S4040_RemediationCost" xml:space="preserve">
<value>2min</value>
</data>
<data name="S4040_Severity" xml:space="preserve">
<value>Minor</value>
</data>
<data name="S4040_Tags" xml:space="preserve">
<value>pitfall</value>
</data>
<data name="S4040_Title" xml:space="preserve">
<value>Strings should be normalized to uppercase</value>
</data>
<data name="S4040_Type" xml:space="preserve">
<value>CODE_SMELL</value>
</data>
<data name="S818_Category" xml:space="preserve">
<value>Sonar Code Smell</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using SonarAnalyzer.Helpers;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace SonarAnalyzer.Rules
{
Expand Down Expand Up @@ -74,7 +74,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext analysisContext)
}
}

private SyntaxToken? GetMethodCallIdentifier(InvocationExpressionSyntax invocation)
protected SyntaxToken? GetMethodCallIdentifier(InvocationExpressionSyntax invocation)
{
var directMethodCall = invocation.Expression as IdentifierNameSyntax;
if (directMethodCall != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2017 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using SonarAnalyzer.Common;
using SonarAnalyzer.Helpers;

namespace SonarAnalyzer.Rules.CSharp
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
[Rule(DiagnosticId)]
public sealed class NormalizeStringsToUppercase : DoNotCallMethodsBase
{
internal const string DiagnosticId = "S4040";
private const string MessageFormat = "Change this normalization to 'String.ToUpperInvariant()'.";

private static readonly DiagnosticDescriptor rule =
DiagnosticDescriptorBuilder.GetDescriptor(DiagnosticId, MessageFormat, RspecStrings.ResourceManager);
protected override DiagnosticDescriptor Rule => rule;

private static readonly List<MethodSignature> checkedMethods = new List<MethodSignature>
{
new MethodSignature(KnownType.System_String, "ToLower"),
new MethodSignature(KnownType.System_String, "ToLowerInvariant"),
};
internal sealed override IEnumerable<MethodSignature> CheckedMethods => checkedMethods;

protected override bool ShouldReportOnMethodCall(InvocationExpressionSyntax invocation,
SemanticModel semanticModel)
{
var identifier = GetMethodCallIdentifier(invocation).Value.ValueText; // never null when we get here
if (identifier == "ToLowerInvariant")
{
return true;
}

return invocation.ArgumentList != null &&
invocation.ArgumentList.Arguments.Count == 1 &&
invocation.ArgumentList.Arguments[0].Expression.ToString() == "CultureInfo.InvariantCulture";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<p>Certain characters, once normalized to lowercase, cannot make a round trip, meaning that they can not be converted from one locale to another and
then accurately restored to their original characters.</p>
<p>It is therefore strongly recommended to normalize strings to uppercase instead.</p>
<h2>Noncompliant Code Example</h2>
<pre>
String s = myString.ToLower(CultureInfo.InvariantCulture); // Noncompliant
</pre>
<h2>Compliant Solution</h2>
<pre>
String s = myString.ToUpper(CultureInfo.InvariantCulture);
</pre>

Original file line number Diff line number Diff line change
Expand Up @@ -4037,7 +4037,7 @@ private static void DetectTypeChanges(ResourceManager resourceManager, IImmutabl
//["4037"],
//["4038"],
//["4039"],
//["4040"],
["4040"] = "CODE_SMELL",
//["4041"],
//["4042"],
//["4043"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2017 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using Microsoft.VisualStudio.TestTools.UnitTesting;
using SonarAnalyzer.Rules.CSharp;

namespace SonarAnalyzer.UnitTest.Rules
{
[TestClass]
public class NormalizeStringsToUppercaseTest
{
[TestMethod]
[TestCategory("Rule")]
public void NormalizeStringsToUppercase()
{
Verifier.VerifyAnalyzer(@"TestCases\NormalizeStringsToUppercase.cs",
new NormalizeStringsToUppercase());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Globalization;

namespace Tests.Diagnostics
{
class Program
{
void Foo()
{
var s1 = "".ToLower(); // Compliant
s1 = "".ToLower(CultureInfo.CurrentCulture);


s1 = "".ToLower(CultureInfo.InvariantCulture); // Noncompliant {{Change this normalization to 'String.ToUpperInvariant()'.}}
// ^^^^^^^
s1 = "".ToLowerInvariant(); // Noncompliant

s1 = Ext.ToLower("", 42);
s1 = "".ToLower(42);
}
}

static class Ext
{
public static string ToLower(this string s, int i) => s;
}
}

0 comments on commit 67fb53a

Please sign in to comment.