[java] InvalidLogMessageFormat detection failing when String.format used

- Fixes #3146
This commit is contained in:
Andreas Dangel committed 2021-03-02 18:36:11 +01:00
1 parent 5650b720b3
commit 954bcffb94
3 files changed
+63 -1

No files matched your search

+3
View File
@@ -16,6 +16,9 @@ This is a {{ site.pmd.release_type }} release.
### Fixed Issues
* java-errorprone
* [#3146](https://github.com/pmd/pmd/issues/3146): \[java] InvalidLogMessageFormat detection failing when String.format used
### API Changes
### External Contributions
@@ -15,6 +15,7 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTArrayInitializer;
@@ -23,6 +24,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTEnumBody;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
@@ -63,10 +65,31 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule {
LOGGERS = loggersMap;
}
private boolean formatIsStringFormat;
public InvalidLogMessageFormatRule() {
addRuleChainVisit(ASTImportDeclaration.class);
addRuleChainVisit(ASTName.class);
}
@Override
public void start(RuleContext ctx) {
formatIsStringFormat = false;
}
@Override
public Object visit(ASTImportDeclaration node, Object data) {
if (node.isStatic()) {
if ("java.lang.String.format".equals(node.getImportedName())) {
formatIsStringFormat = true;
}
if ("java.lang.String".equals(node.getImportedName()) && node.isImportOnDemand()) {
formatIsStringFormat = true;
}
}
return data;
}
@Override
public Object visit(final ASTName node, final Object data) {
final NameDeclaration nameDeclaration = node.getNameDeclaration();
@@ -111,8 +134,13 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule {
// remove the message parameter
final ASTExpression messageParam = argumentList.remove(0);
final int expectedArguments = expectedArguments(messageParam);
// ignore if String.format
if (isStringFormatCall(messageParam)) {
return data;
}
final int expectedArguments = expectedArguments(messageParam);
if (expectedArguments == -1) {
// ignore if we couldn't analyze the message parameter
return data;
@@ -213,6 +241,17 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule {
+ params.size();
}
private boolean isStringFormatCall(ASTExpression node) {
if (node.getNumChildren() > 0 && node.getChild(0) instanceof ASTPrimaryExpression
&& node.getChild(0).getNumChildren() > 0 && node.getChild(0).getChild(0) instanceof ASTPrimaryPrefix
&& node.getChild(0).getChild(0).getNumChildren() > 0 && node.getChild(0).getChild(0).getChild(0) instanceof ASTName) {
String name = node.getChild(0).getChild(0).getChild(0).getImage();
return "String.format".equals(name) || formatIsStringFormat && "format".equals(name);
}
return false;
}
private int expectedArguments(final ASTExpression node) {
int count = -1;
// look if the logger has a literal message
@@ -925,6 +925,26 @@ class TestInvalidLogMessageFormat {
}
private String getBriefDescription() { return ""; }
}
]]></code>
</test-code>
<test-code>
<description>[java] InvalidLogMessageFormat detection failing when String.format used #3146</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.lang.String.format;
class TestInvalidLogMessageFormat {
private static final Logger LOGGER = LoggerFactory.getLogger(TestInvalidLogMessageFormat.class);
public void testPMD() {
LOGGER.info(String.format("Skipping file %s because no parser could be found", getName()));
LOGGER.info(format("Skipping file %s", getName()));
}
private String getName() { return "the-name"; }
}
]]></code>
</test-code>