-
Notifications
You must be signed in to change notification settings - Fork 698
SONARJAVA-5683 S2077 Fix FN on strings built with String.format()/formatted(). #5246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also use isPrimitiveWrapper
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&& !type.isUnknown()
seems useless, remove or invert the logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved and tested.
|
SONARJAVA-5683