diff --git a/.ci/files/all-java.xml b/.ci/files/all-java.xml index a6ab7f8913..5504b69ffb 100644 --- a/.ci/files/all-java.xml +++ b/.ci/files/all-java.xml @@ -291,7 +291,7 @@ - + diff --git a/pmd-java/src/main/resources/category/java/performance.xml b/pmd-java/src/main/resources/category/java/performance.xml index ddc0cd1590..d233ea14e1 100644 --- a/pmd-java/src/main/resources/category/java/performance.xml +++ b/pmd-java/src/main/resources/category/java/performance.xml @@ -116,12 +116,13 @@ public class Test { -Problem: A Calendar is a heavyweight object and expensive to create. +Problem: `java.util.Calendar` is a heavyweight object and expensive to create. It should only be used, if +calendar calculations are needed. Solution: Use `new Date()`, Java 8+ `java.time.LocalDateTime.now()` or `ZonedDateTime.now()`. @@ -129,26 +130,32 @@ Solution: Use `new Date()`, Java 8+ `java.time.LocalDateTime.now()` or `ZonedDat 2 and ../PrimarySuffix[last()-1][@Image = 'getTime' or @Image='getTimeInMillis']] +//MethodCall[pmd-java:matchesSig("java.util.Calendar#getTime()") or pmd-java:matchesSig("java.util.Calendar#getTimeInMillis()")] + [*[1][local-name() = ('MethodCall', 'ConstructorCall')] + [pmd-java:matchesSig("java.util.Calendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#new()")] + ] | -//MethodDeclaration[not(MethodDeclarator/FormalParameters//ClassOrInterfaceType[pmd-java:typeIs('java.util.Calendar')])] - /Block/BlockStatement//PrimaryExpression - /PrimaryPrefix/Name - [pmd-java:typeIs('java.util.Calendar')] - [every $var in @Image satisfies ( - (ends-with($var, '.getTime') or ends-with($var, '.getTimeInMillis')) - and - (: ignore if .set* or .add* or .clear is called on the variable :) - not(ancestor::Block/BlockStatement//Name[ - starts-with(@Image, concat((tokenize($var, '\.'), $var)[1], '.set')) - or - starts-with(@Image, concat((tokenize($var, '\.'), $var)[1], '.add')) - or - starts-with(@Image, concat((tokenize($var, '\.'), $var)[1], '.clear')) - ]) - )] +//MethodCall[pmd-java:matchesSig("java.util.Calendar#getTime()") or pmd-java:matchesSig("java.util.Calendar#getTimeInMillis()")] + [*[1][local-name() = 'VariableAccess']] + (: ignore if .set* or .add or .clear or .roll is called on the variable :) + [not(VariableAccess/@Name = ancestor::Block//MethodCall[starts-with(@MethodName, "set") or @MethodName = ("add", "clear", "roll")]/VariableAccess/@Name)] + (: variable must be initialized with getInstance :) + [VariableAccess/@Name = ancestor::Block//LocalVariableDeclaration/VariableDeclarator[ + (MethodCall | ConstructorCall) + [pmd-java:matchesSig("java.util.Calendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#new()")] + ]/VariableDeclaratorId/@Name] | -//ClassOrInterfaceType[pmd-java:typeIs('org.joda.time.DateTime') or pmd-java:typeIs('org.joda.time.LocalDateTime')][../Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, 'Calendar.getInstance')]] +//ConstructorCall[pmd-java:typeIs("org.joda.time.DateTime") or pmd-java:typeIs("org.joda.time.LocalDateTime")] + [ArgumentList[(MethodCall | ConstructorCall) + [pmd-java:matchesSig("java.util.Calendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#getInstance()") + or pmd-java:matchesSig("java.util.GregorianCalendar#new()")]] + ] + ]]> diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidCalendarDateCreationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidCalendarDateCreationTest.java index fb5991354b..a3c8909f50 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidCalendarDateCreationTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidCalendarDateCreationTest.java @@ -6,6 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.performance; import net.sourceforge.pmd.testframework.PmdRuleTst; -@org.junit.Ignore("Rule has not been updated yet") public class AvoidCalendarDateCreationTest extends PmdRuleTst { + // no additional unit tests } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidCalendarDateCreation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidCalendarDateCreation.xml index ce34feba1f..374b93b004 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidCalendarDateCreation.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidCalendarDateCreation.xml @@ -135,6 +135,7 @@ public class Foo { + + + + False positive with Calendar not created here + 0 + + + + + False positive when this is a Calendar + 0 + + + + + False positive with calendar builder + 0 + + + + + False positive with specific date + 0 + + + + + False positive with calendar not created by getInstance + 0 + + + + + New GregorianCalendar default constructor + 2 + 7,8 +