22 April 2017
The PMD team is pleased to announce PMD 5.6.0.
The most significant changes are on analysis performance, support for Salesforce’s Visualforce language a whole new Apex Security Rule Set and the new Braces Rule Set for Apex.
We have added initial support for incremental analysis. The experimental feature allows PMD to cache analysis results between executions to speed up the analysis for all languages. New CLI flags and Ant options are available to configure it. Currently the feature is disabled by default, but this may change as it matures.
Multithread performance has been enhanced by reducing thread-contention on a bunch of areas. This is still an area of work, as the speedup of running multithreaded analysis is still relatively small (4 threads produce less than a 50% speedup). Future releases will keep improving on this area.
Once again, Symbol Table has been an area of great performance improvements. This time we were able to further improve it’s performance by roughly 10% on all supported languages. In Java in particular, several more improvements were possible, improving Symbol Table performance by a whooping 80%, that’s over 15X faster than PMD 5.5.1, when we first started working on it.
Java developers will also appreciate the revamp of CloneMethodMustImplementCloneable
,
making it over 500X faster, and PreserveStackTrace
which is now 7X faster.
PMD now supports incremental analysis. Analysis results can be cached and reused between runs. This allows PMD to skip files without violations that have remained unchanged. In future releases, we plan to extend this behavior to unchanged files with violations too.
The cache is automatically invalidated if:
auxclasspath
changed and any rules require type resolutionThis feature is incubating and is disabled by default. It’s only enabled if you specifically configure a cache file.
To configure the cache file from CLI, a new -cache <path/to/file>
flag has been added.
For Ant, a new cacheLocation
attribute has been added. For instance:
<target name="pmd">
<taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/>
<pmd cacheLocation="build/pmd/pmd.cache">
<ruleset>rulesets/java/design.xml</ruleset>
<ruleset>java-basic</ruleset>
<formatter type="xml" toFile="c:\pmd_report.xml"/>
<fileset dir="/usr/local/j2sdk1.4.1_01/src/">
<include name="java/lang/*.java"/>
</fileset>
</pmd>
</target>
Salesforce developers rejoice. To out growing Apex support we have added full Visualforce support.
Both CPD and PD are available. So far only a security ruleset is available (vf-security
).
The rule looks for Expression Language occurances printing unescaped values from the backend. These could lead to XSS attacks.
The rule looks for <apex:page>
tags performing an action on page load, definish such action
through Expression Language, as doing so is vulnerable to CSRF attacks.
A new ruleset focused on security has been added, consisting of a wide range of rules to detect most common security problems.
The rule makes sure you are using randomly generated IVs and keys for Crypto
calls.
Hard-wiring these values greatly compromises the security of encrypted data.
For instance, it would report violations on code such as:
public class without sharing Foo {
Blob hardCodedIV = Blob.valueOf('Hardcoded IV 123');
Blob hardCodedKey = Blob.valueOf('0000000000000000');
Blob data = Blob.valueOf('Data to be encrypted');
Blob encrypted = Crypto.encrypt('AES128', hardCodedKey, hardCodedIV, data);
}
The rule validates you are checking for access permissions before a SOQL/SOSL/DML operation. Since Apex runs in system mode not having proper permissions checks results in escalation of privilege and may produce runtime errors. This check forces you to handle such scenarios.
For example, the following code is considered valid:
public class Foo {
public Contact foo(String status, String ID) {
Contact c = [SELECT Status__c FROM Contact WHERE Id=:ID];
// Make sure we can update the database before even trying
if (!Schema.sObjectType.Contact.fields.Name.isUpdateable()) {
return null;
}
c.Status__c = status;
update c;
return c;
}
}
Check to avoid making DML operations in Apex class constructor/init method. This prevents modification of the database just by accessing a page.
For instance, the following code would be invalid:
public class Foo {
public init() {
insert data;
}
public Foo() {
insert data;
}
}
Checks against calling dangerous methods.
For the time being, it reports:
FinancialForce
’s Configuration.disableTriggerCRUDSecurity()
. Disabling CRUD security
opens the door to several attacks and requires manual validation, which is unreliable.System.debug
passing sensitive data as parameter, which could lead to exposure
of private data.Checks against accessing endpoints under plain http. You should always use https for security.
Checks against redirects to user-controlled locations. This prevents attackers from redirecting users to phishing sites.
For instance, the following code would be reported:
public class without sharing Foo {
String unsafeLocation = ApexPage.getCurrentPage().getParameters.get('url_param');
PageReference page() {
return new PageReference(unsafeLocation);
}
}
Detect classes declared without explicit sharing mode if DML methods are used. This forces the developer to take access restrictions into account before modifying objects.
Detects the usage of untrusted / unescaped variables in DML queries.
For instance, it would report on:
public class Foo {
public void test1(String t1) {
Database.query('SELECT Id FROM Account' + t1);
}
}
Detects hardcoded credentials used in requests to an endpoint.
You should refrain from hardcoding credentials:
Instead, you should use Named Credentials and a callout endpoint.
For more information, you can check this
Reports on calls to addError
with disabled escaping. The message passed to addError
will be displayed directly to the user in the UI, making it prime ground for XSS
attacks if unescaped.
Makes sure that all values obtained from URL parameters are properly escaped / sanitized to avoid XSS attacks.
The Braces Rule Set has been added and serves the same purpose as the Braces Rule Set from Java: It checks the use and placement of braces around if-statements, for-loops and so on.
Avoid using if statements without using braces to surround the code block. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
For instance, the following code shows the different. PMD would report on the not recommended approach:
if (foo) // not recommended
x++;
if (foo) { // preferred approach
x++;
}
Avoid using ‘while’ statements without using braces to surround the code block. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
For instance, the following code shows the different. PMD would report on the not recommended approach:
while (true) // not recommended
x++;
while (true) { // preferred approach
x++;
}
Avoid using if..else statements without using surrounding braces. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
For instance, the following code shows the different. PMD would report on the not recommended approach:
// this is not recommended
if (foo)
x = x+1;
else
x = x-1;
// preferred approach
if (foo) {
x = x+1;
} else {
x = x-1;
}
Avoid using ‘for’ statements without using surrounding braces. If the code formatting or indentation is lost then it becomes difficult to separate the code being controlled from the rest.
For instance, the following code shows the different. PMD would report on the not recommended approach:
for (int i = 0; i < 42; i++) // not recommended
foo();
for (int i = 0; i < 42; i++) { // preferred approach
foo();
}
When accessing a private field / method from another class, the Java compiler will generate an accessor method with package-private visibility. This adds overhead, and to the dex method count on Android. This situation can be avoided by changing the visibility of the field / method from private to package-private.
For instance, it would report violations on code such as:
public class OuterClass {
private int counter;
/* package */ int id;
public class InnerClass {
InnerClass() {
OuterClass.this.counter++; // wrong, accessor method will be generated
}
public int getOuterClassId() {
return OuterClass.this.id; // id is package-private, no accessor method needed
}
}
}
This new rule is part of the java-design
ruleset.
The Java rule UnnecessaryLocalBeforeReturn
(ruleset java-design) now has a new property statementOrderMatters
.
It is enabled by default to stay backwards compatible. But if this property is set to false
, this rule
no longer requires the variable declaration
and return statement to be on consecutive lines. Any variable that is used solely in a return statement will be
reported.
The Java rule UseLocaleWithCaseConversions
(ruleset java-design) has been modified, to detect calls
to toLowerCase
and to toUpperCase
also within method call chains. This leads to more detected cases
and potentially new false positives.
See also bugfix #1556.
The Java rule AvoidConstantsInterface
(ruleset java-design) has been removed. It is completely replaced by
the rule ConstantsInInterface
.
UnusedModifier
(ruleset java-unusedcode) has been moved to the ruleset java-unnecessary
and has been renamed to UnnecessaryModifier
.
Additionally, it has been expanded to consider more redundant modifiers:
abstract
.static
.public
.public
or static
.static
.JUnitTestsShouldIncludeAssert
(ruleset java-junit) now accepts usage of @Rule
ExpectedException
to set expectations on exceptions, and are considered as valid assertions.It is now possible to allow CPD suppression through comments in Java. You tell CPD to ignore
the following code with a comment containin CPD-OFF
and with CPD-ON
you tell CPD to resume
analysis. The old approach via @SuppressWarnings
annotation is still supported, but is considered
deprecated, since it is limited to locations where the SuppressWarnings
annotation is allowed.
See PR #250.
For example:
public Object someMethod(int x) throws Exception {
// some unignored code
// tell cpd to start ignoring code - CPD-OFF
// mission critical code, manually loop unroll
goDoSomethingAwesome(x + x / 2);
goDoSomethingAwesome(x + x / 2);
goDoSomethingAwesome(x + x / 2);
goDoSomethingAwesome(x + x / 2);
goDoSomethingAwesome(x + x / 2);
goDoSomethingAwesome(x + x / 2);
// resume CPD analysis - CPD-ON
// further code will *not* be ignored
}
CPD now supports the command line option --filelist
. With that, you can specify a file, which
contains the names and paths of the files, that should be analyzed. This is similar to PMD’s filelist option.
You need to use this, if you have a large project with many files, and you hit the command line length limit.
ResultSet
(false negative)net.sourceforge.pmd.RuleSetFactory
is now immutable and its behavior cannot be changed anymore.
It provides constructors to create new adjusted instances. This allows to avoid synchronization in RuleSetFactory.
See PR #131.net.sourceforge.pmd.RuleSet
is now immutable, too, and can only be created via RuleSetFactory
.
See PR #145.net.sourceforge.pmd.cli.XPathCLI
has been removed. It’s functionality is fully covered by the Designer.net.sourceforge.pmd.Report
now works with ThreadSafeReportListener
s. Both ReportListener
and
SynchronizedReportListener
are deprecated in favor of net.sourceforge.pmd.ThreadSafeReportListener
.
Therefore, the methods getSynchronizedListeners()
and addSynchronizedListeners(...)
have been
replaced by getListeners()
and addListeners(...)
. See PR #193.