diff --git a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpUseToLowerInvariantOrToUpperInvariant.cs b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpUseToLowerInvariantOrToUpperInvariant.cs
new file mode 100644
index 0000000000..ff46b091bb
--- /dev/null
+++ b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpUseToLowerInvariantOrToUpperInvariant.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Diagnostics;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.NetCore.Analyzers.Runtime;
+
+namespace Microsoft.NetCore.CSharp.Analyzers.Runtime
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class CSharpUseToLowerInvariantOrToUpperInvariantAnalyzer : UseToLowerInvariantOrToUpperInvariantAnalyzer
+ {
+ protected override Location GetMethodNameLocation(SyntaxNode invocationNode)
+ {
+ Debug.Assert(invocationNode.IsKind(SyntaxKind.InvocationExpression));
+
+ var invocation = (InvocationExpressionSyntax)invocationNode;
+ if (invocation.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression))
+ {
+ return ((MemberAccessExpressionSyntax)invocation.Expression).Name.GetLocation();
+ }
+ else if (invocation.Expression.IsKind(SyntaxKind.ConditionalAccessExpression))
+ {
+ return ((ConditionalAccessExpressionSyntax)invocation.Expression).WhenNotNull.GetLocation();
+ }
+ return invocation.GetLocation();
+ }
+ }
+}
diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
index 4815e2ae1b..4a36082401 100644
--- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
+++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
@@ -4,6 +4,7 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
+CA1311 | Globalization | Hidden | UseToLowerInvariantOrToUpperInvariant, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1311)
CA1849 | Performance | Disabled | UseAsyncMethodInAsyncContext, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1849)
CA5404 | Security | Disabled | DoNotDisableTokenValidationChecks, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca5404)
CA5405 | Security | Disabled | DoNotAlwaysSkipTokenValidationInDelegates, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca5405)
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
index 5240c979e4..b86f870407 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
@@ -1822,4 +1822,10 @@
'{0}' uses the preview type '{1}' and needs to opt into preview features. See {2} for more information.
+
+ Use an invariant version
+
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
\ No newline at end of file
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariant.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariant.cs
new file mode 100644
index 0000000000..e5fc80f4ed
--- /dev/null
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariant.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Immutable;
+using Analyzer.Utilities;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.NetAnalyzers;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace Microsoft.NetCore.Analyzers.Runtime
+{
+ using static MicrosoftNetCoreAnalyzersResources;
+
+ public abstract class UseToLowerInvariantOrToUpperInvariantAnalyzer : AbstractGlobalizationDiagnosticAnalyzer
+ {
+ internal const string RuleId = "CA1311";
+
+ private static readonly LocalizableString s_localizableMessageAndTitle = CreateLocalizableResourceString(nameof(UseToLowerInvariantOrToUpperInvariantTitle));
+
+ internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
+ RuleId,
+ s_localizableMessageAndTitle,
+ s_localizableMessageAndTitle,
+ DiagnosticCategory.Globalization,
+ RuleLevel.IdeHidden_BulkConfigurable,
+ description: CreateLocalizableResourceString(nameof(UseToLowerInvariantOrToUpperInvariantDescription)),
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ internal const string ToLowerMethodName = "ToLower";
+ internal const string ToUpperMethodName = "ToUpper";
+ protected abstract Location GetMethodNameLocation(SyntaxNode invocationNode);
+
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
+
+ protected override void InitializeWorker(CompilationStartAnalysisContext context)
+ {
+ context.RegisterOperationAction(operationContext =>
+ {
+ var operation = (IInvocationOperation)operationContext.Operation;
+ IMethodSymbol methodSymbol = operation.TargetMethod;
+
+ if (methodSymbol.ContainingType.SpecialType == SpecialType.System_String &&
+ !methodSymbol.IsStatic &&
+ IsToLowerOrToUpper(methodSymbol.Name) &&
+ //picking the correct overload
+ methodSymbol.Parameters.Length == 0)
+ {
+ operationContext.ReportDiagnostic(Diagnostic.Create(Rule, GetMethodNameLocation(operation.Syntax)));
+ }
+ }, OperationKind.Invocation);
+ }
+
+ private static bool IsToLowerOrToUpper(string methodName)
+ {
+ return string.Equals(methodName, ToLowerMethodName, StringComparison.Ordinal) ||
+ string.Equals(methodName, ToUpperMethodName, StringComparison.Ordinal);
+ }
+ }
+}
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf
index 10b28fcd2c..d3b3d9decd 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf
@@ -2717,6 +2717,16 @@
Použít znakový literál pro vyhledávání s jedním znakem
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Analyzátor kompatibility platformy vyžaduje platný název a verzi platformy.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf
index e8fa532b3c..0faef4342a 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf
@@ -2717,6 +2717,16 @@
Zeichenliteral für die Suche nach einem einzelnen Zeichen verwenden
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Das Analysetool für Plattformkompatibilität erfordert einen gültigen Plattformnamen und eine gültige Version.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf
index de70cd6cc7..95f7016459 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf
@@ -2717,6 +2717,16 @@
Usar literal de carácter para una búsqueda de caracteres individuales
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.El analizador de compatibilidad de plataforma requiere un nombre de plataforma y una versión válidos.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf
index fd68311484..b9f4dd1bf6 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf
@@ -2717,6 +2717,16 @@
Utiliser le littéral char pour une recherche à caractère unique
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Platform Analyzer requiert un nom de plateforme et une version valides.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf
index 397345aee1..c0d080fe20 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf
@@ -2717,6 +2717,16 @@
Usare il valore letterale char per la ricerca di un singolo carattere
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Con l'analizzatore della compatibilità della piattaforma sono richiesti un nome e una versione di piattaforma validi.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf
index 03185609ce..c5a09a07f5 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf
@@ -2717,6 +2717,16 @@
1 つの文字参照に単一文字検索を使用する
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.プラットフォーム互換性アナライザーには、有効なプラットフォーム名とバージョンが必要です。
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf
index 5d19f995a3..ae1041e331 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf
@@ -2717,6 +2717,16 @@
단일 문자 조회에 char 리터럴 사용
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.플랫폼 호환성 분석기에는 유효한 플랫폼 이름과 버전이 필요합니다.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf
index 32891bd024..9ecb485248 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf
@@ -2717,6 +2717,16 @@
Użyj literału char do wyszukiwania pojedynczego znaku
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Analizator zgodności platformy wymaga prawidłowej nazwy i wersji platformy.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf
index 71c23cd62b..8d72096612 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf
@@ -2717,6 +2717,16 @@
Usar o literal char para uma pesquisa de caractere único
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.O analisador de compatibilidade de plataforma requer um nome de plataforma e uma versão válidos.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf
index 6ef06a894e..31437e711f 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf
@@ -2717,6 +2717,16 @@
Использовать знаковый литерал для поиска одного знака
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Анализатору совместимости платформы требуется допустимое имя и версия платформы.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf
index ec2ea33c79..7d6801b2b2 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf
@@ -2717,6 +2717,16 @@
Tek bir karakter araması için sabit değerli karakter kullanın
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.Platform uyumluluğu çözümleyicisi geçerli bir platform adı ve sürümü gerektiriyor.
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf
index 70f9aef203..4f5484a93d 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf
@@ -2717,6 +2717,16 @@
将字符型文本用于单个字符查找
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.平台兼容性分析器需要有效的平台名称和版本。
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf
index 449c80197a..b0026ba32d 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf
@@ -2717,6 +2717,16 @@
請為單一字元查閱使用字元常值
+
+ Using an invariant version yields consistent results regardless of the culture of an application.
+ Using an invariant version yields consistent results regardless of the culture of an application.
+
+
+
+ Use an invariant version
+ Use an invariant version
+
+ Platform compatibility analyzer requires a valid platform name and version.平台相容性分析器需要有效的平台名稱和版本。
diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariantTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariantTests.cs
new file mode 100644
index 0000000000..8cca8b0732
--- /dev/null
+++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseToLowerInvariantOrToUpperInvariantTests.cs
@@ -0,0 +1,109 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Testing;
+using Xunit;
+using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
+ Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpUseToLowerInvariantOrToUpperInvariantAnalyzer,
+ Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
+using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
+ Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicUseToLowerInvariantOrToUpperInvariant,
+ Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
+
+namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
+{
+ public class UseToLowerInvariantOrToUpperInvariantTests
+ {
+ #region Helper methods
+
+ private DiagnosticResult CSharpResult(int line, int column)
+#pragma warning disable RS0030 // Do not used banned APIs
+ => VerifyCS.Diagnostic()
+ .WithLocation(line, column);
+#pragma warning restore RS0030 // Do not used banned APIs
+
+ private DiagnosticResult BasicResult(int line, int column)
+#pragma warning disable RS0030 // Do not used banned APIs
+ => VerifyVB.Diagnostic()
+ .WithLocation(line, column);
+#pragma warning restore RS0030 // Do not used banned APIs
+
+ #endregion
+
+ #region Diagnostic tests
+
+ [Fact]
+ public async Task CA1311_ToLowerTest_CSharp()
+ {
+ await VerifyCS.VerifyAnalyzerAsync(@"
+class C
+{
+ void Method()
+ {
+ string a = ""test"";
+ a.ToLower();
+ a?.ToLower();
+ }
+}
+",
+ CSharpResult(7, 11),
+ CSharpResult(8, 11)
+);
+ }
+
+ [Fact]
+ public async Task CA1311_ToLowerTest_Basic()
+ {
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Class C
+ Sub Method()
+ Dim a As String = ""test""
+ a.ToLower()
+ a?.ToLower()
+ End Sub
+End Class
+",
+ BasicResult(5, 11),
+ BasicResult(6, 12)
+);
+ }
+
+ [Fact]
+ public async Task CA1311_ToUpperTest_CSharp()
+ {
+ await VerifyCS.VerifyAnalyzerAsync(@"
+class C
+{
+ void Method()
+ {
+ string a = ""test"";
+ a.ToUpper();
+ a?.ToUpper();
+ }
+}
+",
+ CSharpResult(7, 11),
+ CSharpResult(8, 11)
+);
+ }
+
+ [Fact]
+ public async Task CA1311_ToUpperTest_Basic()
+ {
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Class C
+ Sub Method()
+ Dim a As String = ""test""
+ a.ToUpper()
+ a?.ToUpper()
+ End Sub
+End Class
+",
+ BasicResult(5, 11),
+ BasicResult(6, 12)
+);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicUseToLowerInvariantOrToUpperInvariant.vb b/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicUseToLowerInvariantOrToUpperInvariant.vb
new file mode 100644
index 0000000000..1b0b6c3e08
--- /dev/null
+++ b/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicUseToLowerInvariantOrToUpperInvariant.vb
@@ -0,0 +1,27 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+Imports Microsoft.NetCore.Analyzers.Runtime
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+Imports Microsoft.CodeAnalysis.VisualBasic
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+
+Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime
+
+ Public Class BasicUseToLowerInvariantOrToUpperInvariant
+ Inherits UseToLowerInvariantOrToUpperInvariantAnalyzer
+
+ Protected Overrides Function GetMethodNameLocation(invocationNode As SyntaxNode) As Location
+ Debug.Assert(invocationNode.IsKind(SyntaxKind.InvocationExpression))
+
+ Dim invocation = CType(invocationNode, InvocationExpressionSyntax)
+ If invocation.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) Then
+ Return DirectCast(invocation.Expression, MemberAccessExpressionSyntax).Name.GetLocation()
+ ElseIf invocation.Expression.IsKind(SyntaxKind.ConditionalAccessExpression) Then
+ Return DirectCast(invocation.Expression, ConditionalAccessExpressionSyntax).WhenNotNull.GetLocation()
+ End If
+
+ Return invocation.GetLocation()
+ End Function
+ End Class
+End Namespace
diff --git a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
index bc7985a909..c75a6aa6f6 100644
--- a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
+++ b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
@@ -10,7 +10,7 @@
# 2. Update the range end to the chosen rule ID.
#
Design: CA2210, CA1000-CA1070
-Globalization: CA2101, CA1300-CA1310
+Globalization: CA2101, CA1300-CA1311
Mobility: CA1600-CA1601
Performance: HA, CA1800-CA1849
Security: CA2100-CA2153, CA2300-CA2330, CA3000-CA3147, CA5300-CA5405