From 43ecf1e110c531652f4e26666c050d4883aac2de Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 17 Mar 2013 11:03:02 +0100 Subject: [PATCH] pmd: fix #999 Law of Demeter: False positives and negatives --- pmd/etc/changelog.txt | 1 + .../java/rule/coupling/LawOfDemeterRule.java | 29 +++++++++--- .../java/rule/coupling/xml/LawOfDemeter.xml | 45 +++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/pmd/etc/changelog.txt b/pmd/etc/changelog.txt index b9b929ab96..ea25e1e557 100644 --- a/pmd/etc/changelog.txt +++ b/pmd/etc/changelog.txt @@ -8,6 +8,7 @@ Fixed bug 984: Cyclomatic complexity should treat constructors like methods Fixed bug 985: Suppressed methods shouldn't affect avg CyclomaticComplexity Fixed bug 992: Class java.beans.Statement triggered in CloseResource rule Fixed bug 997: Rule NonThreadSafeSingleton gives analysis problem +Fixed bug 999: Law of Demeter: False positives and negatives Fixed bug 1002: False +: FinalFieldCouldBeStatic on inner class Fixed bug 1005: False + for ConstructorCallsOverridableMethod - overloaded methods Fixed bug 1032: ImmutableField Rule: Private field in inner class gives false positive diff --git a/pmd/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LawOfDemeterRule.java b/pmd/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LawOfDemeterRule.java index 72d21eeee8..09244e4c9a 100644 --- a/pmd/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LawOfDemeterRule.java +++ b/pmd/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LawOfDemeterRule.java @@ -14,6 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; @@ -123,13 +124,16 @@ public class LawOfDemeterRule extends AbstractJavaRule { public static List createMethodCalls(ASTPrimaryExpression expression) { List result = new ArrayList(); - if (isNotAConstructorCall(expression) && hasSuffixesWithArguments(expression)) { + if (isNotAConstructorCall(expression) && isNotLiteral(expression) && hasSuffixesWithArguments(expression)) { ASTPrimaryPrefix prefixNode = expression.getFirstDescendantOfType(ASTPrimaryPrefix.class); - result.add(new MethodCall(expression, prefixNode)); + MethodCall firstMethodCallInChain = new MethodCall(expression, prefixNode); + result.add(firstMethodCallInChain); - List suffixes = findSuffixesWithoutArguments(expression); - for (ASTPrimarySuffix suffix : suffixes) { - result.add(new MethodCall(expression, suffix)); + if (firstMethodCallInChain.isNotBuilder()) { + List suffixes = findSuffixesWithoutArguments(expression); + for (ASTPrimarySuffix suffix : suffixes) { + result.add(new MethodCall(expression, suffix)); + } } } @@ -140,6 +144,21 @@ public class LawOfDemeterRule extends AbstractJavaRule { return !expression.hasDescendantOfType(ASTAllocationExpression.class); } + private static boolean isNotLiteral(ASTPrimaryExpression expression) { + ASTPrimaryPrefix prefix = expression.getFirstDescendantOfType(ASTPrimaryPrefix.class); + if (prefix != null) { + return !prefix.hasDescendantOfType(ASTLiteral.class); + } + return true; + } + + private boolean isNotBuilder() { + return baseType != StringBuffer.class + && baseType != StringBuilder.class + && !"StringBuilder".equals(baseTypeName) + && !"StringBuffer".equals(baseTypeName); + } + private static List findSuffixesWithoutArguments(ASTPrimaryExpression expr) { List result = new ArrayList(); if (hasRealPrefix(expr)) { diff --git a/pmd/src/test/resources/net/sourceforge/pmd/lang/java/rule/coupling/xml/LawOfDemeter.xml b/pmd/src/test/resources/net/sourceforge/pmd/lang/java/rule/coupling/xml/LawOfDemeter.xml index 34a6256f98..93ac6ef0c4 100644 --- a/pmd/src/test/resources/net/sourceforge/pmd/lang/java/rule/coupling/xml/LawOfDemeter.xml +++ b/pmd/src/test/resources/net/sourceforge/pmd/lang/java/rule/coupling/xml/LawOfDemeter.xml @@ -181,4 +181,49 @@ public class Foo { } + + + #999 false positives + 0 + + + + #999 false negatives + 1 + +