diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 01eac786fd..f5c67ef4e1 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -290,6 +290,9 @@ Provide correct arguments to formatting methods + + The format argument is not a valid format string + Test for NaN correctly diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs index b18767a9fc..bfb858e37a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Analyzer.Utilities; using Analyzer.Utilities.Extensions; using Microsoft.CodeAnalysis; @@ -23,7 +24,7 @@ public class ProvideCorrectArgumentsToFormattingMethodsAnalyzer : DiagnosticAnal { internal const string RuleId = "CA2241"; - internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + internal static readonly DiagnosticDescriptor ArgumentCountRule = DiagnosticDescriptorHelper.Create( RuleId, CreateLocalizableResourceString(nameof(ProvideCorrectArgumentsToFormattingMethodsTitle)), CreateLocalizableResourceString(nameof(ProvideCorrectArgumentsToFormattingMethodsMessage)), @@ -33,7 +34,18 @@ public class ProvideCorrectArgumentsToFormattingMethodsAnalyzer : DiagnosticAnal isPortedFxCopRule: true, isDataflowRule: false); - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); + internal static readonly DiagnosticDescriptor InvalidFormatRule = DiagnosticDescriptorHelper.Create( + RuleId, + CreateLocalizableResourceString(nameof(ProvideCorrectArgumentsToFormattingMethodsTitle)), + CreateLocalizableResourceString(nameof(ProvideCorrectArgumentsToFormattingMethodsInvalidFormatMessage)), + DiagnosticCategory.Usage, + RuleLevel.BuildWarningCandidate, + description: CreateLocalizableResourceString(nameof(ProvideCorrectArgumentsToFormattingMethodsDescription)), + isPortedFxCopRule: true, + isDataflowRule: false); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(ArgumentCountRule, InvalidFormatRule); public override void Initialize(AnalysisContext context) { @@ -65,6 +77,13 @@ public override void Initialize(AnalysisContext context) int expectedStringFormatArgumentCount = GetFormattingArguments(stringFormat); + if (expectedStringFormatArgumentCount < 0) + { + // Malformed format specification + operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(InvalidFormatRule)); + return; + } + // explicit parameter case if (info.ExpectedStringFormatArgumentCount >= 0) { @@ -77,11 +96,16 @@ public override void Initialize(AnalysisContext context) if (info.ExpectedStringFormatArgumentCount != expectedStringFormatArgumentCount) { - operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule)); + operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(ArgumentCountRule)); } return; } + else if (info.ExpectedStringFormatArgumentCount == -2) + { + // Not a formatting method, we only checked the format specification. + return; + } // ensure argument is an array IArgumentOperation paramsArgument = invocation.Arguments[info.FormatStringIndex + 1]; @@ -111,7 +135,7 @@ public override void Initialize(AnalysisContext context) int actualArgumentCount = initializer.ElementValues.Length; if (actualArgumentCount != expectedStringFormatArgumentCount) { - operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule)); + operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(ArgumentCountRule)); } }, OperationKind.Invocation); }); @@ -308,7 +332,7 @@ private static int GetFormattingArguments(string format) } // end of main loop - return uniqueNumbers.Count; + return uniqueNumbers.Count == 0 ? 0 : uniqueNumbers.Max() + 1; } private class StringFormatInfo @@ -352,7 +376,7 @@ public StringFormatInfo(Compilation compilation) } // Check if this the underlying method is user configured string formatting method. - var additionalStringFormatMethodsOption = context.Options.GetAdditionalStringFormattingMethodsOption(Rule, context.Operation.Syntax.SyntaxTree, context.Compilation); + var additionalStringFormatMethodsOption = context.Options.GetAdditionalStringFormattingMethodsOption(ArgumentCountRule, context.Operation.Syntax.SyntaxTree, context.Compilation); if (additionalStringFormatMethodsOption.Contains(method.OriginalDefinition) && TryGetFormatInfoByParameterName(method, out info)) { @@ -362,7 +386,7 @@ public StringFormatInfo(Compilation compilation) // Check if the user configured automatic determination of formatting methods. // If so, check if the method called has a 'string format' parameter followed by an params array. var determineAdditionalStringFormattingMethodsAutomatically = context.Options.GetBoolOptionValue(EditorConfigOptionNames.TryDetermineAdditionalStringFormattingMethodsAutomatically, - Rule, context.Operation.Syntax.SyntaxTree, context.Compilation, defaultValue: false); + ArgumentCountRule, context.Operation.Syntax.SyntaxTree, context.Compilation, defaultValue: false); if (determineAdditionalStringFormattingMethodsAutomatically && TryGetFormatInfoByParameterName(method, out info) && info.ExpectedStringFormatArgumentCount == -1) @@ -424,6 +448,13 @@ private bool TryGetFormatInfo(IMethodSymbol method, int formatIndex, [NotNullWhe private static int GetExpectedNumberOfArguments(ImmutableArray parameters, int formatIndex) { + if (formatIndex == parameters.Length - 1) + { + // format specification is the last parameter (e.g. CompositeFormat.Parse) + // this is therefore not a formatting method. + return -2; + } + // check params IParameterSymbol nextParameter = parameters[formatIndex + 1]; if (nextParameter.IsParams) 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 c4f98859c8..137ae94cef 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -2288,6 +2288,11 @@ Obecné přetypování (IL unbox.any) používané sekvencí vrácenou metodou E Argument formátu, který se předává do System.String.Format, neobsahuje položku formátování, která odpovídá jednotlivým argumentům objektů, nebo naopak. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Poskytněte metodám formátování správné argumenty 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 62b16ed7d7..4f473ce27b 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -2288,6 +2288,11 @@ Erweiterungen und benutzerdefinierte Konvertierungen werden bei generischen Type Das an "System.String.Format" übergebene Formatargument enthält kein Formatelement, das den einzelnen Objektargumenten entspricht bzw. umgekehrt. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Geeignete Argumente für Formatierungsmethoden angeben 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 d21492215c..60d7531526 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -2288,6 +2288,11 @@ La ampliación y las conversiones definidas por el usuario no se admiten con tip El argumento de cadena format pasado a System.String.Format no contiene un elemento de formato que corresponda a cada argumento de objeto o viceversa. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Proporcionar argumentos correctos para los métodos de formato 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 c14f18c29d..c6b0b30652 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -2288,6 +2288,11 @@ Les conversions étendues et définies par l’utilisateur ne sont pas prises en L'argument de mise en forme passé à System.String.Format ne contient aucun élément de mise en forme pour chaque argument d'objet correspondant, ou vice versa. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Indiquer le nombre correct d'arguments dans les méthodes de mise en forme 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 7bd9111cf7..21d943a5f7 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -2288,6 +2288,11 @@ L'ampliamento e le conversioni definite dall'utente non sono supportate con tipi L'argomento format passato a System.String.Format non contiene un elemento di formato corrispondente a ogni argomento dell'oggetto o viceversa. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Fornire gli argomenti corretti ai metodi di formattazione 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 5bc3a0ca3e..157c639229 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -2288,6 +2288,11 @@ Enumerable.OfType<T> で使用されるジェネリック型チェック ( System.String.Format に渡される書式引数には、各オブジェクト引数に対応する書式項目が含まれていないか、各書式項目に対応するオブジェクト引数が含まれていません。 + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods 書式設定メソッドに正しい引数を指定します 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 70a0a87e6d..c51c4b7520 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -2288,6 +2288,11 @@ Enumerable.OfType<T>에서 사용하는 제네릭 형식 검사(C# 'is' System.String.Format으로 전달된 format 인수에 각 개체 인수에 해당하는 format 항목이 포함되지 않으며 그 반대의 경우도 마찬가지입니다. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods 서식 지정 메서드에 올바른 인수를 제공하세요. 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 39b613af0b..6716383b08 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -2288,6 +2288,11 @@ Konwersje poszerzane i zdefiniowane przez użytkownika nie są obsługiwane w pr Argument formatu przekazywany do metody System.String.Format nie zawiera elementu formatu odpowiadającego każdemu argumentowi obiektu lub odwrotnie. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Określ poprawne argumenty dla metod formatujących 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 5f63fca477..1158c1feea 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 @@ -2288,6 +2288,11 @@ Ampliação e conversões definidas pelo usuário não são compatíveis com tip O argumento de formato passado para System.String.Format não contém um item de formato correspondente a cada argumento de objeto ou vice-versa. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Fornecer os argumentos corretos para métodos de formatação 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 4bef823371..2fc84e2559 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -2288,6 +2288,11 @@ Widening and user defined conversions are not supported with generic types.Передаваемый в System.String.Format аргумент формата не содержит элемент формата, соответствующий каждому из аргументов объекта, или наоборот. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Задайте правильные аргументы для методов форматирования 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 b68be988c9..dc915b4ce8 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -2288,6 +2288,11 @@ Genel türlerde genişletme ve kullanıcı tanımlı dönüştürmeler desteklen System.String.Format’a geçirilen biçim bağımsız değişkeni, her nesne bağımsız değişkenine karşılık gelen bir biçim öğesi içermiyor ve tersi için de aynısı geçerli. + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods Biçimlendirme yöntemlerine doğru bağımsız değişkenleri sağlayın 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 a7e56d5a10..7c3ee317d2 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 @@ -2288,6 +2288,11 @@ Enumerable.OfType<T> 使用的泛型类型检查 (C# 'is' operator/IL 'isi 传递到 System.String.Format 的 format 参数不包含与各对象参数相对应的格式项,反之亦然。 + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods 为格式化方法提供正确的参数 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 c28ef39f4f..856cc16550 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 @@ -2288,6 +2288,11 @@ Enumerable.OfType<T> 使用的一般型別檢查 (C# 'is' operator/IL 'isi 傳遞給 System.String.Format 的格式化引數,並未包含與每個物件引數相對應的格式項目,反之亦然。 + + The format argument is not a valid format string + The format argument is not a valid format string + + Provide correct arguments to formatting methods 為格式化方法提供正確的引數 diff --git a/src/NetAnalyzers/RulesMissingDocumentation.md b/src/NetAnalyzers/RulesMissingDocumentation.md index eb030b9cc5..42df726b08 100644 --- a/src/NetAnalyzers/RulesMissingDocumentation.md +++ b/src/NetAnalyzers/RulesMissingDocumentation.md @@ -13,6 +13,5 @@ CA1863 | | Use char overload | CA1866 | | Use char overload | CA1867 | | Use char overload | -CA1869 | | Cache and reuse 'JsonSerializerOptions' instances | CA2021 | | Do not call Enumerable.Cast\ or Enumerable.OfType\ with incompatible types | CA2261 | | Do not use ConfigureAwaitOptions.SuppressThrowing with Task\ | diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs index 19d10ea590..ee635c49b2 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs @@ -1,6 +1,7 @@ // 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; using Microsoft.CodeAnalysis.Testing; using Test.Utilities; using Xunit; @@ -118,6 +119,7 @@ void Method() var c = String.Format(""{0} {1} {2}"", 1, 2, 3); var d = String.Format(""{0} {1} {2} {3}"", 1, 2, 3, 4); var e = String.Format(""{0} {1} {2} {0}"", 1, 2, 3); + var f = String.Format(""{0} {0} {0} {0}"", 1); Console.Write(""{0}"", 1); Console.Write(""{0} {1}"", 1, 2); @@ -125,6 +127,7 @@ void Method() Console.Write(""{0} {1} {2} {3}"", 1, 2, 3, 4); Console.Write(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, 5); Console.Write(""{0} {1} {2} {3} {0}"", 1, 2, 3, 4); + Console.Write(""{0} {0} {0} {0} {0}"", 1); Console.WriteLine(""{0}"", 1); Console.WriteLine(""{0} {1}"", 1, 2); @@ -132,11 +135,50 @@ void Method() Console.WriteLine(""{0} {1} {2} {3}"", 1, 2, 3, 4); Console.WriteLine(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, 5); Console.WriteLine(""{0} {1} {2} {3} {0}"", 1, 2, 3, 4); + Console.WriteLine(""{0} {0} {0} {0} {0}"", 1); } } "); } + [Fact] + public async Task CA2241CSharpDifferentDiagnosticsAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System; + +public class C +{ + void Method() + { + var a = String.Format(""{1}"", 1); + var b = String.Format(""{0} {1}"", 1, 2); + var c = String.Format(""{0} {1}"", 1, 2, 3); + var d = String.Format(""{0} {1} {2"", 1, 2, 3); + + Console.Write(""{1}"", 1); + Console.Write(""{0} {1}"", 1, 2); + Console.Write(""{0} {1}"", 1, 2, 3); + Console.Write(""{0} {1} {2"", 1, 2, 3); + + Console.WriteLine(""{1}"", 1); + Console.WriteLine(""{0} {1}"", 1, 2); + Console.WriteLine(""{0} {1}"", 1, 2, 3); + Console.WriteLine(""{0} {1} {2"", 1, 2, 3); + } +} +", + GetCSharpResultAt(8, 17, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(10, 17, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(11, 17, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.InvalidFormatRule), + GetCSharpResultAt(13, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(15, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(16, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.InvalidFormatRule), + GetCSharpResultAt(18, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(20, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule), + GetCSharpResultAt(21, 9, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.InvalidFormatRule)); + } + [Fact] public async Task CA2241CSharpExplicitObjectArraySupportedAsync() { @@ -573,17 +615,54 @@ End Class" await basicTest.RunAsync(); } + [Fact] + [WorkItem(90357, "https://github.com/dotnet/runtime/issues/90357")] + public async Task CA2241CSharpMethodWithNoPossibleArgumentsOnlyChecksFormat() + { + var csharpTest = new VerifyCS.Test + { + TestState = + { + Sources = + { + @" +using System.Diagnostics.CodeAnalysis; + +class Test +{ + public static int Parse([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format) => -1; + + void M1(string param) + { + var a = Parse(""{0} {1}""); + var b = Parse(""{0 {1}""); + } +}" + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + } + }; + + csharpTest.ExpectedDiagnostics.Add( + GetCSharpResultAt(11, 17, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.InvalidFormatRule)); + + await csharpTest.RunAsync(); + } + #endregion private static DiagnosticResult GetCSharpResultAt(int line, int column) + => GetCSharpResultAt(line, column, ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule); + + private static DiagnosticResult GetCSharpResultAt(int line, int column, DiagnosticDescriptor descriptor) #pragma warning disable RS0030 // Do not use banned APIs - => VerifyCS.Diagnostic() + => VerifyCS.Diagnostic(descriptor) .WithLocation(line, column); #pragma warning restore RS0030 // Do not use banned APIs private static DiagnosticResult GetBasicResultAt(int line, int column) #pragma warning disable RS0030 // Do not use banned APIs - => VerifyVB.Diagnostic() + => VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.ArgumentCountRule) .WithLocation(line, column); #pragma warning restore RS0030 // Do not use banned APIs }