diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
index cdf4f1397e..7f555c6d88 100644
--- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
+++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
@@ -1 +1,5 @@
; Please do not edit this file manually, it should only be updated through code fix application.
+### New Rules
+Rule ID | Category | Severity | Notes
+--------|----------|----------|-------
+CA2250 | Usage | Info | ProvideCorrectArgumentsToFormattingMethodsAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2250)
\ No newline at end of file
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
index d53e63aa40..4d3727db65 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
@@ -1,17 +1,17 @@
-
@@ -342,8 +342,8 @@
The format argument that is passed to System.String.Format does not contain a format item that corresponds to each object argument, or vice versa.
-
- Provide correct arguments to formatting methods
+
+ Incorrect number of arguments passed to this formatting method call
Test for NaN correctly
@@ -1482,4 +1482,7 @@
Replace with 'string.Contains'
+
+ Some string format items are missing from this formatting method call
+
\ No newline at end of file
diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs
index 49388ce992..fab4252186 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text.RegularExpressions;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
@@ -18,38 +20,123 @@ namespace Microsoft.NetCore.Analyzers.Runtime
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public class ProvideCorrectArgumentsToFormattingMethodsAnalyzer : DiagnosticAnalyzer
{
- internal const string RuleId = "CA2241";
+ internal const string DefaultRuleId = "CA2241";
+ internal const string NotEnoughArgsRuleId = "CA2250";
private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(MicrosoftNetCoreAnalyzersResources.ProvideCorrectArgumentsToFormattingMethodsTitle), MicrosoftNetCoreAnalyzersResources.ResourceManager, typeof(MicrosoftNetCoreAnalyzersResources));
- private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(MicrosoftNetCoreAnalyzersResources.ProvideCorrectArgumentsToFormattingMethodsMessage), MicrosoftNetCoreAnalyzersResources.ResourceManager, typeof(MicrosoftNetCoreAnalyzersResources));
+ private static readonly LocalizableString s_localizableMessageArgs = new LocalizableResourceString(nameof(MicrosoftNetCoreAnalyzersResources.ProvideCorrectArgumentsToFormattingMethodsMessageArgs), MicrosoftNetCoreAnalyzersResources.ResourceManager, typeof(MicrosoftNetCoreAnalyzersResources));
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(MicrosoftNetCoreAnalyzersResources.ProvideCorrectArgumentsToFormattingMethodsDescription), MicrosoftNetCoreAnalyzersResources.ResourceManager, typeof(MicrosoftNetCoreAnalyzersResources));
- internal static DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(RuleId,
- s_localizableTitle,
- s_localizableMessage,
- DiagnosticCategory.Usage,
- RuleLevel.BuildWarningCandidate,
- description: s_localizableDescription,
- isPortedFxCopRule: true,
- isDataflowRule: false);
-
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+ // e.g. Console.WriteLine("{0} {1}", 42);
+ internal static DiagnosticDescriptor NotEnoughArgsRule = DiagnosticDescriptorHelper.Create(
+ NotEnoughArgsRuleId,
+ s_localizableTitle,
+ s_localizableMessageArgs,
+ DiagnosticCategory.Usage,
+ RuleLevel.BuildWarningCandidate,
+ description: s_localizableDescription,
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ // e.g. Console.WriteLine("{1}", 42);
+ internal static DiagnosticDescriptor NotEnoughArgsMissingFormatIndexRule = DiagnosticDescriptorHelper.Create(
+ NotEnoughArgsRuleId,
+ s_localizableTitle,
+ s_localizableMessageArgs,
+ DiagnosticCategory.Usage,
+ RuleLevel.BuildWarningCandidate,
+ description: s_localizableDescription,
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ // e.g. Console.WriteLine("{0}", 1, 2)
+ internal static DiagnosticDescriptor TooManyArgsRule = DiagnosticDescriptorHelper.Create(
+ DefaultRuleId,
+ s_localizableTitle,
+ s_localizableMessageArgs,
+ DiagnosticCategory.Usage,
+ RuleLevel.IdeSuggestion,
+ description: s_localizableDescription,
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ // e.g. Console.WriteLine("{1}", 1, 2, 3)
+ internal static DiagnosticDescriptor TooManyArgsMissingFormatIndexRule = DiagnosticDescriptorHelper.Create(
+ DefaultRuleId,
+ s_localizableTitle,
+ s_localizableMessageArgs,
+ DiagnosticCategory.Usage,
+ RuleLevel.IdeSuggestion,
+ description: s_localizableDescription,
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ // e.g. Console.WriteLine("{1}", 1, 2)
+ internal static DiagnosticDescriptor EnoughArgsMissingFormatIndexRule = DiagnosticDescriptorHelper.Create(
+ DefaultRuleId,
+ s_localizableTitle,
+ s_localizableMessageArgs,
+ DiagnosticCategory.Usage,
+ RuleLevel.IdeSuggestion,
+ description: s_localizableDescription,
+ isPortedFxCopRule: true,
+ isDataflowRule: false);
+
+ //// e.g. Console.WriteLine("{0} {1}") -> resolves to the overload expecting a string, not a format string
+ //internal static DiagnosticDescriptor FormatItemInNonStringFormatMethodRule = DiagnosticDescriptorHelper.Create(
+ // RuleId,
+ // s_localizableTitle,
+ // s_localizableMessageArgs,
+ // DiagnosticCategory.Usage,
+ // RuleLevel.IdeSuggestion,
+ // description: s_localizableDescription,
+ // isPortedFxCopRule: true,
+ // isDataflowRule: false);
+
+ //// e.g. Console.WriteLine("{1}")
+ //internal static DiagnosticDescriptor FormatItemInNonStringFormatMethodMissingFormatItemRule = DiagnosticDescriptorHelper.Create(
+ // RuleId,
+ // s_localizableTitle,
+ // s_localizableMessageArgs,
+ // DiagnosticCategory.Usage,
+ // RuleLevel.IdeSuggestion,
+ // description: s_localizableDescription,
+ // isPortedFxCopRule: true,
+ // isDataflowRule: false);
+
+ ///
+ /// This regex is used to remove escaped brackets from the format string before looking for valid {} pairs.
+ ///
+ private static readonly Regex s_removeEscapedBracketsRegex = new("{{", RegexOptions.Compiled);
+
+ ///
+ /// This regex is used to extract the text between the brackets and save the contents in a MatchCollection.
+ ///
+ private static readonly Regex s_extractPlaceholdersRegex = new("{(.*?)}", RegexOptions.Compiled);
+
+ public override ImmutableArray SupportedDiagnostics
+ => ImmutableArray.Create(
+ NotEnoughArgsRule,
+ NotEnoughArgsMissingFormatIndexRule,
+ EnoughArgsMissingFormatIndexRule,
+ TooManyArgsRule,
+ TooManyArgsMissingFormatIndexRule);
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.EnableConcurrentExecution();
analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
- analysisContext.RegisterCompilationStartAction(compilationContext =>
+ analysisContext.RegisterCompilationStartAction(context =>
{
- var formatInfo = new StringFormatInfo(compilationContext.Compilation);
+ var formatInfo = new StringFormatInfo(context.Compilation);
- compilationContext.RegisterOperationAction(operationContext =>
+ context.RegisterOperationAction(context =>
{
- var invocation = (IInvocationOperation)operationContext.Operation;
+ var invocation = (IInvocationOperation)context.Operation;
- StringFormatInfo.Info? info = formatInfo.TryGet(invocation.TargetMethod, operationContext);
+ StringFormatInfo.Info? info = formatInfo.TryGet(invocation.TargetMethod, context);
if (info == null || invocation.Arguments.Length <= info.FormatStringIndex)
{
// not a target method
@@ -57,34 +144,36 @@ public override void Initialize(AnalysisContext analysisContext)
}
IArgumentOperation formatStringArgument = invocation.Arguments[info.FormatStringIndex];
- if (!object.Equals(formatStringArgument?.Value?.Type, formatInfo.String) ||
+ if (!Equals(formatStringArgument?.Value?.Type, formatInfo.String) ||
!(formatStringArgument?.Value?.ConstantValue.Value is string))
{
// wrong argument
return;
}
+ // __arglist is not supported here (see https://github.com/dotnet/roslyn/issues/7346)
+ // but we want to skip it only in C# since VB doesn't support __arglist
+ if (info.ExpectedStringFormatArgumentCount >= 0 &&
+ invocation.TargetMethod.IsVararg &&
+ invocation.Language == LanguageNames.CSharp)
+ {
+ return;
+ }
+
var stringFormat = (string)formatStringArgument.Value.ConstantValue.Value;
- int expectedStringFormatArgumentCount = GetFormattingArguments(stringFormat);
+ var stringFormatIndexes = GetStringFormatItemIndexes(stringFormat);
- // explicit parameter case
+ // Target method resolves to an overload with a non variable (e.g. params) argument count
+ // so we can easily analyze the arguments.
if (info.ExpectedStringFormatArgumentCount >= 0)
{
- // __arglist is not supported here
- if (invocation.TargetMethod.IsVararg)
- {
- // can't deal with this for now.
- return;
- }
-
- if (info.ExpectedStringFormatArgumentCount != expectedStringFormatArgumentCount)
- {
- operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
- }
-
+ ReportOnArgumentsMismatch(stringFormat, info.ExpectedStringFormatArgumentCount, context, invocation);
return;
}
+ // Target method resolves to an overload with a variable argument count so we need
+ // to try to understand the number of arguments passed.
+
// ensure argument is an array
IArgumentOperation paramsArgument = invocation.Arguments[info.FormatStringIndex + 1];
if (paramsArgument.ArgumentKind is not ArgumentKind.ParamArray and not ArgumentKind.Explicit)
@@ -95,7 +184,7 @@ public override void Initialize(AnalysisContext analysisContext)
if (paramsArgument.Value is not IArrayCreationOperation arrayCreation ||
arrayCreation.GetElementType() is not ITypeSymbol elementType ||
- !object.Equals(elementType, formatInfo.Object) ||
+ !Equals(elementType, formatInfo.Object) ||
arrayCreation.DimensionSizes.Length != 1)
{
// wrong format
@@ -112,206 +201,102 @@ public override void Initialize(AnalysisContext analysisContext)
// REVIEW: "ElementValues" is a bit confusing where I need to double dot those to get number of elements
int actualArgumentCount = intializer.ElementValues.Length;
- if (actualArgumentCount != expectedStringFormatArgumentCount)
- {
- operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
- }
+ ReportOnArgumentsMismatch(stringFormat, actualArgumentCount, context, invocation);
}, OperationKind.Invocation);
});
}
- private static int GetFormattingArguments(string format)
+ private static HashSet GetStringFormatItemIndexes(string stringFormat)
{
- // code is from mscorlib
- // https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/mscorlib/src/System/Text/StringBuilder.cs#L1312
+ // removing escaped left brackets and replacing with space characters so they won't
+ // impede the extraction of placeholders, yet the locations of the placeholders are
+ // the same as in the original string.
+ var formatStringWithEscapedBracketsChangedToSpaces = s_removeEscapedBracketsRegex.Replace(stringFormat, " ");
- // return count of this format - {index[,alignment][:formatString]}
- var pos = 0;
- int len = format.Length;
- var uniqueNumbers = new HashSet();
+ var matches = s_extractPlaceholdersRegex.Matches(formatStringWithEscapedBracketsChangedToSpaces);
+ var indexes = new HashSet();
- // main loop
- while (true)
+ foreach (Match match in matches)
{
- // loop to find starting "{"
- char ch;
- while (pos < len)
+ var formatItemIndex = ExtractFormatItemIndex(match.Groups[1].Value);
+ if (formatItemIndex.HasValue)
{
- ch = format[pos];
-
- pos++;
- if (ch == '}')
- {
- if (pos < len && format[pos] == '}') // Treat as escape character for }}
- {
- pos++;
- }
- else
- {
- return -1;
- }
- }
-
- if (ch == '{')
- {
- if (pos < len && format[pos] == '{') // Treat as escape character for {{
- {
- pos++;
- }
- else
- {
- pos--;
- break;
- }
- }
+ indexes.Add(formatItemIndex.Value);
}
+ }
- // finished with "{"
- if (pos == len)
- {
- break;
- }
+ return indexes;
+ }
- pos++;
+ private static int? ExtractFormatItemIndex(string textInsideBrackets)
+ {
+ var formatItemText = textInsideBrackets.IndexOf(",", StringComparison.OrdinalIgnoreCase) > 0
+ ? textInsideBrackets.Split(',')[0]
+ : textInsideBrackets.Split(':')[0];
- if (pos == len || (ch = format[pos]) < '0' || ch > '9')
- {
- // finished with "{x"
- return -1;
- }
+ // placeholders cannot begin with whitespace
+ if (formatItemText.Length > 0 && char.IsWhiteSpace(formatItemText, 0))
+ {
+ return null;
+ }
- // searching for index
- var index = 0;
- do
- {
- index = index * 10 + ch - '0';
+ if (!int.TryParse(formatItemText, out var formatItemIndex) ||
+ formatItemIndex < 0)
+ {
+ return null;
+ }
- pos++;
- if (pos == len)
- {
- // wrong index format
- return -1;
- }
+ return formatItemIndex;
+ }
- ch = format[pos];
- } while (ch >= '0' && ch <= '9' && index < 1000000);
+ private static void ReportOnArgumentsMismatch(string stringFormat, int actualArgumentCount,
+ OperationAnalysisContext context, IInvocationOperation invocation)
+ {
+ var stringFormatIndexes = GetStringFormatItemIndexes(stringFormat);
- // eat up whitespace
- while (pos < len && (ch = format[pos]) == ' ')
+ var expectedArgumentCount = stringFormatIndexes.Count > 0
+ ? stringFormatIndexes.Max() + 1
+ : 0;
+
+ if (actualArgumentCount > expectedArgumentCount)
+ {
+ if (HasAnyMissingFormatIndex(stringFormatIndexes, expectedArgumentCount))
{
- pos++;
+ context.ReportDiagnostic(invocation.CreateDiagnostic(TooManyArgsMissingFormatIndexRule));
}
-
- // searching for alignment
- var width = 0;
- if (ch == ',')
+ else
{
- pos++;
-
- // eat up whitespace
- while (pos < len && format[pos] == ' ')
- {
- pos++;
- }
-
- if (pos == len)
- {
- // wrong format, reached end without "}"
- return -1;
- }
-
- ch = format[pos];
- if (ch == '-')
- {
- pos++;
-
- if (pos == len)
- {
- // wrong format. reached end without "}"
- return -1;
- }
-
- ch = format[pos];
- }
-
- if (ch is < '0' or > '9')
- {
- // wrong format after "-"
- return -1;
- }
-
- do
- {
- width = width * 10 + ch - '0';
- pos++;
-
- if (pos == len)
- {
- // wrong width format
- return -1;
- }
-
- ch = format[pos];
- } while (ch >= '0' && ch <= '9' && width < 1000000);
+ context.ReportDiagnostic(invocation.CreateDiagnostic(TooManyArgsRule));
}
- // eat up whitespace
- while (pos < len && (ch = format[pos]) == ' ')
+ return;
+ }
+ else if (actualArgumentCount < expectedArgumentCount)
+ {
+ if (HasAnyMissingFormatIndex(stringFormatIndexes, expectedArgumentCount))
{
- pos++;
+ context.ReportDiagnostic(invocation.CreateDiagnostic(NotEnoughArgsMissingFormatIndexRule));
}
-
- // searching for embedded format string
- if (ch == ':')
+ else
{
- pos++;
-
- while (true)
- {
- if (pos == len)
- {
- // reached end without "}"
- return -1;
- }
-
- ch = format[pos];
- pos++;
-
- if (ch == '{')
- {
- if (pos < len && format[pos] == '{') // Treat as escape character for {{
- pos++;
- else
- return -1;
- }
- else if (ch == '}')
- {
- if (pos < len && format[pos] == '}') // Treat as escape character for }}
- {
- pos++;
- }
- else
- {
- pos--;
- break;
- }
- }
- }
+ context.ReportDiagnostic(invocation.CreateDiagnostic(NotEnoughArgsRule));
}
- if (ch != '}')
+ return;
+ }
+ else
+ {
+ if (HasAnyMissingFormatIndex(stringFormatIndexes, expectedArgumentCount))
{
- // "}" is expected
- return -1;
+ context.ReportDiagnostic(invocation.CreateDiagnostic(EnoughArgsMissingFormatIndexRule));
}
- pos++;
-
- uniqueNumbers.Add(index);
-
- } // end of main loop
+ return;
+ }
- return uniqueNumbers.Count;
+ static bool HasAnyMissingFormatIndex(HashSet stringFormatIndexes, int expectedArgumentCount)
+ => stringFormatIndexes.Count > 0 &&
+ Enumerable.Range(0, expectedArgumentCount - 1).Except(stringFormatIndexes).Any();
}
private class StringFormatInfo
@@ -347,23 +332,28 @@ public StringFormatInfo(Compilation compilation)
return info;
}
- // Check if this the underlying method is user configured string formatting method.
- var additionalStringFormatMethodsOption = context.Options.GetAdditionalStringFormattingMethodsOption(Rule, context.Operation.Syntax.SyntaxTree, context.Compilation, context.CancellationToken);
- if (additionalStringFormatMethodsOption.Contains(method.OriginalDefinition) &&
- TryGetFormatInfo(method, out info))
+ foreach (var descriptor in new[] { NotEnoughArgsRule, TooManyArgsRule })
{
- return info;
- }
+ // Check if this the underlying method is user configured string formatting method.
+ var additionalStringFormatMethodsOption = context.Options.GetAdditionalStringFormattingMethodsOption(descriptor,
+ context.Operation.Syntax.SyntaxTree, context.Compilation, context.CancellationToken);
+ if (additionalStringFormatMethodsOption.Contains(method.OriginalDefinition) &&
+ TryGetFormatInfo(method, out info))
+ {
+ return info;
+ }
- // 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, context.CancellationToken);
- if (determineAdditionalStringFormattingMethodsAutomatically &&
- TryGetFormatInfo(method, out info) &&
- info.ExpectedStringFormatArgumentCount == -1)
- {
- return info;
+ // 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, descriptor,
+ context.Operation.Syntax.SyntaxTree, context.Compilation, defaultValue: false, context.CancellationToken);
+ if (determineAdditionalStringFormattingMethodsAutomatically &&
+ TryGetFormatInfo(method, out info) &&
+ info.ExpectedStringFormatArgumentCount == -1)
+ {
+ return info;
+ }
}
return null;
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 7a20a34670..22a328fcd5 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf
@@ -1667,9 +1667,14 @@
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.
-
- Provide correct arguments to formatting methods
- Poskytněte metodám formátování správné argumenty
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 1f87411727..49db8420f3 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf
@@ -1667,9 +1667,14 @@
Das an "System.String.Format" übergebene Formatargument enthält kein Formatelement, das den einzelnen Objektargumenten entspricht bzw. umgekehrt.
-
- Provide correct arguments to formatting methods
- Geeignete Argumente für Formatierungsmethoden angeben
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 b2eb9e9c1e..e27574f26b 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf
@@ -1667,9 +1667,14 @@
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.
-
- Provide correct arguments to formatting methods
- Proporcionar argumentos correctos para los métodos de formato
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 49c9c08d95..ead7959bd4 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf
@@ -1667,9 +1667,14 @@
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.
-
- Provide correct arguments to formatting methods
- Indiquer le nombre correct d'arguments dans les méthodes de mise en forme
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 9de345095d..658db14059 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf
@@ -1667,9 +1667,14 @@
L'argomento format passato a System.String.Format non contiene un elemento di formato corrispondente a ogni argomento dell'oggetto o viceversa.
-
- Provide correct arguments to formatting methods
- Fornire gli argomenti corretti ai metodi di formattazione
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 69621d6385..cfd9e8a805 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf
@@ -1667,9 +1667,14 @@
System.String.Format に渡される書式引数には、各オブジェクト引数に対応する書式項目が含まれていないか、各書式項目に対応するオブジェクト引数が含まれていません。
-
- Provide correct arguments to formatting methods
- 書式設定メソッドに正しい引数を指定します
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 b8a532fec1..430b92b5ad 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf
@@ -1667,9 +1667,14 @@
System.String.Format으로 전달된 format 인수에 각 개체 인수에 해당하는 format 항목이 포함되지 않으며 그 반대의 경우도 마찬가지입니다.
-
- Provide correct arguments to formatting methods
- 서식 지정 메서드에 올바른 인수를 제공하세요.
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 7de06d566f..a6b13e4181 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf
@@ -1667,9 +1667,14 @@
Argument formatu przekazywany do metody System.String.Format nie zawiera elementu formatu odpowiadającego każdemu argumentowi obiektu lub odwrotnie.
-
- Provide correct arguments to formatting methods
- Określ poprawne argumenty dla metod formatujących
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 519a58d4cf..26afbce484 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
@@ -1667,9 +1667,14 @@
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.
-
- Provide correct arguments to formatting methods
- Fornecer os argumentos corretos para métodos de formatação
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 b519700bb4..c993dbe2f0 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf
@@ -1667,9 +1667,14 @@
Передаваемый в System.String.Format аргумент формата не содержит элемент формата, соответствующий каждому из аргументов объекта, или наоборот.
-
- Provide correct arguments to formatting methods
- Задайте правильные аргументы для методов форматирования
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 897668ed0b..1e47fd5264 100644
--- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf
+++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf
@@ -1667,9 +1667,14 @@
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.
-
- Provide correct arguments to formatting methods
- Biçimlendirme yöntemlerine doğru bağımsız değişkenleri sağlayın
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 2bfc4eeecc..baf997726b 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
@@ -1667,9 +1667,14 @@
传递到 System.String.Format 的 format 参数不包含与各对象参数相对应的格式项,反之亦然。
-
- Provide correct arguments to formatting methods
- 为格式化方法提供正确的参数
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
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 662d9960e3..7b7850a4a8 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
@@ -1667,9 +1667,14 @@
傳遞給 System.String.Format 的格式化引數,並未包含與每個物件引數相對應的格式項目,反之亦然。
-
- Provide correct arguments to formatting methods
- 為格式化方法提供正確的引數
+
+ Incorrect number of arguments passed to this formatting method call
+ Incorrect number of arguments passed to this formatting method call
+
+
+
+ Some string format items are missing from this formatting method call
+ Some string format items are missing from this formatting method call
diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs
index 293decb6df..86319c10db 100644
--- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs
+++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
@@ -15,10 +16,10 @@ namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
public class ProvideCorrectArgumentsToFormattingMethodsTests
{
- #region Diagnostic Tests
-
- [Fact]
- public async Task CA2241CSharpString()
+ [Theory]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2241_TooManyArgs_ConsoleWriteMethods_Diagnostic(string invocation)
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
@@ -27,34 +28,51 @@ public class C
{
void Method()
{
- var a = String.Format("""", 1);
- var b = String.Format(""{0}"", 1, 2);
- var c = String.Format(""{0} {1}"", 1, 2, 3);
- var d = String.Format(""{0} {1} {2}"", 1, 2, 3, 4);
- var e = string.Format(""{0} {0}"", 1, 2);
-
- IFormatProvider p = null;
- var f = String.Format(p, """", 1);
- var g = String.Format(p, ""{0}"", 1, 2);
- var h = String.Format(p, ""{0} {1}"", 1, 2, 3);
- var i = String.Format(p, ""{0} {1} {2}"", 1, 2, 3, 4);
+ {|#0:" + invocation + @"("""", 1)|};
+ {|#1:" + invocation + @"(""{0}"", 1, 2)|};
+ {|#2:" + invocation + @"(""{0} {1}"", 1, 2, 3)|};
+ {|#3:" + invocation + @"(""{0} {1} {2}"", 1, 2, 3, 4)|};
+ {|#4:" + invocation + @"(""{0} {1} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|};
+ {|#5:" + invocation + @"(""{2} {0} {1}"", 1, 2, 3, 4)|};
+ {|#6:" + invocation + @"(""{0} {0}"", 1, 2)|};
}
}
",
- GetCSharpResultAt(8, 17),
- GetCSharpResultAt(9, 17),
- GetCSharpResultAt(10, 17),
- GetCSharpResultAt(11, 17),
- GetCSharpResultAt(12, 17),
-
- GetCSharpResultAt(15, 17),
- GetCSharpResultAt(16, 17),
- GetCSharpResultAt(17, 17),
- GetCSharpResultAt(18, 17));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(6));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method()
+ {|#0:" + invocation + @"("""", 1)|}
+ {|#1:" + invocation + @"(""{0}"", 1, 2)|}
+ {|#2:" + invocation + @"(""{0} {1}"", 1, 2, 3)|}
+ {|#3:" + invocation + @"(""{0} {1} {2}"", 1, 2, 3, 4)|}
+ {|#4:" + invocation + @"(""{0} {1} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|}
+ {|#5:" + invocation + @"(""{2} {0} {1}"", 1, 2, 3, 4)|}
+ {|#6:" + invocation + @"(""{0} {0}"", 1, 2)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(6));
}
- [Fact]
- public async Task CA2241CSharpConsoleWrite()
+ [Theory, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2241_TooManyArgsMissingFormatIndex_ConsoleWriteMethods_Diagnostic(string invocation)
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
@@ -63,82 +81,181 @@ public class C
{
void Method()
{
- Console.Write("""", 1);
- Console.Write(""{0}"", 1, 2);
- Console.Write(""{0} {1}"", 1, 2, 3);
- Console.Write(""{0} {1} {2}"", 1, 2, 3, 4);
- Console.Write(""{0} {1} {2} {3}"", 1, 2, 3, 4, 5);
+ {|#0:" + invocation + @"(""{1}"", 1, 2, 3)|};
+ {|#1:" + invocation + @"(""{2}"", 1, 2, 3, 4)|};
+ {|#2:" + invocation + @"(""{0} {2}"", 1, 2, 3, 4)|};
+ {|#3:" + invocation + @"(""{0} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|};
+ {|#4:" + invocation + @"(""{0} {2} {3} {5}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|};
+ {|#5:" + invocation + @"(""{5} {2} {3} {1}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|};
}
}
",
- GetCSharpResultAt(8, 9),
- GetCSharpResultAt(9, 9),
- GetCSharpResultAt(10, 9),
- GetCSharpResultAt(11, 9),
- GetCSharpResultAt(12, 9));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(5));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method()
+ {|#0:" + invocation + @"(""{1}"", 1, 2, 3)|}
+ {|#1:" + invocation + @"(""{2}"", 1, 2, 3, 4)|}
+ {|#2:" + invocation + @"(""{0} {2}"", 1, 2, 3, 4)|}
+ {|#3:" + invocation + @"(""{0} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|}
+ {|#4:" + invocation + @"(""{0} {2} {3} {5}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|}
+ {|#5:" + invocation + @"(""{5} {2} {3} {1}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(5));
}
[Fact]
- public async Task CA2241CSharpConsoleWriteLine()
+ public async Task CA2241_TooManyArgs_StringFormatMethods_Diagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
public class C
{
- void Method()
+ void Method(IFormatProvider formatProvider)
{
- Console.WriteLine("""", 1);
- Console.WriteLine(""{0}"", 1, 2);
- Console.WriteLine(""{0} {1}"", 1, 2, 3);
- Console.WriteLine(""{0} {1} {2}"", 1, 2, 3, 4);
- Console.WriteLine(""{0} {1} {2} {3}"", 1, 2, 3, 4, 5);
+ // Too many args
+ var a = {|#0:String.Format("""", 1)|};
+ var b = {|#1:String.Format(""{0}"", 1, 2)|};
+ var c = {|#2:String.Format(""{0} {1}"", 1, 2, 3)|};
+ var d = {|#3:String.Format(""{0} {1} {2}"", 1, 2, 3, 4)|};
+ var e = {|#4:String.Format(""{0} {1} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|};
+ var f = {|#5:string.Format(""{0} {0}"", 1, 2)|};
+
+ // Too many args with format provider
+ var g = {|#6:String.Format(formatProvider, """", 1)|};
+ var h = {|#7:String.Format(formatProvider, ""{0}"", 1, 2)|};
+ var i = {|#8:String.Format(formatProvider, ""{0} {1}"", 1, 2, 3)|};
+ var j = {|#9:String.Format(formatProvider, ""{0} {1} {2}"", 1, 2, 3, 4)|};
+ var k = {|#10:String.Format(formatProvider, ""{0} {0}"", 1, 2)|};
}
}
",
- GetCSharpResultAt(8, 9),
- GetCSharpResultAt(9, 9),
- GetCSharpResultAt(10, 9),
- GetCSharpResultAt(11, 9),
- GetCSharpResultAt(12, 9));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(6),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(7),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(8),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(10));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method(formatProvider As IFormatProvider)
+ ' Too many args
+ Dim a = {|#0:String.Format("""", 1)|}
+ Dim b = {|#1:String.Format(""{0}"", 1, 2)|}
+ Dim c = {|#2:String.Format(""{0} {1}"", 1, 2, 3)|}
+ Dim d = {|#3:String.Format(""{0} {1} {2}"", 1, 2, 3, 4)|}
+ Dim e = {|#4:String.Format(""{0} {1} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|}
+ Dim f = {|#5:string.Format(""{0} {0}"", 1, 2)|}
+
+ ' Too many args with format provider
+ Dim g = {|#6:String.Format(formatProvider, """", 1)|}
+ Dim h = {|#7:String.Format(formatProvider, ""{0}"", 1, 2)|}
+ Dim i = {|#8:String.Format(formatProvider, ""{0} {1}"", 1, 2, 3)|}
+ Dim j = {|#9:String.Format(formatProvider, ""{0} {1} {2}"", 1, 2, 3, 4)|}
+ Dim k = {|#10:String.Format(formatProvider, ""{0} {0}"", 1, 2)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(6),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(7),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(8),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(10));
}
- [Fact]
- public async Task CA2241CSharpPassing()
+ [Fact, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ public async Task CA2241_TooManyArgsMissingFormatIndex_StringFormatMethods_Diagnostic()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
public class C
{
- void Method()
+ void Method(IFormatProvider formatProvider)
{
- var a = String.Format(""{0}"", 1);
- var b = String.Format(""{0} {1}"", 1, 2);
- 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);
+ // Too many args + missing format index
+ var a = {|#0:string.Format(""{1}"", 1, 2, 3)|};
+ var b = {|#1:string.Format(""{2}"", 1, 2, 3, 4)|};
+ var c = {|#2:string.Format(""{0} {2}"", 1, 2, 3, 4)|};
+ var d = {|#3:string.Format(""{0} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|};
+ var e = {|#4:string.Format(""{0} {2} {3} {5}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|};
- Console.Write(""{0}"", 1);
- Console.Write(""{0} {1}"", 1, 2);
- Console.Write(""{0} {1} {2}"", 1, 2, 3);
- 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.WriteLine(""{0}"", 1);
- Console.WriteLine(""{0} {1}"", 1, 2);
- Console.WriteLine(""{0} {1} {2}"", 1, 2, 3);
- 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);
+ // Too many args with format provider + missing format index
+ var f = {|#5:string.Format(formatProvider, ""{1}"", 1, 2, 3)|};
+ var g = {|#6:string.Format(formatProvider, ""{2}"", 1, 2, 3, 4)|};
+ var h = {|#7:string.Format(formatProvider, ""{0} {2}"", 1, 2, 3, 4)|};
}
}
-");
+",
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(7));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method(formatProvider As IFormatProvider)
+ ' Too many args + missing format index
+ Dim a = {|#0:string.Format(""{1}"", 1, 2, 3)|}
+ Dim b = {|#1:string.Format(""{2}"", 1, 2, 3, 4)|}
+ Dim c = {|#2:string.Format(""{0} {2}"", 1, 2, 3, 4)|}
+ Dim d = {|#3:string.Format(""{0} {2}"", 1, 2, 3, 4, 5, 6, 7, 8)|}
+ Dim e = {|#4:string.Format(""{0} {2} {3} {5}"", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)|}
+
+ ' Too many args with format provider + missing format index
+ Dim f = {|#5:string.Format(formatProvider, ""{1}"", 1, 2, 3)|}
+ Dim g = {|#6:string.Format(formatProvider, ""{2}"", 1, 2, 3, 4)|}
+ Dim h = {|#7:string.Format(formatProvider, ""{0} {2}"", 1, 2, 3, 4)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(7));
}
- [Fact]
- public async Task CA2241CSharpExplicitObjectArraySupported()
+ [Theory]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2250_NotEnoughArgs_ConsoleWriteMethods_Diagnostic(string invocation)
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
@@ -147,134 +264,361 @@ public class C
{
void Method()
{
- var s = String.Format(""{0} {1} {2} {3}"", new object[] {1, 2});
- Console.Write(""{0} {1} {2} {3}"", new object[] {1, 2, 3, 4, 5});
- Console.WriteLine(""{0} {1} {2} {3}"", new object[] {1, 2, 3, 4, 5});
+ {|#0:" + invocation + @"(""{0} {1}"", 1)|};
+ {|#1:" + invocation + @"(""{0} {1} {2}"", 1, 2)|};
+ {|#2:" + invocation + @"(""{0} {1} {2}"", 1)|};
+ {|#3:" + invocation + @"(""{2} {0} {1}"", 1)|};
+ {|#4:" + invocation + @"(""{1} {0} {1}"", 1)|};
}
}
",
- GetCSharpResultAt(8, 17),
- GetCSharpResultAt(9, 9),
- GetCSharpResultAt(10, 9));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(4));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method()
+ {|#0:" + invocation + @"(""{0} {1}"", 1)|}
+ {|#1:" + invocation + @"(""{0} {1} {2}"", 1, 2)|}
+ {|#2:" + invocation + @"(""{0} {1} {2}"", 1)|}
+ {|#3:" + invocation + @"(""{2} {0} {1}"", 1)|}
+ {|#4:" + invocation + @"(""{1} {0} {1}"", 1)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(4));
}
- [Fact]
- public async Task CA2241CSharpVarArgsNotSupported()
+ [Theory, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2250_NotEnoughArgsMissingFormatIndexRule_ConsoleWriteMethods_Diagnostic(string invocation)
{
- // currently not supported due to "https://github.com/dotnet/roslyn/issues/7346"
- await new VerifyCS.Test
- {
- ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net472.Default,
- TestCode = @"
+ await VerifyCS.VerifyAnalyzerAsync(@"
using System;
public class C
{
void Method()
{
- Console.Write(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, __arglist(5));
- Console.WriteLine(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, __arglist(5));
+ {|#0:" + invocation + @"(""{1}"", 1)|};
+ {|#1:" + invocation + @"(""{1} {2}"", 1, 2)|};
+ {|#2:" + invocation + @"(""{2} {0}"", 1, 2)|};
+ {|#3:" + invocation + @"(""{4} {1} {2}"", 1, 2, 3)|};
}
}
",
- }.RunAsync();
- }
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3));
- [Fact]
- public async Task CA2241VBString()
- {
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Public Class C
Sub Method()
- Dim a = String.Format("""", 1)
- Dim b = String.Format(""{0}"", 1, 2)
- Dim c = String.Format(""{0} {1}"", 1, 2, 3)
- Dim d = String.Format(""{0} {1} {2}"", 1, 2, 3, 4)
-
- Dim p as IFormatProvider = Nothing
- Dim e = String.Format(p, """", 1)
- Dim f = String.Format(p, ""{0}"", 1, 2)
- Dim g = String.Format(p, ""{0} {1}"", 1, 2, 3)
- Dim h = String.Format(p, ""{0} {1} {2}"", 1, 2, 3, 4)
+ {|#0:" + invocation + @"(""{1}"", 1)|}
+ {|#1:" + invocation + @"(""{1} {2}"", 1, 2)|}
+ {|#2:" + invocation + @"(""{2} {0}"", 1, 2)|}
+ {|#3:" + invocation + @"(""{4} {1} {2}"", 1, 2, 3)|}
End Sub
-End Class
-",
- GetBasicResultAt(6, 17),
- GetBasicResultAt(7, 17),
- GetBasicResultAt(8, 17),
- GetBasicResultAt(9, 17),
-
- GetBasicResultAt(12, 17),
- GetBasicResultAt(13, 17),
- GetBasicResultAt(14, 17),
- GetBasicResultAt(15, 17));
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3));
}
[Fact]
- public async Task CA2241VBConsoleWrite()
+ public async Task CA2250_NotEnoughArgs_StringFormatMethods_Diagnostic()
{
- // this works in VB
- // Dim s = Console.WriteLine(""{0} {1} {2}"", 1, 2, 3, 4)
- // since VB bind it to __arglist version where we skip analysis
- // due to a bug - https://github.com/dotnet/roslyn/issues/7346
- // we might skip it only in C# since VB doesn't support __arglist
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Method(IFormatProvider formatProvider)
+ {
+ // Not enough args
+ var a = {|#0:String.Format(""{0}"")|};
+ var b = {|#1:String.Format(""{0} {1}"", 1)|};
+ var c = {|#2:String.Format(""{0} {1} {2}"", 1, 2)|};
+ var d = {|#3:String.Format(""{0} {1} {2}"", 1)|};
+ var e = {|#4:String.Format(""{2} {0} {1}"", 1)|};
+ var f = {|#5:String.Format(""{1} {0} {1}"", 1)|};
+
+ // Not enough args with format provider
+ var g = {|#6:String.Format(formatProvider, ""{0}"")|};
+ var h = {|#7:String.Format(formatProvider, ""{0} {1}"", 1)|};
+ var i = {|#8:String.Format(formatProvider, ""{0} {1} {2}"", 1, 2)|};
+ var j = {|#9:String.Format(formatProvider, ""{0} {1} {2}"", 1)|};
+ var k = {|#10:String.Format(formatProvider, ""{2} {0} {1}"", 1)|};
+ var l = {|#11:String.Format(formatProvider, ""{1} {0} {1}"", 1)|};
+ }
+}
+",
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(6),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(7),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(8),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(9),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(10),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(11));
+
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Public Class C
- Sub Method()
- Console.Write("""", 1)
- Console.Write(""{0}"", 1, 2)
- Console.Write(""{0} {1}"", 1, 2, 3)
- Console.Write(""{0} {1} {2}"", 1, 2, 3, 4)
- Console.Write(""{0} {1} {2} {3}"", 1, 2, 3, 4, 5)
+ Sub Method(formatProvider As IFormatProvider)
+ ' Not enough args
+ Dim a = {|#0:String.Format(""{0}"")|}
+ Dim b = {|#1:String.Format(""{0} {1}"", 1)|}
+ Dim c = {|#2:String.Format(""{0} {1} {2}"", 1, 2)|}
+ Dim d = {|#3:String.Format(""{0} {1} {2}"", 1)|}
+ Dim e = {|#4:String.Format(""{2} {0} {1}"", 1)|}
+ Dim f = {|#5:String.Format(""{1} {0} {1}"", 1)|}
+
+ ' Not enough args with format provider
+ Dim g = {|#6:String.Format(formatProvider, ""{0}"")|}
+ Dim h = {|#7:String.Format(formatProvider, ""{0} {1}"", 1)|}
+ Dim i = {|#8:String.Format(formatProvider, ""{0} {1} {2}"", 1, 2)|}
+ Dim j = {|#9:String.Format(formatProvider, ""{0} {1} {2}"", 1)|}
+ Dim k = {|#10:String.Format(formatProvider, ""{2} {0} {1}"", 1)|}
+ Dim l = {|#11:String.Format(formatProvider, ""{1} {0} {1}"", 1)|}
End Sub
-End Class
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(6),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(7),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(8),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(9),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(10),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(11));
+ }
+
+ [Fact, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ public async Task CA2250_NotEnoughArgsMissingFormatIndex_StringFormatMethods_Diagnostic()
+ {
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Method(IFormatProvider formatProvider)
+ {
+ // Not enough args + missing format index
+ var a = {|#0:String.Format(""{1}"")|};
+ var b = {|#1:String.Format(""{1}"", 1)|};
+ var c = {|#2:String.Format(""{2}"", 1, 2)|};
+ var d = {|#3:String.Format(""{2} {0}"", 1)|};
+
+ // Not enough args with format provider + missing format index
+ var e = {|#4:String.Format(formatProvider, ""{1}"")|};
+ var f = {|#5:String.Format(formatProvider, ""{1}"", 1)|};
+ var g = {|#6:String.Format(formatProvider, ""{2}"", 1, 2)|};
+ var h = {|#7:String.Format(formatProvider, ""{2} {0}"", 1)|};
+ }
+}
",
- GetBasicResultAt(6, 9),
- GetBasicResultAt(7, 9),
- GetBasicResultAt(8, 9),
-#if NETCOREAPP
- GetBasicResultAt(9, 9),
-#endif
- GetBasicResultAt(10, 9));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(7));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method(formatProvider As IFormatProvider)
+ ' Not enough args + missing format index
+ Dim a = {|#0:String.Format(""{1}"")|}
+ Dim b = {|#1:String.Format(""{1}"", 1)|}
+ Dim c = {|#2:String.Format(""{2}"", 1, 2)|}
+ Dim d = {|#3:String.Format(""{2} {0}"", 1)|}
+
+ ' Not enough args with format provider + missing format index
+ Dim e = {|#4:String.Format(formatProvider, ""{1}"")|}
+ Dim f = {|#5:String.Format(formatProvider, ""{1}"", 1)|}
+ Dim g = {|#6:String.Format(formatProvider, ""{2}"", 1, 2)|}
+ Dim h = {|#7:String.Format(formatProvider, ""{2} {0}"", 1)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(7));
}
- [Fact]
- public async Task CA2241VBConsoleWriteLine()
+ [Theory, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2241_EnoughArgsMissingFormatIndex_ConsoleWriteMethods_Diagnostic(string invocation)
{
- // this works in VB
- // Dim s = Console.WriteLine(""{0} {1} {2}"", 1, 2, 3, 4)
- // since VB bind it to __arglist version where we skip analysis
- // due to a bug - https://github.com/dotnet/roslyn/issues/7346
- // we might skip it only in C# since VB doesn't support __arglist
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Method()
+ {
+ {|#0:" + invocation + @"(""{1}"", 1, 2)|};
+ {|#1:" + invocation + @"(""{1} {2}"", 1, 2, 3)|};
+ {|#2:" + invocation + @"(""{2} {0}"", 1, 2, 3)|};
+ {|#3:" + invocation + @"(""{4} {1} {2}"", 1, 2, 3, 4, 5)|};
+ {|#4:" + invocation + @"(""{0} {2} {0} {2}"", 1, 2, 3)|};
+ }
+}
+",
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
+
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Public Class C
Sub Method()
- Console.WriteLine("""", 1)
- Console.WriteLine(""{0}"", 1, 2)
- Console.WriteLine(""{0} {1}"", 1, 2, 3)
- Console.WriteLine(""{0} {1} {2}"", 1, 2, 3, 4)
- Console.WriteLine(""{0} {1} {2} {3}"", 1, 2, 3, 4, 5)
+ {|#0:" + invocation + @"(""{1}"", 1, 2)|}
+ {|#1:" + invocation + @"(""{1} {2}"", 1, 2, 3)|}
+ {|#2:" + invocation + @"(""{2} {0}"", 1, 2, 3)|}
+ {|#3:" + invocation + @"(""{4} {1} {2}"", 1, 2, 3, 4, 5)|}
+ {|#4:" + invocation + @"(""{0} {2} {0} {2}"", 1, 2, 3)|}
End Sub
-End Class
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
+ }
+
+ [Fact, WorkItem(1254, "https://github.com/dotnet/roslyn-analyzers/issues/1254")]
+ public async Task CA2241_EnoughArgsMissingFormatIndex_StringFormatMethods_Diagnostic()
+ {
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Method(IFormatProvider formatProvider)
+ {
+ var a = {|#0:string.Format(""{1}"", 1, 2)|};
+ var b = {|#1:string.Format(""{1} {2}"", 1, 2, 3)|};
+ var c = {|#2:string.Format(""{2} {0}"", 1, 2, 3)|};
+ var d = {|#3:string.Format(""{4} {1} {2}"", 1, 2, 3, 4, 5)|};
+ var e = {|#4:string.Format(""{0} {2} {0} {2}"", 1, 2, 3)|};
+
+ var f = {|#5:string.Format(formatProvider, ""{1}"", 1, 2)|};
+ var g = {|#6:string.Format(formatProvider, ""{1} {2}"", 1, 2, 3)|};
+ var h = {|#7:string.Format(formatProvider, ""{2} {0}"", 1, 2, 3)|};
+ var i = {|#8:string.Format(formatProvider, ""{4} {1} {2}"", 1, 2, 3, 4, 5)|};
+ var j = {|#9:string.Format(formatProvider, ""{0} {2} {0} {2}"", 1, 2, 3)|};
+ }
+}
",
- GetBasicResultAt(6, 9),
- GetBasicResultAt(7, 9),
- GetBasicResultAt(8, 9),
-#if NETCOREAPP
- GetBasicResultAt(9, 9),
-#endif
- GetBasicResultAt(10, 9));
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(7),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(8),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(9));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Method(formatProvider As IFormatProvider)
+ Dim a = {|#0:string.Format(""{1}"", 1, 2)|}
+ Dim b = {|#1:string.Format(""{1} {2}"", 1, 2, 3)|}
+ Dim c = {|#2:string.Format(""{2} {0}"", 1, 2, 3)|}
+ Dim d = {|#3:string.Format(""{4} {1} {2}"", 1, 2, 3, 4, 5)|}
+ Dim e = {|#4:string.Format(""{0} {2} {0} {2}"", 1, 2, 3)|}
+
+ Dim f = {|#5:string.Format(formatProvider, ""{1}"", 1, 2)|}
+ Dim g = {|#6:string.Format(formatProvider, ""{1} {2}"", 1, 2, 3)|}
+ Dim h = {|#7:string.Format(formatProvider, ""{2} {0}"", 1, 2, 3)|}
+ Dim i = {|#8:string.Format(formatProvider, ""{4} {1} {2}"", 1, 2, 3, 4, 5)|}
+ Dim j = {|#9:string.Format(formatProvider, ""{0} {2} {0} {2}"", 1, 2, 3)|}
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(5),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(6),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(7),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(8),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(9));
}
[Fact]
- public async Task CA2241VBPassing()
+ public async Task CA2241_ValidInvocation_NoDiagnostic()
{
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Method()
+ {
+ var a = String.Format(""{0}"", 1);
+ var b = String.Format(""{0} {1}"", 1, 2);
+ 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(""abc"");
+
+ Console.Write(""{0}"", 1);
+ Console.Write(""{0} {1}"", 1, 2);
+ Console.Write(""{0} {1} {2}"", 1, 2, 3);
+ 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.WriteLine(""{0}"", 1);
+ Console.WriteLine(""{0} {1}"", 1, 2);
+ Console.WriteLine(""{0} {1} {2}"", 1, 2, 3);
+ 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);
+ }
+}");
+
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
@@ -284,65 +628,200 @@ Sub Method()
Dim b = String.Format(""{0} {1}"", 1, 2)
Dim c = String.Format(""{0} {1} {2}"", 1, 2, 3)
Dim d = String.Format(""{0} {1} {2} {3}"", 1, 2, 3, 4)
+ Dim e = String.Format(""{0} {1} {2} {0}"", 1, 2, 3)
+ Dim f = String.Format(""abc"")
Console.Write(""{0}"", 1)
Console.Write(""{0} {1}"", 1, 2)
Console.Write(""{0} {1} {2}"", 1, 2, 3)
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} {0}"", 1, 2, 3)
Console.WriteLine(""{0}"", 1)
Console.WriteLine(""{0} {1}"", 1, 2)
Console.WriteLine(""{0} {1} {2}"", 1, 2, 3)
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} {0}"", 1, 2, 3)
End Sub
-End Class
-");
+End Class");
}
- [Fact]
- public async Task CA2241VBExplicitObjectArraySupported()
+ [Theory]
+ [InlineData("Console.Write")]
+ [InlineData("Console.WriteLine")]
+ public async Task CA2241_CA2250_ExplicitObjectArray_ConsoleWriteMethods(string invocation)
{
+ await VerifyCS.VerifyAnalyzerAsync(@"
+using System;
+
+public class C
+{
+ void Diag()
+ {
+ // Too many args
+ {|#0:" + invocation + @"(""{0} {1} {2}"", new object[] { 1, 2, 3, 4 })|};
+ // Too many args + missing format index
+ {|#1:" + invocation + @"(""{0} {2}"", new object[] { 1, 2, 3, 4 })|};
+ // Not enough args
+ {|#2:" + invocation + @"(""{0} {1} {2}"", new object[] { 1, 2 })|};
+ // Not enough args + missing format index
+ {|#3:" + invocation + @"(""{0} {2}"", new object[] { 1, 2 })|};
+ // Enough args but missing format index
+ {|#4:" + invocation + @"(""{0} {2}"", new object[] { 1, 2, 3 })|};
+ }
+
+ void NoDiag()
+ {
+ " + invocation + @"(""{0} {1} {2}"", new object[] { 1, 2, 3 });
+ }
+}
+",
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
+
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Public Class C
- Sub Method()
- Dim s = String.Format(""{0} {1} {2} {3}"", New Object() {1, 2})
- Console.Write(""{0} {1} {2} {3}"", New Object() {1, 2, 3, 4, 5})
- Console.WriteLine(""{0} {1} {2} {3}"", New Object() {1, 2, 3, 4, 5})
+ Sub Diag()
+ ' Too many args
+ {|#0:" + invocation + @"(""{0} {1} {2}"", New Object() { 1, 2, 3, 4 })|}
+ ' Too many args + missing format index
+ {|#1:" + invocation + @"(""{0} {2}"", New Object() { 1, 2, 3, 4 })|}
+ ' Not enough args
+ {|#2:" + invocation + @"(""{0} {1} {2}"", New Object() { 1, 2 })|}
+ ' Not enough args + missing format index
+ {|#3:" + invocation + @"(""{0} {2}"", New Object() { 1, 2 })|}
+ ' Enough args but missing format index
+ {|#4:" + invocation + @"(""{0} {2}"", New Object() { 1, 2, 3 })|}
End Sub
-End Class
-",
- GetBasicResultAt(6, 17),
- GetBasicResultAt(7, 9),
- GetBasicResultAt(8, 9));
+
+ Sub NoDiag()
+ " + invocation + @"(""{0} {1} {2}"", New Object() { 1, 2, 3 })
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
}
[Fact]
- public async Task CA2241CSharpFormatStringParser()
+ public async Task CA2241_CA2250_ExplicitObjectArray_StringFormatMethods()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
public class C
{
- void Method()
+ void Diag()
{
- var a = String.Format(""{0,-4 :xd}"", 1);
- var b = String.Format(""{0 , 5 : d} {1}"", 1, 2);
- var c = String.Format(""{0:d} {1} {2}"", 1, 2, 3);
- var d = String.Format(""{0, 5} {1} {2} {3}"", 1, 2, 3, 4);
-
- Console.Write(""{0,1}"", 1);
- Console.Write(""{0: x} {1}"", 1, 2);
- Console.Write(""{{escape}}{0} {1} {2}"", 1, 2, 3);
- Console.Write(""{0: {{escape}} x} {1} {2} {3}"", 1, 2, 3, 4);
- Console.Write(""{0 , -10 : {{escape}} y} {1} {2} {3} {4}"", 1, 2, 3, 4, 5);
+ // Too many args
+ var a = {|#0:string.Format(""{0} {1} {2}"", new object[] { 1, 2, 3, 4 })|};
+ // Too many args + missing format index
+ var b = {|#1:string.Format(""{0} {2}"", new object[] { 1, 2, 3, 4 })|};
+ // Not enough args
+ var c = {|#2:string.Format(""{0} {1} {2}"", new object[] { 1, 2 })|};
+ // Not enough args + missing format index
+ var d = {|#3:string.Format(""{0} {2}"", new object[] { 1, 2 })|};
+ // Enough args but missing format index
+ var e = {|#4:string.Format(""{0} {2}"", new object[] { 1, 2, 3 })|};
+ }
+
+ void NoDiag()
+ {
+ var s = String.Format(""{0} {1} {2}"", new object[] { 1, 2, 3 });
}
}
-");
+",
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
+
+ await VerifyVB.VerifyAnalyzerAsync(@"
+Imports System
+
+Public Class C
+ Sub Diag()
+ ' Too many args
+ Dim a = {|#0:string.Format(""{0} {1} {2}"", New Object() { 1, 2, 3, 4 })|}
+ ' Too many args + missing format index
+ Dim b = {|#1:string.Format(""{0} {2}"", New Object() { 1, 2, 3, 4 })|}
+ ' Not enough args
+ Dim c = {|#2:string.Format(""{0} {1} {2}"", New Object() { 1, 2 })|}
+ ' Not enough args + missing format index
+ Dim d = {|#3:string.Format(""{0} {2}"", New Object() { 1, 2 })|}
+ ' Enough args but missing format index
+ Dim e = {|#4:string.Format(""{0} {2}"", New Object() { 1, 2, 3 })|}
+ End Sub
+
+ Sub NoDiag()
+ Dim s = String.Format(""{0} {1} {2}"", New Object() { 1, 2, 3 })
+ End Sub
+End Class",
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(0),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(1),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(2),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(3),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(4));
+ }
+
+ [Fact]
+ public async Task CA2241_CA2250_CSharp_VarArgsNotSupported()
+ {
+ await new VerifyCS.Test
+ {
+ ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net472.Default,
+ TestCode = @"
+ using System;
+
+ public class C
+ {
+ void Method()
+ {
+ Console.Write(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, __arglist(5));
+ Console.WriteLine(""{0} {1} {2} {3} {4}"", 1, 2, 3, 4, __arglist(5));
+
+ Console.Write(""{0} {1}"", 1, 2, 3, 4, __arglist(5));
+ Console.WriteLine(""{0} {1}"", 1, 2, 3, 4, __arglist(5));
+
+ Console.Write(""{0} {1} {2} {3} {4} {5} {6}"", 1, 2, 3, 4, __arglist(5));
+ Console.WriteLine(""{0} {1} {2} {3} {4} {5} {6}"", 1, 2, 3, 4, __arglist(5));
+ }
+ }
+ ",
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task CA2241_CA2250_FormatStringParser_NoDiagnostic()
+ {
+ await VerifyCS.VerifyAnalyzerAsync(@"
+ using System;
+
+ public class C
+ {
+ void Method()
+ {
+ var a = String.Format(""{0,-4 :xd}"", 1);
+ var b = String.Format(""{0 , 5 : d} {1}"", 1, 2);
+ var c = String.Format(""{0:d} {1} {2}"", 1, 2, 3);
+ var d = String.Format(""{0, 5} {1} {2} {3}"", 1, 2, 3, 4);
+
+ Console.Write(""{0,1}"", 1);
+ Console.Write(""{0: x} {1}"", 1, 2);
+ Console.Write(""{{escape}}{0} {1} {2}"", 1, 2, 3);
+ Console.Write(""{0: {{escape}} x} {1} {2} {3}"", 1, 2, 3, 4);
+ Console.Write(""{0 , -10 : {{escape}} y} {1} {2} {3} {4}"", 1, 2, 3, 4, 5);
+ }
+ }
+ ");
}
[Theory]
@@ -353,7 +832,7 @@ void Method()
[InlineData(false)]
// Configured and enabled
[InlineData(true)]
- public async Task EditorConfigConfiguration_HeuristicAdditionalStringFormattingMethods(bool? editorConfig)
+ public async Task CA2241_CA2250_EditorConfigConfiguration_HeuristicAdditionalStringFormattingMethods(bool? editorConfig)
{
string editorConfigText = editorConfig == null ? string.Empty :
"dotnet_code_quality.try_determine_additional_string_formatting_methods_automatically = " + editorConfig.Value;
@@ -371,7 +850,18 @@ class Test
void M1(string param)
{
- var a = MyFormat("""", 1);
+ // Too many args
+ var s1 = MyFormat(""{0}"", 1, 2);
+ // Too many args and missing format index
+ var s2 = MyFormat(""{1}"", 1, 2, 3);
+
+ // Not enough args
+ var s3 = MyFormat(""{0} {1}"", 1);
+ // Not enough args and missing format index
+ var s4 = MyFormat(""{0} {2}"", 1);
+
+ // Enough args and missing format index
+ var s5 = MyFormat(""{1}"", 1, 2);
}
}"
},
@@ -381,9 +871,14 @@ void M1(string param)
if (editorConfig == true)
{
- csharpTest.ExpectedDiagnostics.Add(
- // Test0.cs(8,17): warning CA2241: Provide correct arguments to formatting methods
- GetCSharpResultAt(8, 17));
+ csharpTest.ExpectedDiagnostics.AddRange(new[]
+ {
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(11, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(14, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(16, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(19, 18),
+ });
}
await csharpTest.RunAsync();
@@ -401,7 +896,18 @@ Return format
End Function
Private Sub M1(ByVal param As String)
- Dim a = MyFormat("""", 1)
+ ' Too many args
+ Dim s1 = MyFormat(""{0}"", 1, 2)
+ ' Too many args and missing format index
+ Dim s2 = MyFormat(""{1}"", 1, 2, 3)
+
+ ' Not enough args
+ Dim s3 = MyFormat(""{0} {1}"", 1)
+ ' Not enough args and missing format index
+ Dim s4 = MyFormat(""{0} {2}"", 1)
+
+ ' Enough args and missing format index
+ Dim s5 = MyFormat(""{1}"", 1, 2)
End Sub
End Class"
},
@@ -411,9 +917,14 @@ End Class"
if (editorConfig == true)
{
- basicTest.ExpectedDiagnostics.Add(
- // Test0.vb(8,17): warning CA2241: Provide correct arguments to formatting methods
- GetBasicResultAt(8, 17));
+ basicTest.ExpectedDiagnostics.AddRange(new[]
+ {
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(11, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(14, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(16, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(19, 18),
+ });
}
await basicTest.RunAsync();
@@ -426,12 +937,15 @@ End Class"
// Match by method name
[InlineData("dotnet_code_quality.additional_string_formatting_methods = MyFormat")]
// Setting only for Rule ID
- [InlineData("dotnet_code_quality." + ProvideCorrectArgumentsToFormattingMethodsAnalyzer.RuleId + ".additional_string_formatting_methods = MyFormat")]
+ [InlineData(@"dotnet_code_quality.CA2241.additional_string_formatting_methods = MyFormat
+ dotnet_code_quality.CA2250.additional_string_formatting_methods = MyFormat")]
+ [InlineData(@"dotnet_code_quality.CA2241.additional_string_formatting_methods = MyFormat")]
+ [InlineData(@"dotnet_code_quality.CA2250.additional_string_formatting_methods = MyFormat")]
// Match by documentation ID without "M:" prefix
[InlineData("dotnet_code_quality.additional_string_formatting_methods = Test.MyFormat(System.String,System.Object[])~System.String")]
// Match by documentation ID with "M:" prefix
[InlineData("dotnet_code_quality.additional_string_formatting_methods = M:Test.MyFormat(System.String,System.Object[])~System.String")]
- public async Task EditorConfigConfiguration_AdditionalStringFormattingMethods(string editorConfigText)
+ public async Task CA2241_CA2250_EditorConfigConfiguration_AdditionalStringFormattingMethods(string editorConfigText)
{
var csharpTest = new VerifyCS.Test
{
@@ -446,7 +960,18 @@ class Test
void M1(string param)
{
- var a = MyFormat("""", 1);
+ // Too many args
+ var s1 = MyFormat(""{0}"", 1, 2);
+ // Too many args and missing format index
+ var s2 = MyFormat(""{1}"", 1, 2, 3);
+
+ // Not enough args
+ var s3 = MyFormat(""{0} {1}"", 1);
+ // Not enough args and missing format index
+ var s4 = MyFormat(""{0} {2}"", 1);
+
+ // Enough args and missing format index
+ var s5 = MyFormat(""{1}"", 1, 2);
}
}"
},
@@ -456,9 +981,15 @@ void M1(string param)
if (editorConfigText.Length > 0)
{
- csharpTest.ExpectedDiagnostics.Add(
- // Test0.cs(8,17): warning CA2241: Provide correct arguments to formatting methods
- GetCSharpResultAt(8, 17));
+ // TODO: Make sure to report only the right diagnostic not both
+ csharpTest.ExpectedDiagnostics.AddRange(new[]
+ {
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(11, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(14, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(16, 18),
+ VerifyCS.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(19, 18),
+ });
}
await csharpTest.RunAsync();
@@ -476,7 +1007,18 @@ Return format
End Function
Private Sub M1(ByVal param As String)
- Dim a = MyFormat("""", 1)
+ ' Too many args
+ Dim s1 = MyFormat(""{0}"", 1, 2)
+ ' Too many args and missing format index
+ Dim s2 = MyFormat(""{1}"", 1, 2, 3)
+
+ ' Not enough args
+ Dim s3 = MyFormat(""{0} {1}"", 1)
+ ' Not enough args and missing format index
+ Dim s4 = MyFormat(""{0} {2}"", 1)
+
+ ' Enough args and missing format index
+ Dim s5 = MyFormat(""{1}"", 1, 2)
End Sub
End Class"
},
@@ -486,22 +1028,18 @@ End Class"
if (editorConfigText.Length > 0)
{
- basicTest.ExpectedDiagnostics.Add(
- // Test0.vb(8,17): warning CA2241: Provide correct arguments to formatting methods
- GetBasicResultAt(8, 17));
+ // TODO: Make sure to report only the right diagnostic not both
+ basicTest.ExpectedDiagnostics.AddRange(new[]
+ {
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsRule).WithLocation(9, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.TooManyArgsMissingFormatIndexRule).WithLocation(11, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsRule).WithLocation(14, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.NotEnoughArgsMissingFormatIndexRule).WithLocation(16, 18),
+ VerifyVB.Diagnostic(ProvideCorrectArgumentsToFormattingMethodsAnalyzer.EnoughArgsMissingFormatIndexRule).WithLocation(19, 18),
+ });
}
await basicTest.RunAsync();
}
-
- #endregion
-
- private static DiagnosticResult GetCSharpResultAt(int line, int column)
- => VerifyCS.Diagnostic()
- .WithLocation(line, column);
-
- private static DiagnosticResult GetBasicResultAt(int line, int column)
- => VerifyVB.Diagnostic()
- .WithLocation(line, column);
}
}
\ No newline at end of file
diff --git a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
index 7baccb8b66..8366c30f30 100644
--- a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
+++ b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt
@@ -14,7 +14,7 @@ Globalization: CA2101, CA1300-CA1310
Mobility: CA1600-CA1601
Performance: HA, CA1800-CA1838
Security: CA2100-CA2153, CA2300-CA2330, CA3000-CA3147, CA5300-CA5403
-Usage: CA1801, CA1806, CA1816, CA2200-CA2209, CA2211-CA2249
+Usage: CA1801, CA1806, CA1816, CA2200-CA2209, CA2211-CA2250
Naming: CA1700-CA1726
Interoperability: CA1400-CA1417
Maintainability: CA1500-CA1509