PMD 6.0.0 released

15 December 2017


15-December-2017 - 6.0.0

The PMD team is pleased to announce PMD 6.0.0.

This is a major release.

Table Of Contents

New and noteworthy

New Rule Designer

Thanks to Clément Fournier, we now have a new rule designer GUI, which is based on JavaFX. It replaces the old designer and can be started via

  • bin/run.sh designer (on Unix-like platform such as Linux and Mac OS X)
  • bin\designer.bat (on Windows)

Note: At least Java8 is required for the designer. The old designer is still available as designerold but will be removed with the next major release.

Java 9 support

The Java grammar has been updated to support analyzing Java 9 projects:

  • private methods in interfaces are possible
  • The underscore “_” is considered an invalid identifier
  • Diamond operator for anonymous classes
  • The module declarations in module-info.java can be parsed
  • Concise try-with-resources statements are supported

Java 9 support is enabled by default. You can switch back to an older java version via the command line, e.g. -language java -version 1.8.

Revamped Apex CPD

We are now using the Apex Jorje Lexer to tokenize Apex code for CPD. This change means:

  • All comments are now ignored for CPD. This is consistent with how other languages such as Java and Groovy work.
  • Tokenization honors the language specification, which improves accuracy.

CPD will therefore have less false positives and false negatives.

Java Type Resolution

As part of Google Summer of Code 2017, Bendegúz Nagy worked on type resolution for Java. For this release he has extended support for method calls for both instance and static methods.

Method shadowing and overloading are supported, as are varargs. However, the selection of the target method upon the presence of generics and type inference is still work in progress. Expect it in forecoming releases.

As for fields, the basic support was in place for release 5.8.0, but has now been expanded to support static fields.

Metrics Framework

As part of Google Summer of Code 2017, Clément Fournier is worked on the new metrics framework for object-oriented metrics.

There are already a couple of metrics (e.g. ATFD, WMC, Cyclo, LoC) implemented. More metrics are planned. Based on those metrics, rules like “GodClass” detection could be implemented more easily. The following rules benefit from the metrics framework: NcssCount (java), NPathComplexity (java), CyclomaticComplexity (both java and apex).

The Metrics framework has been abstracted and is available in pmd-core for other languages. With this PMD release, the metrics framework is supported for both Java and Apex.

Error Reporting

A number of improvements on error reporting have taken place, meaning changes to some of the report formats.

Also of note, the xml report now provides a XML Schema definition, allowing easier parsing and validation.

Processing Errors

Processing errors can now provide not only the message previously included on some reports, but also a full stacktrace. This will allow better error reports when providing feedback to the PMD team and help in debugging issues.

The report formats providing full stacktrace of errors are:

  • html
  • summaryhtml
  • textcolor
  • vbhtml
  • xml
Configuration Errors

For a long time reports have been notified of configuration errors on rules, but they have remained hidden. On a push to make these more evident to users, and help them get the best results out of PMD, we have started to include them on the reports.

So far, only reports that include processing errors are showing configuration errors. In other words, the report formats providing configuration error reporting are:

  • csv
  • html
  • summaryhtml
  • text
  • textcolor
  • vbhtml
  • xml

As we move forward we will be able to detect and report more configuration errors (ie: incomplete auxclasspath) and include them to such reports.

Apex Rule Suppression

Apex violations can now be suppressed very similarly to how it’s done in Java, by making use of a @SuppressWarnings annotation.

Supported syntax includes:

@SupressWarnings('PMD') // to supress all Apex rules
@SupressWarnings('all') // to supress all Apex rules
@SupressWarnings('PMD.ARuleName') // to supress only the rule named ARuleName
@SupressWarnings('PMD.ARuleName, PMD.AnotherRuleName') // to supress only the rule named ARuleName or AnotherRuleName

Notice this last scenario is slightly different to the Java syntax. This is due to differences in the Apex grammar for annotations.

Rule Categories

All built-in rules have been sorted into one of eight categories:

  1. Best Practices: These are rules which enforce generally accepted best practices.
  2. Code Style: These rules enforce a specific coding style.
  3. Design: Rules that help you discover design issues.
  4. Documentation: These rules are related to code documentation.
  5. Error Prone: Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors.
  6. Multithreading: These are rules that flag issues when dealing with multiple threads of execution.
  7. Performance: Rules that flag suboptimal code.
  8. Security: Rules that flag potential security flaws.

These categories help you to find rules and figure out the relevance and impact for your project.

All rules have been moved accordingly, e.g. the rule “JumbledIncrementer”, which was previously defined in the ruleset “java-basic” has now been moved to the “Error Prone” category. The new rule reference to be used is <rule ref="category/java/errorprone.xml/JumbledIncrementer"/>.

The old rulesets like “java-basic” are still kept for backwards-compatibility but will be removed eventually. The rule reference documentation has been updated to reflect these changes.

New Rules

  • The new Java rule NcssCount (category design) replaces the three rules “NcssConstructorCount”, “NcssMethodCount”, and “NcssTypeCount”. The new rule uses the metrics framework to achieve the same. It has two properties, to define the report level for method and class sizes separately. Constructors and methods are considered the same.

  • The new Java rule DoNotExtendJavaLangThrowable (category errorprone) is a companion for the java-strictexception.xml/DoNotExtendJavaLangError, detecting direct extensions of java.lang.Throwable.

  • The new Java rule ForLoopCanBeForeach (category errorprone) helps to identify those for-loops that can be safely refactored into for-each-loops available since java 1.5.

  • The new Java rule AvoidFileStream (category performance) helps to identify code relying on FileInputStream / FileOutputStream which, by using a finalizer, produces extra / unnecessary overhead to garbage collection, and should be replaced with Files.newInputStream / Files.newOutputStream available since java 1.7.

  • The new Java rule DataClass (category design) detects simple data-holders without behaviour. This might indicate that the behaviour is scattered elsewhere and the data class exposes the internal data structure, which breaks encapsulation.

  • The new Apex rule AvoidDirectAccessTriggerMap (category errorprone) helps to identify direct array access to triggers, which can produce bugs by either accessing non-existing indexes, or leaving them out. You should use for-each-loops instead.

  • The new Apex rule AvoidHardcodingId (category errorprone) detects hardcoded strings that look like identifiers and flags them. Record IDs change between environments, meaning hardcoded ids are bound to fail under a different setup.

  • The new Apex rule CyclomaticComplexity (category design) detects overly complex classes and methods. The report threshold can be configured separately for classes and methods.

  • A whole bunch of new rules has been added to Apex. They all fit into the category errorprone. The 5 rules are migrated for Apex from the equivalent Java rules and include:
    • EmptyCatchBlock to detect catch blocks completely ignoring exceptions.
    • EmptyIfStmt for if blocks with no content, that can be safely removed.
    • EmptyTryOrFinallyBlock for empty try / finally blocks that can be safely removed.
    • EmptyWhileStmt for empty while loops that can be safely removed.
    • EmptyStatementBlock for empty code blocks that can be safely removed.
  • The new Apex rule AvoidSoslInLoops (category performance) is the companion of the old AvoidSoqlInLoops rule, flagging SOSL (Salesforce Object Search Language) queries when within loops, to avoid governor issues, and hitting the database too often.

Modified Rules

  • The Java rule UnnecessaryFinalModifier (category codestyle, former ruleset java-unnecessarycode) has been merged into the rule UnnecessaryModifier. As part of this, the rule has been revamped to detect more cases. It will now flag anonymous class’ methods marked as final (can’t be overridden, so it’s pointless), along with final methods overridden / defined within enum instances. It will also flag final modifiers on try-with-resources.

  • The Java rule UnnecessaryParentheses (category codestyle, former ruleset java-controversial) has been merged into UselessParentheses (category codestyle, former ruleset java-unnecessary). The rule covers all scenarios previously covered by either rule.

  • The Java rule UncommentedEmptyConstructor (category documentation, former ruleset java-design) will now ignore empty constructors annotated with javax.inject.Inject.

  • The Java rule AbstractClassWithoutAnyMethod (category bestpractices, former ruleset java-design) will now ignore classes annotated with com.google.auto.value.AutoValue.

  • The Java rule GodClass (category design', former ruleset java-design`) has been revamped to use the new metrics framework.

  • The Java rule LooseCoupling (category bestpractices, former ruleset java-coupling) has been replaced by the typeresolution-based implementation.

  • The Java rule CloneMethodMustImplementCloneable (category errorprone, former ruleset java-clone) has been replaced by the typeresolution-based implementation and is now able to detect cases if a class implements or extends a Cloneable class/interface.

  • The Java rule UnusedImports (category bestpractices, former ruleset java-imports) has been replaced by the typeresolution-based implementation and is now able to detect unused on-demand imports.

  • The Java rule SignatureDeclareThrowsException (category design, former ruleset ‘java-strictexception’) has been replaced by the typeresolution-based implementation. It has a new property IgnoreJUnitCompletely, which allows all methods in a JUnit testcase to throw exceptions.

  • The Java rule NPathComplexity (category design, former ruleset java-codesize) has been revamped to use the new metrics framework. Its report threshold can be configured via the property reportLevel, which replaces the now deprecated property minimum.

  • The Java rule CyclomaticComplexity (category design, former ruleset java-codesize) has been revamped to use the new metrics framework. Its report threshold can be configured via the properties classReportLevel and methodReportLevel separately. The old property reportLevel, which configured the level for both total class and method complexity, is deprecated.

  • The Java rule CommentRequired (category documentation, former ruleset java-comments) has been revamped to include 2 new properties:
    • accessorCommentRequirement to specify documentation requirements for getters and setters (default to ignored)
    • methodWithOverrideCommentRequirement to specify documentation requirements for methods annotated with @Override (default to ignored)
  • The Java rule EmptyCatchBlock (category errorprone, former ruleset java-empty) has been changed to ignore exceptions named ignore or expected by default. You can still override this behaviour by setting the allowExceptionNameRegex property.

  • The Java rule OptimizableToArrayCall (category performance, former ruleset design) has been modified to fit for the current JVM implementations: It basically detects now the opposite and suggests to use Collection.toArray(new E[0]) with a zero-sized array. See Arrays of Wisdom of the Ancients.

Deprecated Rules

  • The Java rules NcssConstructorCount, NcssMethodCount, and NcssTypeCount (ruleset java-codesize) have been deprecated. They will be replaced by the new rule NcssCount in the category design.

  • The Java rule LooseCoupling in ruleset java-typeresolution is deprecated. Use the rule with the same name from category bestpractices instead.

  • The Java rule CloneMethodMustImplementCloneable in ruleset java-typeresolution is deprecated. Use the rule with the same name from category errorprone instead.

  • The Java rule UnusedImports in ruleset java-typeresolution is deprecated. Use the rule with the same name from category bestpractices instead.

  • The Java rule SignatureDeclareThrowsException in ruleset java-typeresolution is deprecated. Use the rule with the same name from category design instead.

  • The Java rule EmptyStaticInitializer in ruleset java-empty is deprecated. Use the rule EmptyInitializer from the category errorprone, which covers both static and non-static empty initializers.`

  • The Java rules GuardDebugLogging (ruleset java-logging-jakarta-commons) and GuardLogStatementJavaUtil (ruleset java-logging-java) have been deprecated. Use the rule GuardLogStatement from the category bestpractices, which covers all cases regardless of the logging framework.

Removed Rules

  • The deprecated Java rule UseSingleton has been removed from the ruleset java-design. The rule has been renamed long time ago to UseUtilityClass (category design).

Java Symbol Table

A bug in symbol table prevented the symbol table analysis to properly match primitive arrays types. The issue affected the java-unsedcode/UnusedPrivateMethod rule, but other rules may now produce improved results as consequence of this fix.

Apex Parser Update

The Apex parser version was bumped, from 1.0-sfdc-187 to 210-SNAPSHOT. This update let us take full advantage of the latest improvements from Salesforce, but introduces some breaking changes:

  • BlockStatements are now created for all control structures, even if no brace is used. We have therefore added a hasCurlyBrace method to differentiate between both scenarios.
  • New AST node types are available. In particular CastExpression, ConstructorPreamble, IllegalStoreExpression, MethodBlockStatement, Modifier, MultiStatement, NestedExpression, NestedStoreExpression, NewKeyValueObjectExpression and StatementExecuted
  • Some nodes have been removed. Such is the case of TestNode, DottedExpression and NewNameValueObjectExpression (replaced by NewKeyValueObjectExpression)

All existing rules have been updated to reflect these changes. If you have custom rules, be sure to update them.

For more info about the included Apex parser, see the new pmd module “pmd-apex-jorje”, which packages and provides the parser as a binary.

Incremental Analysis

The incremental analysis feature first introduced in PMD 5.6.0 has been enhanced. A few minor issues have been fixed, and several improvements have been performed to make it more accurate.

The cache will now detect changes to the JARs referenced in the auxclasspath instead of simply looking at their paths and order. This means that if you are referencing a JAR you are overwriting in some way, the incremental analysis can now detect it and invalidate it’s cache to avoid false reports.

Similarly, any changes to the execution classpath of PMD will invalidate the cache. This means that if you have custom rules packaged in a jar, any changes to it will invalidate the cache automatically.

We have also improved logging on the analysis code, allowing better insight into how the cache is performing, under debug / verbose builds you can even see individual hits / misses to the cache (and the reason for any miss!)

Finally, as this feature keeps maturing, we are gently pushing this forward. If not using incremental analysis, a warning will now be produced suggesting users to adopt it for better performance.

Rule and Report Properties

The implementation around the properties support for rule properties and report properties has been revamped to be fully typesafe. Along with that change, the support classes have been moved into an own package net.sourceforge.pmd.properties. While there is no change necessary in the ruleset XML files, when using/setting values for rules, there are adjustments necessary when declaring properties in Java-implemented rules.

Rule properties can be declared both for Java based rules and XPath rules. This is now very well documented in Working with properties.

With PMD 6.0.0, multivalued properties are now also possible with XPath rules.

Fixed Issues

  • all
    • #394: [core] PMD exclude rules are failing with IllegalArgumentException with non-default minimumPriority
    • #532: [core] security concerns on URL-based rulesets
    • #538: [core] Provide an XML Schema for XML reports
    • #600: [core] Nullpointer while creating cache File
    • #604: [core] Incremental analysis should detect changes to jars in classpath
    • #608: [core] Add DEBUG log when applying incremental analysis
    • #618: [core] Incremental Analysis doesn’t close file correctly on Windows upon a cache hit
    • #643: [core] PMD Properties (dev-properties) breaks markup on CodeClimateRenderer
    • #680: [core] Isolate classloaders for runtime and auxclasspath
    • #762: [core] Remove method and file property from available property descriptors for XPath rules
    • #763: [core] Turn property descriptor util into an enum and enrich its interface
  • apex
    • #265: [apex] Make Rule suppression work
    • #488: [apex] Use Apex lexer for CPD
    • #489: [apex] Update Apex compiler
    • #500: [apex] Running through CLI shows jorje optimization messages
    • #605: [apex] java.lang.NoClassDefFoundError in the latest build
    • #637: [apex] Avoid SOSL in loops
    • #760: [apex] EmptyStatementBlock complains about missing rather than empty block
    • #766: [apex] Replace old Jorje parser with new one
    • #768: [apex] java.lang.NullPointerException from PMD
  • cpp
    • #448: [cpp] Write custom CharStream to handle continuation characters
  • java
    • #1454: [java] OptimizableToArrayCall is outdated and invalid in current JVMs
    • #1513: [java] Remove deprecated rule UseSingleton
    • #328: [java] java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/servlet/jsp/PageContext
    • #487: [java] Fix typeresolution for anonymous extending object
    • #496: [java] processing error on generics inherited from enclosing class
    • #510: [java] Typeresolution fails on a simple primary when the source is loaded from a class literal
    • #527: [java] Lombok getter annotation on enum is not recognized correctly
    • #534: [java] NPE in MethodTypeResolution for static methods
    • #603: [core] incremental analysis should invalidate upon Java rule plugin changes
    • #650: [java] ProcesingError analyzing code under 5.8.1
    • #732: [java] LinkageError with aux classpath
  • java-basic
    • #565: [java] False negative on DontCallThreadRun when extending Thread
  • java-comments
    • #396: [java] CommentRequired: add properties to ignore @Override method and getters / setters
    • #536: [java] CommentDefaultAccessModifierRule ignores constructors
  • java-controversial
    • #388: [java] controversial.AvoidLiteralsInIfCondition 0.0 false positive
    • #408: [java] DFA not analyzing asserts
    • #537: [java] UnnecessaryParentheses fails to detect obvious scenario
  • java-design
    • #357: [java] UncommentedEmptyConstructor consider annotations on Constructor
    • #438: [java] Relax AbstractClassWithoutAnyMethod when class is annotated by @AutoValue
    • #590: [java] False positive on MissingStaticMethodInNonInstantiatableClass
  • java-logging * #457: [java] Merge all log guarding rules * #721: [java] NPE in PMD 5.8.1 InvalidSlf4jMessageFormat
  • java-sunsecure
    • #468: [java] ArrayIsStoredDirectly false positive
  • java-unusedcode
    • #521: [java] UnusedPrivateMethod returns false positives with primitive data type in map argument
  • java-unnecessarycode
    • #412: [java] java-unnecessarycode/UnnecessaryFinalModifier missing cases
    • #676: [java] java-unnecessarycode/UnnecessaryFinalModifier on try-with-resources

API Changes

  • The class net.sourceforge.pmd.lang.dfa.NodeType has been converted to an enum. All node types are enum members now instead of int constants. The names for node types are retained.

  • The Properties API (rule and report properties) has been revamped to be fully typesafe. This is everything around net.sourceforge.pmd.properties.PropertyDescriptor.

    Note: All classes related to properties have been moved into the package net.sourceforge.pmd.properties.

  • The rule classes net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestClassShouldHaveAsserts and net.sourceforge.pmd.lang.apex.rule.apexunit.ApexUnitTestShouldNotUseSeeAllDataTrue have been renamed to ApexUnitTestClassShouldHaveAssertsRule and ApexUnitTestShouldNotUseSeeAllDataTrueRule, respectively. This is to comply with the naming convention, that each rule class should be suffixed with “Rule”.

    This change has no impact on custom rulesets, since the rule names themselves didn’t change.

  • The never implemented method PMD.processFiles(PMDConfiguration, RuleSetFactory, Collection<File>, RuleContext, ProgressMonitor) along with the interface ProgressMonitor has been removed.

  • The method PMD.setupReport(RuleSets, RuleContext, String) is gone. It was used to report dysfunctional rules. But PMD does this now automatically before processing the files, so there is no need for this method anymore.

  • All APIs deprecated in older versions are now removed. This includes:
    • Renderer.getPropertyDefinitions
    • AbstractRenderer.defineProperty(String, String)
    • AbstractRenderer.propertyDefinitions
    • ReportListener
    • Report.addListener(ReportListener)
    • SynchronizedReportListener
    • CPDConfiguration.CPDConfiguration(int, Language, String)
    • CPDConfiguration.getRendererFromString(String)
    • StreamUtil
    • StringUtil.appendXmlEscaped(StringBuilder, String)
    • StringUtil.htmlEncode(String)
  • Several methods in net.sourceforge.pmd.util.CollectionUtil have been deprecated and will be removed in PMD 7.0.0. In particular:
    • CollectionUtil.addWithoutDuplicates(T[], T)
    • CollectionUtil.addWithoutDuplicates(T[], T[])
    • CollectionUtil.areSemanticEquals(T[], T[])
    • CollectionUtil.areEqual(Object, Object)
    • CollectionUtil.arraysAreEqual(Object, Object)
    • CollectionUtil.valuesAreTransitivelyEqual(Object[], Object[])
  • Several methods in net.sourceforge.pmd.util.StringUtil have been deprecated and will be removed in PMD 7.0.0. In particular:
    • StringUtil.startsWithAny(String, String[])
    • StringUtil.isNotEmpty(String)
    • StringUtil.isEmpty(String)
    • StringUtil.isMissing(String)
    • StringUtil.areSemanticEquals(String, String)
    • StringUtil.replaceString(String, String, String)
    • StringUtil.replaceString(String, char, String)
    • StringUtil.substringsOf(String, char)
    • StringUtil.substringsOf(String, String)
    • StringUtil.asStringOn(StringBuffer, Iterator, String)
    • StringUtil.asStringOn(StringBuilder, Object[], String)
    • StringUtil.lpad(String, int)
  • The class net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition is now abstract, and has been enhanced to provide several new methods.

  • The constructor of net.sourceforge.pmd.RuleSetFactory, which took a ClassLoader is deprecated. Please use the alternative constructor with the net.sourceforge.pmd.util.ResourceLoader instead.

  • The following GUI related classes have been deprecated and will be removed in PMD 7.0.0. The tool “bgastviewer”, that could be started via the script bgastviewer.bat or run.sh bgastviewer is deprecated, too, and will be removed in PMD 7.0.0. Both the “old designer” and “bgastviewer” are replaced by the New Rule Designer.
    • net.sourceforge.pmd.util.designer.CodeEditorTextPane
    • net.sourceforge.pmd.util.designer.CreateXMLRulePanel
    • net.sourceforge.pmd.util.designer.Designer
    • net.sourceforge.pmd.util.designer.DFAPanel
    • net.sourceforge.pmd.util.designer.LineGetter
    • net.sourceforge.pmd.util.viewer.Viewer
    • net.sourceforge.pmd.util.viewer.gui.ActionCommands
    • net.sourceforge.pmd.util.viewer.gui.ASTPanel
    • net.sourceforge.pmd.util.viewer.gui.EvaluationResultsPanel
    • net.sourceforge.pmd.util.viewer.gui.MainFrame
    • net.sourceforge.pmd.util.viewer.gui.ParseExceptionHandler
    • net.sourceforge.pmd.util.viewer.gui.SourceCodePanel
    • net.sourceforge.pmd.util.viewer.gui.XPathPanel
    • net.sourceforge.pmd.util.viewer.gui.menu.ASTNodePopupMenu
    • net.sourceforge.pmd.util.viewer.gui.menu.AttributesSubMenu
    • net.sourceforge.pmd.util.viewer.gui.menu.SimpleNodeSubMenu
    • net.sourceforge.pmd.util.viewer.gui.menu.XPathFragmentAddingItem
    • net.sourceforge.pmd.util.viewer.model.ASTModel
    • net.sourceforge.pmd.util.viewer.model.AttributeToolkit
    • net.sourceforge.pmd.util.viewer.model.SimpleNodeTreeNodeAdapter
    • net.sourceforge.pmd.util.viewer.model.ViewerModel
    • net.sourceforge.pmd.util.viewer.model.ViewerModelEvent
    • net.sourceforge.pmd.util.viewer.model.ViewerModelListener
    • net.sourceforge.pmd.util.viewer.util.NLS
  • The following methods in net.sourceforge.pmd.Rule have been deprecated and will be removed in PMD 7.0.0. All methods are replaced by their bean-like counterparts
    • void setUsesDFA(). Use void setDfa(boolean) instead.
    • boolean usesDFA(). Use boolean isDfa() instead.
    • void setUsesTypeResolution(). Use void setTypeResolution(boolean) instead.
    • boolean usesTypeResolution(). Use boolean isTypeResolution() instead.
    • void setUsesMultifile(). Use void setMultifile(boolean) instead.
    • boolean usesMultifile(). Use boolean isMultifile() instead.
    • boolean usesRuleChain(). Use boolean isRuleChain() instead.

External Contributions