diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index efbb83fb66..fe5d6673bd 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -254,7 +254,7 @@ folder: pmd/rules * [IdempotentOperations](pmd_rules_java_errorprone.html#idempotentoperations): Avoid idempotent operations - they have no effect. * [ImportFromSamePackage](pmd_rules_java_errorprone.html#importfromsamepackage): There is no need to import a type that lives in the same package. * [InstantiationToGetClass](pmd_rules_java_errorprone.html#instantiationtogetclass): Avoid instantiating an object just to call getClass() on it; use the .class public member instead. -* [InvalidSlf4jMessageFormat](pmd_rules_java_errorprone.html#invalidslf4jmessageformat): Check for messages in slf4j loggers with non matching number of arguments and placeholders. +* [InvalidSlf4jMessageFormat](pmd_rules_java_errorprone.html#invalidslf4jmessageformat): Check for messages in slf4j and log4j2 loggers with non matching number of arguments and placehol... * [JumbledIncrementer](pmd_rules_java_errorprone.html#jumbledincrementer): Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. * [JUnitSpelling](pmd_rules_java_errorprone.html#junitspelling): Some JUnit framework methods are easy to misspell. * [JUnitStaticSuite](pmd_rules_java_errorprone.html#junitstaticsuite): The suite() method in a JUnit test needs to be both public and static. diff --git a/docs/pages/pmd/rules/java/errorprone.md b/docs/pages/pmd/rules/java/errorprone.md index 4af46319b9..09b3874264 100644 --- a/docs/pages/pmd/rules/java/errorprone.md +++ b/docs/pages/pmd/rules/java/errorprone.md @@ -2278,7 +2278,7 @@ Class c = String.class;{%endraw%} **Priority:** Low (5) -Check for messages in slf4j loggers with non matching number of arguments and placeholders. +Check for messages in slf4j and log4j2 loggers with non matching number of arguments and placeholders. **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.errorprone.InvalidSlf4jMessageFormatRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java) diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 2479508fbc..81a2ed49d2 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -4,6 +4,10 @@ pmd-java PMD Java + + 1.3.50 + + net.sourceforge.pmd pmd @@ -41,6 +45,32 @@ kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + src/test/java + src/test/kotlin + + + + + + 1.8 + org.jetbrains.kotlin @@ -92,6 +122,20 @@ pmd-java-checkstyle-suppressions.xml + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + none + + + default-testCompile + none + + + @@ -143,6 +187,18 @@ slf4j-api test + + org.apache.logging.log4j + log4j-api + 2.12.1 + test + + + org.apache.logging.log4j + log4j-core + 2.12.1 + test + junit junit @@ -169,5 +225,16 @@ assertj-core test + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java index 6534669cba..9b08a58431 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java @@ -7,8 +7,10 @@ package net.sourceforge.pmd.lang.java.rule.errorprone; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -43,12 +45,18 @@ import net.sourceforge.pmd.lang.symboltable.NameDeclaration; public class InvalidSlf4jMessageFormatRule extends AbstractJavaRule { private static final Logger LOG = Logger.getLogger(InvalidSlf4jMessageFormatRule.class.getName()); - private static final Set LOGGER_LEVELS; - private static final String LOGGER_CLASS = "org.slf4j.Logger"; + private static final Map> LOGGERS; static { - LOGGER_LEVELS = Collections - .unmodifiableSet(new HashSet(Arrays.asList("trace", "debug", "info", "warn", "error"))); + Map> loggersMap = new HashMap<>(); + + loggersMap.put("org.slf4j.Logger", Collections + .unmodifiableSet(new HashSet(Arrays.asList("trace", "debug", "info", "warn", "error")))); + loggersMap.put("org.apache.logging.log4j.Logger", Collections + .unmodifiableSet(new HashSet(Arrays.asList("trace", "debug", "info", "warn", "error", "fatal", "all")))); + + LOGGERS = Collections + .unmodifiableMap(new HashMap>(loggersMap)); } public InvalidSlf4jMessageFormatRule() { @@ -62,11 +70,13 @@ public class InvalidSlf4jMessageFormatRule extends AbstractJavaRule { if (!(nameDeclaration instanceof VariableNameDeclaration)) { return data; } - - // ignore non slf4j logger + final String loggingClass; + // ignore unsupported logger Class type = ((VariableNameDeclaration) nameDeclaration).getType(); - if (type == null || !type.getName().equals(LOGGER_CLASS)) { + if (type == null || !LOGGERS.containsKey(type.getName())) { return data; + } else { + loggingClass = type.getName(); } // get the node that contains the logger @@ -77,7 +87,7 @@ public class InvalidSlf4jMessageFormatRule extends AbstractJavaRule { .getImage().replace(nameDeclaration.getImage() + ".", ""); // ignore if not a log level - if (!LOGGER_LEVELS.contains(method)) { + if (!LOGGERS.get(loggingClass).contains(method)) { return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java index 30e201509d..59cfc83362 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java @@ -22,6 +22,7 @@ import net.sourceforge.pmd.util.NumericConstants; public class MoreThanOneLoggerRule extends AbstractJavaRule { private static final String LOG4J_LOGGER_NAME = "org.apache.log4j.Logger"; + private static final String LOG4J2_LOGGER_NAME = "org.apache.logging.log4j.Logger"; private static final String JAVA_LOGGER_NAME = "java.util.logging.Logger"; private static final String SLF4J_LOGGER_NAME = "org.slf4j.Logger"; @@ -72,7 +73,8 @@ public class MoreThanOneLoggerRule extends AbstractJavaRule { Class clazzType = ((ASTClassOrInterfaceType) classOrIntType).getType(); if (clazzType != null && (TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, LOG4J_LOGGER_NAME) - || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, JAVA_LOGGER_NAME) + || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, LOG4J2_LOGGER_NAME) + || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, JAVA_LOGGER_NAME) || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, SLF4J_LOGGER_NAME)) || clazzType == null && "Logger".equals(classOrIntType.getImage())) { ++count; diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 74e40ae08e..5dc4f6127b 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2063,7 +2063,7 @@ Class c = String.class; class="net.sourceforge.pmd.lang.java.rule.errorprone.InvalidSlf4jMessageFormatRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#invalidslf4jmessageformat"> -Check for messages in slf4j loggers with non matching number of arguments and placeholders. +Check for messages in slf4j and log4j2 loggers with non matching number of arguments and placeholders. 5 diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidSlf4jMessageFormat.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidSlf4jMessageFormat.xml index 486a1351fc..0c5162f38a 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidSlf4jMessageFormat.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidSlf4jMessageFormat.xml @@ -375,6 +375,383 @@ public final class Main { public static void main(String[] args) { final Logger logger = LoggerFactory.getLogger(LoggerHelper.class); + logger.info(pattern, 1, 2); + } + } + ]]> + + + + 1 + 9 + + + + + 1 + 9 + + + + + 0 + + + + + 0 + + + + + Class cast exception with Method calls + 0 + + + + + Null pointer with VariableNameDeclaration / VariableDeclaratorId + 0 + + + + + Log4j2 NPE + 0 + + + + + Log4j2: doesn't ignore exception param + 0 + + + + + Log4j2: False positive with placeholder and exception + 0 + + + + + Log4j2: fails with NPE + 0 + + + + + Log4j2: false positive with pre-incremented variable + 0 + + + + + NPE in PMD 5.8.1 Log4j2 + 0 + + + + + Log4j2 false positive: too many arguments with string concatenation operator + 0 + + + + + NPE in static block (see #1512) + 0 + + + + + missing argument in static block + 1 + 8 + + + + + NPE in lambda call (see #1512) + 0 + list = someMethod(message -> logger.info(message)); + } + ]]> + + + + missing argument in lambda call + 1 + 9 + list = someMethod(message -> { + final String pattern = "log: {}"; + + logger.info(pattern, 1, 2); + }); + } + ]]> + + + + NPE in enums (see #1549) + 0 + + + + + missing argument in enum + 1 + 12 + - + + Add log4j2 Logger type + 0 + + + + Logger type log4j2: Two Loggers + 1 + + + \ No newline at end of file