IG: check array argument to format call correctly (IDEA-171421)

This commit is contained in:
Bas Leijdekkers
2017-06-04 12:32:12 +02:00
parent 324e0f1dd1
commit 674b80a1a2
2 changed files with 54 additions and 10 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2016 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2017 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.FormatUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -130,12 +131,13 @@ public class MalformedFormatStringInspectionBase extends BaseInspection {
return;
}
final PsiExpressionList argumentList = expression.getArgumentList();
final PsiExpression[] arguments = argumentList.getExpressions();
final int formatArgumentIndex = findFirstStringArgumentIndex(arguments);
PsiExpression[] arguments = argumentList.getExpressions();
int formatArgumentIndex = findFirstStringArgumentIndex(arguments);
if (formatArgumentIndex < 0) {
return;
}
final PsiExpression formatArgument = arguments[formatArgumentIndex];
formatArgumentIndex++;
if (!ExpressionUtils.hasStringType(formatArgument) || !PsiUtil.isConstantExpression(formatArgument)) {
return;
}
@@ -147,7 +149,7 @@ public class MalformedFormatStringInspectionBase extends BaseInspection {
if (value == null) {
return;
}
final int argumentCount = arguments.length - (formatArgumentIndex + 1);
int argumentCount = arguments.length - (formatArgumentIndex);
final FormatDecode.Validator[] validators;
try {
validators = FormatDecode.decode(value, argumentCount);
@@ -156,20 +158,36 @@ public class MalformedFormatStringInspectionBase extends BaseInspection {
registerError(formatArgument, e);
return;
}
if (validators.length != argumentCount) {
if (argumentCount == 1) {
final PsiExpression argument = arguments[formatArgumentIndex + 1];
final PsiType argumentType = argument.getType();
if (argumentType instanceof PsiArrayType) {
if (argumentCount == 1) {
final PsiExpression argument = resolveIfPossible(arguments[formatArgumentIndex]);
final PsiType argumentType = argument.getType();
if (argumentType instanceof PsiArrayType) {
final PsiArrayInitializerExpression arrayInitializer;
if (argument instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)argument;
arrayInitializer = newExpression.getArrayInitializer();
}
else if (argument instanceof PsiArrayInitializerExpression) {
arrayInitializer = (PsiArrayInitializerExpression)argument;
}
else {
return;
}
if (arrayInitializer == null) {
return;
}
arguments = arrayInitializer.getInitializers();
argumentCount = arguments.length;
formatArgumentIndex = 0;
}
}
if (validators.length != argumentCount) {
registerMethodCallError(expression, validators, Integer.valueOf(argumentCount));
return;
}
for (int i = 0; i < validators.length; i++) {
final FormatDecode.Validator validator = validators[i];
final PsiExpression argument = arguments[i + formatArgumentIndex + 1];
final PsiExpression argument = arguments[i + formatArgumentIndex];
final PsiType argumentType = argument.getType();
if (argumentType == null) {
continue;
@@ -179,5 +197,21 @@ public class MalformedFormatStringInspectionBase extends BaseInspection {
}
}
}
private PsiExpression resolveIfPossible(PsiExpression expression) {
expression = ParenthesesUtils.stripParentheses(expression);
if (expression instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression;
final PsiElement target = referenceExpression.resolve();
if (target instanceof PsiVariable && target.getContainingFile() == expression.getContainingFile()) {
final PsiVariable variable = (PsiVariable)target;
final PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
return initializer;
}
}
}
return expression;
}
}
}
@@ -124,6 +124,16 @@ public class MalformedFormatString {
public String highlightBothArguments() {
return String.format("count 1: %f, count 2: %f", <warning descr="Argument type 'int' does not match the type of the format specifier '%f'">count1</warning>, <warning descr="Argument type 'int' does not match the type of the format specifier '%f'">count2</warning>);
}
void arrayArguments() {
String.format("%c", new Object[]{'a'});
String.<warning descr="Too many arguments for format string (found: 2, expected: 1)">format</warning>("%c", new Object[]{'a', 'b'});
String.<warning descr="Too few arguments for format string (found: 1, expected: 2)">format</warning>("%c %c", new Object[]{'a'});
Object[] array = new Object[]{<warning descr="Argument type 'String' does not match the type of the format specifier '%#s'">"the void"</warning>};
String.format("%#s", array);
Object[] array2 = {<warning descr="Argument type 'String' does not match the type of the format specifier '%#s'">"the void"</warning>};
String.format("%#s", array2);
}
}
class A {
void m(Formattable f) {