Skip to content

Commit df95d68

Browse files
benzonicoWohops
authored andcommitted
SONARJAVA-2588 Support java.util.Logging.log for S3457
1 parent 6702dd9 commit df95d68

3 files changed

Lines changed: 37 additions & 6 deletions

File tree

java-checks/src/main/java/org/sonar/java/checks/AbstractPrintfChecker.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.commons.lang.StringUtils;
2424
import org.sonar.java.checks.methods.AbstractMethodDetection;
2525
import org.sonar.java.matcher.MethodMatcher;
26+
import org.sonar.java.matcher.TypeCriteria;
2627
import org.sonar.plugins.java.api.tree.ExpressionTree;
2728
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
2829
import org.sonar.plugins.java.api.tree.NewArrayTree;
@@ -43,6 +44,10 @@ public abstract class AbstractPrintfChecker extends AbstractMethodDetection {
4344
private static final String FORMAT_METHOD_NAME = "format";
4445

4546
protected static final MethodMatcher MESSAGE_FORMAT = MethodMatcher.create().typeDefinition("java.text.MessageFormat").name(FORMAT_METHOD_NAME).withAnyParameters();
47+
protected static final MethodMatcher JAVA_UTIL_LOGGER = MethodMatcher.create().typeDefinition("java.util.logging.Logger").name("log")
48+
.addParameter("java.util.logging.Level")
49+
.addParameter("java.lang.String")
50+
.addParameter(TypeCriteria.anyType());
4651
protected static final Pattern MESSAGE_FORMAT_PATTERN = Pattern.compile("\\{(?<index>\\d+)(?<type>,\\w+)?(?<style>,[^}]*)?\\}");
4752

4853
@Override
@@ -54,7 +59,8 @@ protected List<MethodMatcher> getMethodInvocationMatchers() {
5459
MethodMatcher.create().typeDefinition("java.io.PrintStream").name("printf").withAnyParameters(),
5560
MethodMatcher.create().typeDefinition("java.io.PrintWriter").name(FORMAT_METHOD_NAME).withAnyParameters(),
5661
MethodMatcher.create().typeDefinition("java.io.PrintWriter").name("printf").withAnyParameters(),
57-
MESSAGE_FORMAT
62+
MESSAGE_FORMAT,
63+
JAVA_UTIL_LOGGER
5864
);
5965
}
6066

java-checks/src/main/java/org/sonar/java/checks/PrintfMisuseCheck.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
*/
2020
package org.sonar.java.checks;
2121

22+
import java.util.ArrayList;
23+
import java.util.Collection;
24+
import java.util.List;
25+
import java.util.Set;
2226
import org.sonar.check.Rule;
2327
import org.sonar.java.matcher.MethodMatcher;
2428
import org.sonar.java.matcher.TypeCriteria;
@@ -31,11 +35,6 @@
3135
import org.sonar.plugins.java.api.tree.NewArrayTree;
3236
import org.sonar.plugins.java.api.tree.Tree;
3337

34-
import java.util.ArrayList;
35-
import java.util.Collection;
36-
import java.util.List;
37-
import java.util.Set;
38-
3938
@Rule(key = "S3457")
4039
public class PrintfMisuseCheck extends AbstractPrintfChecker {
4140

@@ -51,6 +50,13 @@ protected void onMethodInvocationFound(MethodInvocationTree mit) {
5150
// only consider the static method
5251
return;
5352
}
53+
if (!isMessageFormat) {
54+
isMessageFormat = JAVA_UTIL_LOGGER.matches(mit);
55+
if (isMessageFormat && mit.arguments().get(2).symbolType().isSubtypeOf("java.lang.Throwable")) {
56+
// ignore formatting issues when last argument is a throwable
57+
return;
58+
}
59+
}
5460
// Check type of first argument:
5561
if (mit.arguments().get(0).symbolType().is("java.lang.String")) {
5662
formatStringTree = mit.arguments().get(0);

java-checks/src/test/files/checks/PrintfMisuseCheck.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,24 @@ void foo(Calendar c){
112112
MessageFormat.format("{0,number,#.#}{1}", new Object[42]); // Compliant - Not considered
113113
MessageFormat.format("value=\"'{'{0}'}'{1}\"", new Object[] {"value 1", "value 2"});
114114
MessageFormat.format("value=\"{0}'{'{1}'}'\"", new Object[] {"value 1", "value 2"});
115+
116+
java.util.logging.Logger logger;
117+
logger.log(java.util.logging.Level.SEVERE, "{0,number,$'#',##}", value); // Compliant
118+
logger.log(java.util.logging.Level.SEVERE, "Result ''{0}''.", 14); // Compliant
119+
logger.log(java.util.logging.Level.SEVERE, "Result '{0}'", 14); // Noncompliant {{String contains no format specifiers.}}
120+
logger.log(java.util.logging.Level.SEVERE, "Result ' {0}", 14);
121+
logger.log(java.util.logging.Level.SEVERE, "Result {{{0}}.", 14);
122+
logger.log(java.util.logging.Level.SEVERE, "Result {0}!", myObject.toString()); // Noncompliant {{No need to call toString "method()" as formatting and string conversion is done by the Formatter.}}
123+
logger.log(java.util.logging.Level.SEVERE, "Result {0}!", myObject.hashCode()); // Compliant
124+
logger.log(java.util.logging.Level.SEVERE, "Result yeah!", 14); // Noncompliant {{String contains no format specifiers.}}
125+
logger.log(java.util.logging.Level.SEVERE, "Result yeah!", new Exception()); // compliant, throwable parameter
126+
logger.log(java.util.logging.Level.SEVERE, "Result {1}!", 14);
127+
logger.log(java.util.logging.Level.SEVERE, "Result {0} and {1}!", 14);
128+
logger.log(java.util.logging.Level.SEVERE, "{0,number,#.#}{1}", new Object[] {0.07, "$"}); // Compliant
129+
logger.log(java.util.logging.Level.SEVERE, "{0,number,#.#}{1}", new Object[] {0.07});
130+
logger.log(java.util.logging.Level.SEVERE, "{0,number,#.#}{1}", objs); // Compliant - skipped as the array is not initialized in the method invocation
131+
logger.log(java.util.logging.Level.SEVERE, "{0,number,#.#}{1}", new Object[42]); // Compliant - Not considered
132+
logger.log(java.util.logging.Level.SEVERE, "value=\"'{'{0}'}'{1}\"", new Object[] {"value 1", "value 2"});
133+
logger.log(java.util.logging.Level.SEVERE, "value=\"{0}'{'{1}'}'\"", new Object[] {"value 1", "value 2"});
115134
}
116135
}

0 commit comments

Comments
 (0)