diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringHelper.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringHelper.cs index 9531dd1243..555582e605 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringHelper.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringHelper.cs @@ -36,14 +36,13 @@ namespace ICSharpCode.NRefactory.CSharp static string[] parameterNames = { "format", "frmt", "fmt" }; public static bool TryGetFormattingParameters(CSharpInvocationResolveResult invocationResolveResult, InvocationExpression invocationExpression, - out Expression formatArgument, out TextLocation formatStart, out IList arguments, + out Expression formatArgument, out IList arguments, Func argumentFilter) { if (argumentFilter == null) argumentFilter = (p, e) => true; formatArgument = null; - formatStart = default(TextLocation); arguments = new List(); var argumentToParameterMap = invocationResolveResult.GetArgumentToParameterMap(); var resolvedParameters = invocationResolveResult.Member.Parameters; @@ -51,15 +50,22 @@ namespace ICSharpCode.NRefactory.CSharp for (int i = 0; i < allArguments.Length; i++) { var parameterIndex = argumentToParameterMap[i]; if (parameterIndex < 0 || parameterIndex >= resolvedParameters.Count) { - // No valid mapping for this parameter, skip it + // No valid mapping for this argument, skip it continue; } var parameter = resolvedParameters[parameterIndex]; var argument = allArguments[i]; if (parameter.Type.IsKnownType(KnownTypeCode.String) && parameterNames.Contains(parameter.Name)) { formatArgument = argument; - formatStart = argument.StartLocation; - } else if ((formatArgument != null || parameter.IsParams) && argumentFilter(parameter, argument)) { + } else if (formatArgument != null && parameter.IsParams && !invocationResolveResult.IsExpandedForm) { + var ace = argument as ArrayCreateExpression; + if (ace == null || ace.Initializer.IsNull) + return false; + foreach (var element in ace.Initializer.Elements) { + if (argumentFilter(parameter, element)) + arguments.Add(argument); + } + } else if (formatArgument != null && argumentFilter(parameter, argument)) { arguments.Add(argument); } } diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs index 19b94d6ca2..7017b02d42 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs @@ -69,9 +69,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return; Expression formatArgument; IList formatArguments; - TextLocation formatStart; if (!FormatStringHelper.TryGetFormattingParameters(invocationResolveResult, invocationExpression, - out formatArgument, out formatStart, out formatArguments, null)) { + out formatArgument, out formatArguments, null)) { return; } var primitiveArgument = formatArgument as PrimitiveExpression; @@ -79,7 +78,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return; var format = (string)primitiveArgument.Value; var parsingResult = context.ParseFormatString(format); - CheckSegments(parsingResult.Segments, formatStart, formatArguments, invocationExpression); + CheckSegments(parsingResult.Segments, formatArgument.StartLocation, formatArguments, invocationExpression); } void CheckSegments(IList segments, TextLocation formatStart, IList formatArguments, AstNode anchor) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs index c0eb65ed33..eee0a69387 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs @@ -215,7 +215,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { Expression formatArgument; IList formatArguments; - TextLocation formatStart; // Only check parameters that are of type object: String means it is neccessary, others // means that there is another problem (ie no matching overload of the method). Func predicate = (parameter, argument) => { @@ -229,7 +228,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return typeDefinition.IsKnownType(KnownTypeCode.Object); }; if (FormatStringHelper.TryGetFormattingParameters(invocationResolveResult, invocationExpression, - out formatArgument, out formatStart, out formatArguments, predicate)) { + out formatArgument, out formatArguments, predicate)) { foreach (var argument in formatArguments) { CheckExpressionInAutoCallContext(argument); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/FormatStringIssues/FormatStringTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/FormatStringIssues/FormatStringTests.cs index ca1ca48751..ce0fb277f6 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/FormatStringIssues/FormatStringTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/FormatStringIssues/FormatStringTests.cs @@ -70,6 +70,23 @@ class TestClass Assert.AreEqual (0, issues.Count); } + [Test] + public void IgnoresCallWithUnknownNumberOfArguments() + { + var input = @" +class TestClass +{ + string Bar(params object[] args) + { + return string.Format(""{1}"", args); + } +}"; + + TestRefactoringContext context; + var issues = GetIssues (new FormatStringIssue (), input, out context); + Assert.AreEqual (0, issues.Count); + } + [Test] public void FormatItemIndexOutOfRangeOfArguments() { @@ -87,6 +104,23 @@ class TestClass Assert.AreEqual (1, issues.Count); } + [Test] + public void FormatItemIndexOutOfRangeOfArguments_ExplicitArrayCreation() + { + var input = @" +class TestClass +{ + void Foo() + { + string.Format(""{1}"", new object[] { 1 }); + } +}"; + + TestRefactoringContext context; + var issues = GetIssues (new FormatStringIssue (), input, out context); + Assert.AreEqual (1, issues.Count); + } + [Test] public void FormatItemMissingEndBrace() { @@ -138,6 +172,23 @@ class TestClass Assert.AreEqual (0, issues.Count); } + [Test] + public void IgnoresStringWithGoodArguments_ExplicitArrayCreation() + { + var input = @" +class TestClass +{ + void Foo() + { + string.Format(""{1}"", new object[] { ""arg0"", ""arg1"" }); + } +}"; + + TestRefactoringContext context; + var issues = GetIssues (new FormatStringIssue (), input, out context); + Assert.AreEqual (0, issues.Count); + } + [Test] public void IgnoresNonFormattingCall() {