SONARJAVA-5683 S2077 Fix FN on strings built with String.format()/formatted(). - #5246
Conversation
3424d8b to
119bacd
Compare
|
| private static boolean hasDynamicStringParameters(MethodInvocationTree mit) { | ||
| for (ExpressionTree arg: mit.arguments()) { | ||
| if (arg.symbolType().is(JAVA_LANG_STRING) && arg.asConstant().isEmpty()) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Is it intentional not to support String.format(String format, Object... args) when args is not a String?
For example, if the argument is a int. Why does the rule not support the following case?
public void formatIntVar(int input) throws SQLException {
String query = String.format("SELECT %s", input);
this.stmt.execute(query); // Noncompliant
}
public void formatIntConst() throws SQLException {
String query = String.format("SELECT %s", 1);
this.stmt.execute(query);
}
Could be done with this kind of logic:
| private static boolean hasDynamicStringParameters(MethodInvocationTree mit) { | |
| for (ExpressionTree arg: mit.arguments()) { | |
| if (arg.symbolType().is(JAVA_LANG_STRING) && arg.asConstant().isEmpty()) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| private static boolean hasDynamicStringParameters(MethodInvocationTree mit) { | |
| boolean firstArg = true; | |
| for (ExpressionTree arg: mit.arguments()) { | |
| Type type = arg.symbolType(); | |
| boolean notTheFirstLocaleArgument = !firstArg || !type.isUnknown() || !type.is("java.util.Locale"); | |
| if (notTheFirstLocaleArgument && arg.asConstant().isEmpty()) { | |
| return true; | |
| } | |
| firstArg = false; | |
| } | |
| return false; | |
| } |
There was a problem hiding this comment.
I had to change it due to a failing test and then expanded it to exclude primitive arguments as well. Please see code comments for details.
| // `format` has a variant with Locale as the first argument - we do not need to check that parameter. | ||
| boolean isFirstLocaleArgument = firstArg && !type.isUnknown() && type.is("java.util.Locale"); | ||
| // Primitives will not lead to SQL injection, so the code is compliant. | ||
| if (!isFirstLocaleArgument && !type.isPrimitive() && arg.asConstant().isEmpty()) { |
There was a problem hiding this comment.
We could also use isPrimitiveWrapper
There was a problem hiding this comment.
Done.
| for (ExpressionTree arg: mit.arguments()) { | ||
| Type type = arg.symbolType(); | ||
| // `format` has a variant with Locale as the first argument - we do not need to check that parameter. | ||
| boolean isFirstLocaleArgument = firstArg && !type.isUnknown() && type.is("java.util.Locale"); |
There was a problem hiding this comment.
&& !type.isUnknown() seems useless, remove or invert the logic
There was a problem hiding this comment.
Moved and tested.
|




SONARJAVA-5683