diff --git a/docs/_config.yml b/docs/_config.yml
index e6fee403f1..c308c5c33d 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,9 +1,9 @@
repository: pmd/pmd
pmd:
- version: 6.11.0
- previous_version: 6.10.0
- date: ??-January-2019
+ version: 6.12.0
+ previous_version: 6.11.0
+ date: ??-February-2019
release_type: minor
output: web
diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb
index 7bdf60560c..940c2826e2 100644
--- a/docs/_plugins/javadoc_tag.rb
+++ b/docs/_plugins/javadoc_tag.rb
@@ -97,7 +97,7 @@ class JavadocTag < Liquid::Tag
QNAME_NO_NAMESPACE_REGEX = /((?:\w+\.)*\w+)/
ARG_REGEX = Regexp.new(Regexp.union(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX, QNAME_NO_NAMESPACE_REGEX).source + '(\[\])*')
- ARGUMENTS_REGEX = Regexp.new('\(\)|\((' + ARG_REGEX.source + "(?:," + ARG_REGEX.source + ")*" + ')\)')
+ ARGUMENTS_REGEX = Regexp.new('\(\)|\((' + ARG_REGEX.source + "(?:,(?:" + ARG_REGEX.source + "))*" + ')\)')
def initialize(tag_name, doc_ref, tokens)
diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md
index 616dcae65c..456e9fb1cb 100644
--- a/docs/pages/next_major_development.md
+++ b/docs/pages/next_major_development.md
@@ -73,6 +73,16 @@ the breaking API changes will be performed in 7.0.0.
an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0,
we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %}
+#### 6.11.0
+
+* {% jdoc core::lang.rule.stat.StatisticalRule %} and the related helper classes and base rule classes
+are deprecated for removal in 7.0.0. This includes all of {% jdoc_package core::stat %} and {% jdoc_package core::lang.rule.stat %},
+and also {% jdoc java::lang.java.rule.AbstractStatisticalJavaRule %}, {% jdoc apex::lang.apex.rule.AbstractStatisticalApexRule %} and the like.
+The methods {% jdoc !c!core::Report#addMetric(core::stat.Metric) %} and {% jdoc core::ThreadSafeReportListener#metricAdded(core::stat.Metric) %}
+will also be removed.
+* {% jdoc core::properties.PropertySource#setProperty(core::properties.MultiValuePropertyDescriptor, Object[]) %} is deprecated,
+because {% jdoc core::properties.MultiValuePropertyDescriptor %} is deprecated as well
+
#### 6.10.0
##### Properties framework
diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index 43a401f025..b8f8783555 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -14,98 +14,11 @@ This is a {{ site.pmd.release_type }} release.
### New and noteworthy
-### Updatex Apex Support
-
-* The Apex language support has been bumped to version 45 (Spring '19). All new language features are now properly
- parsed and processed.
-
-#### New Rules
-
-* The new Java rule {% rule "java/multithreading/UnsynchronizedStaticFormatter" %} (`java-multithreading`) detects
- unsynchronized usages of static `java.text.Format` instances. This rule is a more generic replacement of the
- rule {% rule "java/multithreading/UnsynchronizedStaticDateFormatter" %} which focused just on `DateFormat`.
-
-* The new Java rule {% rule "java/bestpractices/ForLoopVariableCount" %} (`java-bestpractices`) checks for
- the number of control variables in a for-loop. Having a lot of control variables makes it harder to understand
- what the loop does. The maximum allowed number of variables is by default 1 and can be configured by a
- property.
-
-* The new Java rule {% rule "java/bestpractices/AvoidReassigningLoopVariables" %} (`java-bestpractices`) searches
- for loop variables that are reassigned. Changing the loop variables additionally to the loop itself can lead to
- hard-to-find bugs.
-
-* The new Java rule {% rule "java/codestyle/UseDiamondOperator" %} (`java-codestyle`) looks for constructor
- calls with explicit type parameters. Since Java 1.7, these type parameters are not necessary anymore, as they
- can be inferred now.
-
-#### Modified Rules
-
-* The Java rule {% rule "java/codestyle/LocalVariableCouldBeFinal" %} (`java-codestyle`) has a new
- property `ignoreForEachDecl`, which is by default disabled. The new property allows for ignoring
- non-final loop variables in a for-each statement.
-
-#### Deprecated Rules
-
-* The Java rule {% rule "java/multithreading/UnsynchronizedStaticDateFormatter" %} has been deprecated and
- will be removed with PMD 7.0.0. The rule is replaced by the more general
- {% rule "java/multithreading/UnsynchronizedStaticFormatter" %}.
-
### Fixed Issues
-* all
- * [#1196](https://github.com/pmd/pmd/issues/1196): \[core] CPD results not consistent between runs
-* apex
- * [#1542](https://github.com/pmd/pmd/pull/1542): \[apex] Include the documentation category
- * [#1546](https://github.com/pmd/pmd/issues/1546): \[apex] PMD parsing exception for Apex classes using 'inherited sharing' keyword
-* java
- * [#1556](https://github.com/pmd/pmd/issues/1556): \[java] Default methods should not be considered abstract
- * [#1578](https://github.com/pmd/pmd/issues/1578): \[java] Private field is detected as public inside nested classes in interfaces
-* java-bestpractices
- * [#658](https://github.com/pmd/pmd/issues/658): \[java] OneDeclarationPerLine: False positive for loops
- * [#1518](https://github.com/pmd/pmd/issues/1518): \[java] New rule: AvoidReassigningLoopVariable
- * [#1519](https://github.com/pmd/pmd/issues/1519): \[java] New rule: ForLoopVariableCount
-* java-codestyle
- * [#1513](https://github.com/pmd/pmd/issues/1513): \[java] LocalVariableCouldBeFinal: allow excluding the variable in a for-each loop
- * [#1517](https://github.com/pmd/pmd/issues/1517): \[java] New Rule: UseDiamondOperator
-* java-errorprone
- * [#1035](https://github.com/pmd/pmd/issues/1035): \[java] ReturnFromFinallyBlock: False positive on lambda expression in finally block
- * [#1549](https://github.com/pmd/pmd/issues/1549): \[java] NPE in PMD 6.8.0 InvalidSlf4jMessageFormat
-* java-multithreading
- * [#1533](https://github.com/pmd/pmd/issues/1533): \[java] New rule: UnsynchronizedStaticFormatter
-* plsql
- * [#1507](https://github.com/pmd/pmd/issues/1507): \[plsql] Parse Exception when using '||' operator in where clause
- * [#1508](https://github.com/pmd/pmd/issues/1508): \[plsql] Parse Exception when using SELECT COUNT(\*)
- * [#1509](https://github.com/pmd/pmd/issues/1509): \[plsql] Parse Exception with OUTER/INNER Joins
- * [#1511](https://github.com/pmd/pmd/issues/1511): \[plsql] Parse Exception with IS NOT NULL
- * [#1583](https://github.com/pmd/pmd/issues/1583): \[plsql] Update Set Clause should allow multiple columns
- * [#1586](https://github.com/pmd/pmd/issues/1586): \[plsql] Parse Exception when functions are used with LIKE
-
### API Changes
-#### Deprecated API
-
-* {% jdoc core::lang.rule.stat.StatisticalRule %} and the related helper classes and base rule classes
-are deprecated for removal in 7.0.0. This includes all of {% jdoc_package core::stat %} and {% jdoc_package core::lang.rule.stat %},
-and also {% jdoc java::lang.java.rule.AbstractStatisticalJavaRule %}, {% jdoc apex::lang.apex.rule.AbstractStatisticalApexRule %} and the like.
-The methods {% jdoc !c!core::Report#addMetric(core::stat.Metric) %} and {% jdoc core::ThreadSafeReportListener#metricAdded(core::stat.Metric) %}
-will also be removed.
-
-
### External Contributions
-* [#1503](https://github.com/pmd/pmd/pull/1503): \[java] Fix for ReturnFromFinallyBlock false-positives - [RishabhDeep Singh](https://github.com/rishabhdeepsingh)
-* [#1514](https://github.com/pmd/pmd/pull/1514): \[java] LocalVariableCouldBeFinal: allow excluding the variable in a for-each loop - [Kris Scheibe](https://github.com/kris-scheibe)
-* [#1516](https://github.com/pmd/pmd/pull/1516): \[java] OneDeclarationPerLine: Don't report multiple variables in a for statement. - [Kris Scheibe](https://github.com/kris-scheibe)
-* [#1520](https://github.com/pmd/pmd/pull/1520): \[java] New rule: ForLoopVariableCount: check the number of control variables in a for loop - [Kris Scheibe](https://github.com/kris-scheibe)
-* [#1521](https://github.com/pmd/pmd/pull/1521): \[java] Upgrade to ASM7 for JDK 11 support - [Mark Pritchard](https://github.com/markpritchard)
-* [#1530](https://github.com/pmd/pmd/pull/1530): \[java] New rule: AvoidReassigningLoopVariables - [Kris Scheibe](https://github.com/kris-scheibe)
-* [#1534](https://github.com/pmd/pmd/pull/1534): \[java] This is the change regarding the usediamondoperator #1517 - [hemanshu070](https://github.com/hemanshu070)
-* [#1545](https://github.com/pmd/pmd/pull/1545): \[doc] fixing dead links + tool to check for dead links automatically - [Kris Scheibe](https://github.com/kris-scheibe)
-* [#1551](https://github.com/pmd/pmd/pull/1551): \[java] InvalidSlf4jMessageFormatRule should not throw NPE for enums - [Robbie Martinus](https://github.com/rmartinus)
-* [#1552](https://github.com/pmd/pmd/pull/1552): \[core] Upgrading Google Gson from 2.5 to 2.8.5 - [Thunderforge](https://github.com/Thunderforge)
-* [#1553](https://github.com/pmd/pmd/pull/1553): \[core] Upgrading System Rules dependency from 1.8.0 to 1.19.0 - [Thunderforge](https://github.com/Thunderforge)
-* [#1554](https://github.com/pmd/pmd/pull/1554): \[plsql] updates should allow for multiple statements - [tashiscool](https://github.com/tashiscool)
-* [#1584](https://github.com/pmd/pmd/pull/1584): \[core] Fixes 1196: inconsistencies of clones returned by different CPD executions for the same files - [Bruno Ferreira](https://github.com/bmbferreira)
-
{% endtocmaker %}
diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md
index 15b232db0f..50e5f8e12e 100644
--- a/docs/pages/release_notes_old.md
+++ b/docs/pages/release_notes_old.md
@@ -5,6 +5,131 @@ permalink: pmd_release_notes_old.html
Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases
+## 27-January-2019 - 6.11.0
+
+The PMD team is pleased to announce PMD 6.11.0.
+
+This is a minor release.
+
+### Table Of Contents
+
+* [New and noteworthy](#new-and-noteworthy)
+ * [Updated Apex Support](#updated-apex-support)
+ * [PL/SQL Grammar improvements](#pl/sql-grammar-improvements)
+ * [New Rules](#new-rules)
+ * [Modified Rules](#modified-rules)
+ * [Deprecated Rules](#deprecated-rules)
+* [Fixed Issues](#fixed-issues)
+* [API Changes](#api-changes)
+* [External Contributions](#external-contributions)
+
+### New and noteworthy
+
+#### Updated Apex Support
+
+* The Apex language support has been bumped to version 45 (Spring '19). All new language features are now properly
+ parsed and processed.
+* Many nodes now expose more informations, such as the operator for BooleanExpressions. This makes these operators
+ consumable by XPath rules, e.g. `//BooleanExpression[@Operator='&&']`.
+
+#### PL/SQL Grammar improvements
+
+* In this release, many parser bugs in our PL/SQL support have been fixed. This adds e.g. support for
+ table collection expressions (`SELECT * FROM TABLE(expr)`).
+* Support for parsing insert statements has been added.
+* More improvements are planned for the next release of PMD.
+
+#### New Rules
+
+* The new Java rule [`UnsynchronizedStaticFormatter`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_multithreading.html#unsynchronizedstaticformatter) (`java-multithreading`) detects
+ unsynchronized usages of static `java.text.Format` instances. This rule is a more generic replacement of the
+ rule [`UnsynchronizedStaticDateFormatter`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_multithreading.html#unsynchronizedstaticdateformatter) which focused just on `DateFormat`.
+
+* The new Java rule [`ForLoopVariableCount`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_bestpractices.html#forloopvariablecount) (`java-bestpractices`) checks for
+ the number of control variables in a for-loop. Having a lot of control variables makes it harder to understand
+ what the loop does. The maximum allowed number of variables is by default 1 and can be configured by a
+ property.
+
+* The new Java rule [`AvoidReassigningLoopVariables`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_bestpractices.html#avoidreassigningloopvariables) (`java-bestpractices`) searches
+ for loop variables that are reassigned. Changing the loop variables additionally to the loop itself can lead to
+ hard-to-find bugs.
+
+* The new Java rule [`UseDiamondOperator`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_codestyle.html#usediamondoperator) (`java-codestyle`) looks for constructor
+ calls with explicit type parameters. Since Java 1.7, these type parameters are not necessary anymore, as they
+ can be inferred now.
+
+#### Modified Rules
+
+* The Java rule [`LocalVariableCouldBeFinal`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_codestyle.html#localvariablecouldbefinal) (`java-codestyle`) has a new
+ property `ignoreForEachDecl`, which is by default disabled. The new property allows for ignoring
+ non-final loop variables in a for-each statement.
+
+#### Deprecated Rules
+
+* The Java rule [`UnsynchronizedStaticDateFormatter`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_multithreading.html#unsynchronizedstaticdateformatter) has been deprecated and
+ will be removed with PMD 7.0.0. The rule is replaced by the more general
+ [`UnsynchronizedStaticFormatter`](https://pmd.github.io/pmd-6.11.0/pmd_rules_java_multithreading.html#unsynchronizedstaticformatter).
+
+### Fixed Issues
+
+* core
+ * [#1196](https://github.com/pmd/pmd/issues/1196): \[core] CPD results not consistent between runs
+ * [#1496](https://github.com/pmd/pmd/issues/1496) \[core] Refactor metrics to be dealt with generically from pmd-core
+* apex
+ * [#1542](https://github.com/pmd/pmd/pull/1542): \[apex] Include the documentation category
+ * [#1546](https://github.com/pmd/pmd/issues/1546): \[apex] PMD parsing exception for Apex classes using 'inherited sharing' keyword
+ * [#1568](https://github.com/pmd/pmd/pull/1568): \[apex] AST node attribute @Image not usable / always null in XPath rule / Designer
+* java
+ * [#1556](https://github.com/pmd/pmd/issues/1556): \[java] Default methods should not be considered abstract
+ * [#1578](https://github.com/pmd/pmd/issues/1578): \[java] Private field is detected as public inside nested classes in interfaces
+* java-bestpractices
+ * [#658](https://github.com/pmd/pmd/issues/658): \[java] OneDeclarationPerLine: False positive for loops
+ * [#1518](https://github.com/pmd/pmd/issues/1518): \[java] New rule: AvoidReassigningLoopVariable
+ * [#1519](https://github.com/pmd/pmd/issues/1519): \[java] New rule: ForLoopVariableCount
+* java-codestyle
+ * [#1513](https://github.com/pmd/pmd/issues/1513): \[java] LocalVariableCouldBeFinal: allow excluding the variable in a for-each loop
+ * [#1517](https://github.com/pmd/pmd/issues/1517): \[java] New Rule: UseDiamondOperator
+* java-errorprone
+ * [#1035](https://github.com/pmd/pmd/issues/1035): \[java] ReturnFromFinallyBlock: False positive on lambda expression in finally block
+ * [#1549](https://github.com/pmd/pmd/issues/1549): \[java] NPE in PMD 6.8.0 InvalidSlf4jMessageFormat
+* java-multithreading
+ * [#1533](https://github.com/pmd/pmd/issues/1533): \[java] New rule: UnsynchronizedStaticFormatter
+* plsql
+ * [#1507](https://github.com/pmd/pmd/issues/1507): \[plsql] Parse Exception when using '||' operator in where clause
+ * [#1508](https://github.com/pmd/pmd/issues/1508): \[plsql] Parse Exception when using SELECT COUNT(\*)
+ * [#1509](https://github.com/pmd/pmd/issues/1509): \[plsql] Parse Exception with OUTER/INNER Joins
+ * [#1511](https://github.com/pmd/pmd/issues/1511): \[plsql] Parse Exception with IS NOT NULL
+ * [#1526](https://github.com/pmd/pmd/issues/1526): \[plsql] ParseException when using TableCollectionExpression
+ * [#1583](https://github.com/pmd/pmd/issues/1583): \[plsql] Update Set Clause should allow multiple columns
+ * [#1586](https://github.com/pmd/pmd/issues/1586): \[plsql] Parse Exception when functions are used with LIKE
+ * [#1588](https://github.com/pmd/pmd/issues/1588): \[plsql] Parse Exception with function calls in WHERE clause
+
+### API Changes
+
+* [`StatisticalRule`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.html#) and the related helper classes and base rule classes
+are deprecated for removal in 7.0.0. This includes all of [`net.sourceforge.pmd.stat`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/stat/package-summary.html#) and [`net.sourceforge.pmd.lang.rule.stat`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/lang/rule/stat/package-summary.html#),
+and also [`AbstractStatisticalJavaRule`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.11.0/net/sourceforge/pmd/lang/java/rule/AbstractStatisticalJavaRule.html#), [`AbstractStatisticalApexRule`](https://javadoc.io/page/net.sourceforge.pmd/pmd-apex/6.11.0/net/sourceforge/pmd/lang/apex/rule/AbstractStatisticalApexRule.html#) and the like.
+The methods [`Report#addMetric`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/Report.html#addMetric(net.sourceforge.pmd.stat.Metric)) and [`metricAdded`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/ThreadSafeReportListener.html#metricAdded(net.sourceforge.pmd.stat.Metric))
+will also be removed.
+* [`setProperty`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/properties/PropertySource.html#setProperty(net.sourceforge.pmd.properties.MultiValuePropertyDescriptor,Object[])) is deprecated,
+because [`MultiValuePropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.11.0/net/sourceforge/pmd/properties/MultiValuePropertyDescriptor.html#) is deprecated as well
+
+### External Contributions
+
+* [#1503](https://github.com/pmd/pmd/pull/1503): \[java] Fix for ReturnFromFinallyBlock false-positives - [RishabhDeep Singh](https://github.com/rishabhdeepsingh)
+* [#1514](https://github.com/pmd/pmd/pull/1514): \[java] LocalVariableCouldBeFinal: allow excluding the variable in a for-each loop - [Kris Scheibe](https://github.com/kris-scheibe)
+* [#1516](https://github.com/pmd/pmd/pull/1516): \[java] OneDeclarationPerLine: Don't report multiple variables in a for statement. - [Kris Scheibe](https://github.com/kris-scheibe)
+* [#1520](https://github.com/pmd/pmd/pull/1520): \[java] New rule: ForLoopVariableCount: check the number of control variables in a for loop - [Kris Scheibe](https://github.com/kris-scheibe)
+* [#1521](https://github.com/pmd/pmd/pull/1521): \[java] Upgrade to ASM7 for JDK 11 support - [Mark Pritchard](https://github.com/markpritchard)
+* [#1530](https://github.com/pmd/pmd/pull/1530): \[java] New rule: AvoidReassigningLoopVariables - [Kris Scheibe](https://github.com/kris-scheibe)
+* [#1534](https://github.com/pmd/pmd/pull/1534): \[java] This is the change regarding the usediamondoperator #1517 - [hemanshu070](https://github.com/hemanshu070)
+* [#1545](https://github.com/pmd/pmd/pull/1545): \[doc] fixing dead links + tool to check for dead links automatically - [Kris Scheibe](https://github.com/kris-scheibe)
+* [#1551](https://github.com/pmd/pmd/pull/1551): \[java] InvalidSlf4jMessageFormatRule should not throw NPE for enums - [Robbie Martinus](https://github.com/rmartinus)
+* [#1552](https://github.com/pmd/pmd/pull/1552): \[core] Upgrading Google Gson from 2.5 to 2.8.5 - [Thunderforge](https://github.com/Thunderforge)
+* [#1553](https://github.com/pmd/pmd/pull/1553): \[core] Upgrading System Rules dependency from 1.8.0 to 1.19.0 - [Thunderforge](https://github.com/Thunderforge)
+* [#1554](https://github.com/pmd/pmd/pull/1554): \[plsql] updates should allow for multiple statements - [tashiscool](https://github.com/tashiscool)
+* [#1584](https://github.com/pmd/pmd/pull/1584): \[core] Fixes 1196: inconsistencies of clones returned by different CPD executions for the same files - [Bruno Ferreira](https://github.com/bmbferreira)
+
## 09-December-2018 - 6.10.0
The PMD team is pleased to announce PMD 6.10.0.
diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml
index 210bccf173..6d18f8f1a7 100644
--- a/pmd-apex-jorje/pom.xml
+++ b/pmd-apex-jorje/pom.xml
@@ -8,7 +8,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml
index 4e2af0c24a..78754823fb 100644
--- a/pmd-apex/pom.xml
+++ b/pmd-apex/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java
index 6984ff1a36..3a8663871d 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java
@@ -5,21 +5,34 @@
package net.sourceforge.pmd.lang.apex;
import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.VisitorStarter;
import net.sourceforge.pmd.lang.XPathHandler;
+import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
+import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface;
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
import net.sourceforge.pmd.lang.apex.ast.DumpFacade;
+import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsComputer;
+import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey;
+import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey;
import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileVisitorFacade;
import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory;
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
+import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
+
public class ApexHandler extends AbstractLanguageVersionHandler {
+ private final ApexMetricsProvider myMetricsProvider = new ApexMetricsProvider();
+
+
@Override
public VisitorStarter getMultifileFacade() {
return rootNode -> new ApexMultifileVisitorFacade().initializeWith((ApexNode>) rootNode);
@@ -51,4 +64,31 @@ public class ApexHandler extends AbstractLanguageVersionHandler {
return rootNode -> new DumpFacade().initializeWith(writer, prefix, recurse, (ApexNode>) rootNode);
}
+
+ @Override
+ public LanguageMetricsProvider, ASTMethod> getLanguageMetricsProvider() {
+ return myMetricsProvider;
+ }
+
+
+ private static class ApexMetricsProvider extends AbstractLanguageMetricsProvider, ASTMethod> {
+
+ @SuppressWarnings("unchecked")
+ ApexMetricsProvider() {
+ // a wild double cast
+ super((Class>) (Object) ASTUserClassOrInterface.class, ASTMethod.class, ApexMetricsComputer.getInstance());
+ }
+
+
+ @Override
+ public List getAvailableTypeMetrics() {
+ return Arrays.asList(ApexClassMetricKey.values());
+ }
+
+
+ @Override
+ public List getAvailableOperationMetrics() {
+ return Arrays.asList(ApexOperationMetricKey.values());
+ }
+ }
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java
index 29f466692b..de3531be71 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java
@@ -4,6 +4,7 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.data.ast.AssignmentOp;
import apex.jorje.semantic.ast.expression.AssignmentExpression;
public class ASTAssignmentExpression extends AbstractApexNode {
@@ -16,4 +17,8 @@ public class ASTAssignmentExpression extends AbstractApexNode {
@@ -16,4 +17,8 @@ public class ASTBinaryExpression extends AbstractApexNode {
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+ public BinaryOp getOperator() {
+ return node.getOp();
+ }
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java
index f2e44dbc4a..efd46f2a2b 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java
@@ -4,16 +4,25 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.data.ast.BooleanOp;
import apex.jorje.semantic.ast.expression.BooleanExpression;
+
public class ASTBooleanExpression extends AbstractApexNode {
public ASTBooleanExpression(BooleanExpression booleanExpression) {
super(booleanExpression);
}
+
@Override
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+
+ public BooleanOp getOperator() {
+ return this.node.getOp();
+ }
+
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java
index 19e7440fac..35b04e7d37 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java
@@ -4,16 +4,24 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.data.ast.LiteralType;
import apex.jorje.semantic.ast.expression.LiteralExpression;
+
public class ASTLiteralExpression extends AbstractApexNode {
public ASTLiteralExpression(LiteralExpression literalExpression) {
super(literalExpression);
}
+
@Override
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+
+ public LiteralType getLiteralType() {
+ return node.getLiteralType();
+ }
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java
index 4d2bd2b017..5a760da8b2 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java
@@ -4,16 +4,24 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.data.ast.PostfixOp;
import apex.jorje.semantic.ast.expression.PostfixExpression;
+
public class ASTPostfixExpression extends AbstractApexNode {
public ASTPostfixExpression(PostfixExpression postfixExpression) {
super(postfixExpression);
}
+
@Override
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+
+ public PostfixOp getOperator() {
+ return node.getOp();
+ }
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java
index 11db2fb4a3..4dd4a20cde 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java
@@ -4,6 +4,7 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.data.ast.PrefixOp;
import apex.jorje.semantic.ast.expression.PrefixExpression;
public class ASTPrefixExpression extends AbstractApexNode {
@@ -16,4 +17,10 @@ public class ASTPrefixExpression extends AbstractApexNode {
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+
+ public PrefixOp getOperator() {
+ return node.getOp();
+ }
+
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java
index 32e91d26bb..ef3db237a3 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java
@@ -4,7 +4,10 @@
package net.sourceforge.pmd.lang.apex.ast;
+import apex.jorje.semantic.ast.expression.IdentifierContext;
import apex.jorje.semantic.ast.expression.ReferenceExpression;
+import apex.jorje.semantic.ast.expression.ReferenceType;
+
public class ASTReferenceExpression extends AbstractApexNode {
@@ -12,8 +15,19 @@ public class ASTReferenceExpression extends AbstractApexNode extends AbstractApexNo
protected final T node;
- public AbstractApexNode(T node) {
+ protected AbstractApexNode(T node) {
super(node.getClass());
this.node = node;
}
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java
index d0d82c3d63..63ccc76f74 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java
@@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.apex.metrics;
import java.util.ArrayList;
import java.util.List;
+import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface;
import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
@@ -18,7 +19,13 @@ import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
*/
public class ApexMetricsComputer extends AbstractMetricsComputer, ASTMethod> {
- static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer();
+ private static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer();
+
+
+ @InternalApi
+ public static ApexMetricsComputer getInstance() {
+ return INSTANCE;
+ }
@Override
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java
index 0bcd271ab9..4ed4fa23d3 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java
@@ -27,7 +27,7 @@ public class ApexMetricsFacade extends AbstractMetricsFacade, ASTMethod> getLanguageSpecificComputer() {
- return ApexMetricsComputer.INSTANCE;
+ return ApexMetricsComputer.getInstance();
}
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java
new file mode 100644
index 0000000000..a7b1f2012d
--- /dev/null
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java
@@ -0,0 +1,35 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.apex.ast;
+
+import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import net.sourceforge.pmd.lang.ast.Node;
+
+import apex.jorje.semantic.ast.compilation.Compilation;
+
+public class ApexParserXPathTest {
+
+ @Test
+ public void testBooleanExpressions() throws Exception {
+ ApexNode node = parse(IOUtils.toString(ApexParserXPathTest.class.getResourceAsStream("BooleanExpressions.cls"),
+ StandardCharsets.UTF_8));
+ List booleanExpressions = node.findDescendantsOfType(ASTBooleanExpression.class);
+ Assert.assertEquals(2, booleanExpressions.size());
+ Assert.assertEquals("&&", booleanExpressions.get(0).getOperator().toString());
+ Assert.assertEquals("!=", booleanExpressions.get(1).getOperator().toString());
+
+ List extends Node> xpathResult = node.findChildNodesWithXPath("//BooleanExpression[@Operator='&&']");
+ Assert.assertEquals(1, xpathResult.size());
+ Assert.assertSame(booleanExpressions.get(0), xpathResult.get(0));
+ }
+}
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java
index 9c78229005..49d077318b 100644
--- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java
@@ -91,7 +91,7 @@ public class ApexProjectMirrorTest {
@Override
public Object visit(ASTMethod node, Object data) {
MetricMemoizer op = toplevel.getOperationMemoizer(node.getQualifiedName());
- result.add((int) ApexMetricsComputer.INSTANCE.computeForOperation(opMetricKey, node, force,
+ result.add((int) ApexMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force,
MetricOptions.emptyOptions(), op));
return super.visit(node, data);
}
@@ -100,7 +100,7 @@ public class ApexProjectMirrorTest {
@Override
public Object visit(ASTUserClass node, Object data) {
MetricMemoizer> clazz = toplevel.getClassMemoizer(node.getQualifiedName());
- result.add((int) ApexMetricsComputer.INSTANCE.computeForType(classMetricKey, node, force,
+ result.add((int) ApexMetricsComputer.getInstance().computeForType(classMetricKey, node, force,
MetricOptions.emptyOptions(), clazz));
return super.visit(node, data);
}
diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/BooleanExpressions.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/BooleanExpressions.cls
new file mode 100644
index 0000000000..d70885a456
--- /dev/null
+++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/BooleanExpressions.cls
@@ -0,0 +1,9 @@
+// See https://github.com/pmd/pmd/issues/1568
+
+class MyApexClass {
+ void bar(){
+ if(!alist.isEmpty() && alist != null) {
+ foo();
+ }
+ }
+}
diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml
index 3e3c6f51fc..1f7f28b889 100644
--- a/pmd-core/pom.xml
+++ b/pmd-core/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java
new file mode 100644
index 0000000000..b7ae345175
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java
@@ -0,0 +1,49 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * @author Clément Fournier
+ * @since 6.11.0
+ */
+public final class IteratorUtil {
+
+ private IteratorUtil() {
+
+ }
+
+
+ public static Iterator reverse(Iterator it) {
+ List tmp = toList(it);
+ Collections.reverse(tmp);
+ return tmp.iterator();
+ }
+
+
+ public static List toList(Iterator it) {
+ List list = new ArrayList<>();
+ while (it.hasNext()) {
+ list.add(it.next());
+ }
+ return list;
+ }
+
+
+ public static Iterable toIterable(final Iterator it) {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return it;
+ }
+ };
+ }
+
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java
index 400be33c40..c00f38a05f 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java
@@ -7,6 +7,8 @@ package net.sourceforge.pmd.lang;
import java.io.Writer;
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
+
/**
* This is a generic implementation of the LanguageVersionHandler interface.
@@ -71,4 +73,10 @@ public abstract class AbstractLanguageVersionHandler implements LanguageVersionH
public DFAGraphRule getDFAGraphRule() {
return null;
}
+
+
+ @Override
+ public LanguageMetricsProvider, ?> getLanguageMetricsProvider() {
+ return null;
+ }
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java
index 5037c9f456..5474b1758a 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java
@@ -6,8 +6,10 @@ package net.sourceforge.pmd.lang;
import java.io.Writer;
+import net.sourceforge.pmd.annotation.Experimental;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
/**
@@ -135,4 +137,17 @@ public interface LanguageVersionHandler {
@Deprecated
@InternalApi
DFAGraphRule getDFAGraphRule();
+
+
+ /**
+ * Returns the metrics provider for this language version,
+ * or null if it has none.
+ *
+ * Note: this is experimental, ie unstable until 7.0.0, after
+ * which it will probably be promoted to a stable API. For
+ * instance the return type will probably be changed to an Optional.
+ */
+ @Experimental
+ LanguageMetricsProvider, ?> getLanguageMetricsProvider();
+
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
index 6f57f00dab..ef05342008 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.xpath;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
@@ -18,6 +19,9 @@ import net.sourceforge.pmd.lang.ast.Node;
* Attributes know their name, the node they wrap,
* and have access to their value.
*
+ *
Two attributes are equal if they have the same name
+ * and their parent nodes are equal.
+ *
* @author daniels
*/
public class Attribute {
@@ -28,8 +32,8 @@ public class Attribute {
private static final Object[] EMPTY_OBJ_ARRAY = new Object[0];
- private Node parent;
- private String name;
+ private final Node parent;
+ private final String name;
private Method method;
private Object value;
private String stringValue;
@@ -41,7 +45,6 @@ public class Attribute {
this.method = m;
}
-
/** Creates a new attribute belonging to the given node using its string value. */
public Attribute(Node parent, String name, String value) {
this.parent = parent;
@@ -93,12 +96,33 @@ public class Attribute {
return stringValue;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Attribute attribute = (Attribute) o;
+ return Objects.equals(parent, attribute.parent)
+ && Objects.equals(name, attribute.name);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(parent, name);
+ }
+
+
private String getLoggableAttributeName() {
return parent.getXPathNodeName() + "/@" + name;
}
@Override
public String toString() {
- return name + ':' + getValue() + ':' + parent;
+ return name + ':' + getValue() + ':' + parent.getXPathNodeName();
}
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java
index 75807ecd71..13397c16e1 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java
@@ -69,7 +69,6 @@ public class AttributeAxisIterator implements Iterator {
this.currObj = getNextAttribute();
}
-
/**
* Returns whether the given method is an attribute accessor,
* in which case a corresponding Attribute will be added to
@@ -80,12 +79,16 @@ public class AttributeAxisIterator implements Iterator {
protected boolean isAttributeAccessor(Method method) {
String methodName = method.getName();
- return CONSIDERED_RETURN_TYPES.contains(method.getReturnType())
+ return isConsideredReturnType(method.getReturnType())
&& method.getParameterTypes().length == 0
&& !methodName.startsWith("jjt")
&& !FILTERED_OUT_NAMES.contains(methodName);
}
+ private boolean isConsideredReturnType(Class> klass) {
+ return CONSIDERED_RETURN_TYPES.contains(klass) || klass.isEnum();
+ }
+
@Override
public Attribute next() {
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java
new file mode 100644
index 0000000000..ec57cceff9
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java
@@ -0,0 +1,92 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.metrics;
+
+import java.util.List;
+import java.util.Map;
+
+import net.sourceforge.pmd.annotation.Experimental;
+import net.sourceforge.pmd.lang.LanguageVersionHandler;
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.ast.QualifiableNode;
+
+
+/**
+ * Language-specific provider for metrics. Knows about all the metrics
+ * defined for a language. Can be used e.g. to build GUI applications
+ * like the designer, in a language independent way. Accessible through
+ * {@link LanguageVersionHandler#getLanguageMetricsProvider()}.
+ *
+ * Note: this is experimental, ie unstable until 7.0.0, after which it will probably
+ * be promoted to a real API.
+ *
+ * @param Type of type declaration nodes of the language
+ * @param Type of operation declaration nodes of the language
+ *
+ * @author Clément Fournier
+ * @since 6.11.0
+ */
+@Experimental
+public interface LanguageMetricsProvider {
+
+ /**
+ * Returns a list of all supported type metric keys
+ * for the language.
+ */
+ List extends MetricKey> getAvailableTypeMetrics();
+
+
+ /**
+ * Returns a list of all supported operation metric keys
+ * for the language.
+ */
+ List extends MetricKey> getAvailableOperationMetrics();
+
+
+ /**
+ * Returns the given node casted to {@link T} if it's of the correct
+ * type, otherwise returns null.
+ */
+ T asTypeNode(Node anyNode);
+
+
+ /**
+ * Returns the given node casted to {@link O} if it's of the correct
+ * type, otherwise returns null.
+ */
+ O asOperationNode(Node anyNode);
+
+
+ /**
+ * Like {@link MetricsComputer#computeForType(MetricKey, QualifiableNode, boolean, MetricOptions, MetricMemoizer)},
+ * but performs no memoisation.
+ */
+ double computeForType(MetricKey key, T node, MetricOptions options);
+
+
+ /**
+ * Like {@link MetricsComputer#computeForOperation(MetricKey, QualifiableNode, boolean, MetricOptions, MetricMemoizer)}
+ * but performs no memoisation.
+ */
+ double computeForOperation(MetricKey key, O node, MetricOptions options);
+
+
+ /**
+ * Like {@link MetricsComputer#computeWithResultOption(MetricKey, QualifiableNode, boolean, MetricOptions, ResultOption, ProjectMemoizer)}
+ * but performs no memoisation.
+ */
+ double computeWithResultOption(MetricKey key, T node, MetricOptions options, ResultOption option);
+
+
+ /**
+ * Computes all metrics available on the given node.
+ * The returned results may contain Double.NaN as a value.
+ *
+ * @param node Node to inspect
+ *
+ * @return A map of metric key to their result, possibly empty, but with no null value
+ */
+ Map, Double> computeAllMetricsFor(Node node);
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java
index 4f7521df0d..2259ed8956 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java
@@ -41,5 +41,6 @@ public interface MetricKey {
*/
boolean supports(N node);
+ // TODO the metric key should know about supported options
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java
new file mode 100644
index 0000000000..d6f46e0d7a
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java
@@ -0,0 +1,90 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.metrics.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.ast.QualifiableNode;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
+import net.sourceforge.pmd.lang.metrics.MetricKey;
+import net.sourceforge.pmd.lang.metrics.MetricOptions;
+import net.sourceforge.pmd.lang.metrics.MetricsComputer;
+import net.sourceforge.pmd.lang.metrics.ResultOption;
+
+
+/**
+ * Base implementation for {@link LanguageMetricsProvider}.
+ *
+ * @author Clément Fournier
+ * @since 6.11.0
+ */
+public abstract class AbstractLanguageMetricsProvider implements LanguageMetricsProvider {
+
+ private final Class tClass;
+ private final Class oClass;
+ private final MetricsComputer myComputer;
+
+
+ protected AbstractLanguageMetricsProvider(Class tClass,
+ Class oClass,
+ MetricsComputer computer) {
+ this.tClass = tClass;
+ this.oClass = oClass;
+ this.myComputer = computer;
+ }
+
+
+ @Override
+ public T asTypeNode(Node anyNode) {
+ return tClass.isInstance(anyNode) ? tClass.cast(anyNode) : null;
+ }
+
+
+ @Override
+ public O asOperationNode(Node anyNode) {
+ return oClass.isInstance(anyNode) ? oClass.cast(anyNode) : null;
+ }
+
+
+ @Override
+ public double computeForType(MetricKey key, T node, MetricOptions options) {
+ return myComputer.computeForType(key, node, true, options, DummyMetricMemoizer.getInstance());
+ }
+
+
+ @Override
+ public double computeForOperation(MetricKey key, O node, MetricOptions options) {
+ return myComputer.computeForOperation(key, node, true, options, DummyMetricMemoizer.getInstance());
+ }
+
+
+ @Override
+ public double computeWithResultOption(MetricKey key, T node, MetricOptions options, ResultOption option) {
+ return myComputer.computeWithResultOption(key, node, true, options, option, DummyProjectMemoizer.getInstance());
+ }
+
+
+ @Override
+ public Map, Double> computeAllMetricsFor(Node node) {
+ Map, Double> results = new HashMap<>();
+ T t = asTypeNode(node);
+ if (t != null) {
+ for (MetricKey tkey : getAvailableTypeMetrics()) {
+ results.put(tkey, computeForType(tkey, t, MetricOptions.emptyOptions()));
+ }
+ }
+ O o = asOperationNode(node);
+ if (o != null) {
+ for (MetricKey okey : getAvailableOperationMetrics()) {
+ results.put(okey, computeForOperation(okey, o, MetricOptions.emptyOptions()));
+ }
+ }
+
+ return results;
+ }
+
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java
new file mode 100644
index 0000000000..1d6cae45a1
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java
@@ -0,0 +1,44 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.metrics.internal;
+
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
+import net.sourceforge.pmd.lang.metrics.ParameterizedMetricKey;
+
+
+/**
+ * Memoizes nothing.
+ *
+ * @author Clément Fournier
+ * @since 6.11.0
+ */
+public final class DummyMetricMemoizer implements MetricMemoizer {
+
+ private static final DummyMetricMemoizer INSTANCE = new DummyMetricMemoizer<>();
+
+
+ private DummyMetricMemoizer() {
+
+ }
+
+
+ @Override
+ public Double getMemo(ParameterizedMetricKey key) {
+ return null;
+ }
+
+
+ @Override
+ public void memoize(ParameterizedMetricKey key, double value) {
+ // do nothing
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public static DummyMetricMemoizer getInstance() {
+ return (DummyMetricMemoizer) INSTANCE;
+ }
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java
new file mode 100644
index 0000000000..10abe75a9e
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java
@@ -0,0 +1,45 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.metrics.internal;
+
+import net.sourceforge.pmd.lang.ast.QualifiableNode;
+import net.sourceforge.pmd.lang.ast.QualifiedName;
+import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
+import net.sourceforge.pmd.lang.metrics.ProjectMemoizer;
+
+
+/**
+ * Memoizes nothing.
+ *
+ * @author Clément Fournier
+ * @since 6.11.0
+ */
+public final class DummyProjectMemoizer implements ProjectMemoizer {
+
+ private static final DummyProjectMemoizer extends QualifiableNode, ? extends QualifiableNode> INSTANCE = new DummyProjectMemoizer<>();
+
+
+ private DummyProjectMemoizer() {
+
+ }
+
+
+ @Override
+ public MetricMemoizer getOperationMemoizer(QualifiedName qname) {
+ return DummyMetricMemoizer.getInstance();
+ }
+
+
+ @Override
+ public MetricMemoizer getClassMemoizer(QualifiedName qname) {
+ return DummyMetricMemoizer.getInstance();
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public static DummyProjectMemoizer getInstance() {
+ return (DummyProjectMemoizer) INSTANCE;
+ }
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java
index ddbe17615b..b369007c68 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java
@@ -236,7 +236,9 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
*/
if (value == null) {
return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
-
+ } else if (value instanceof Enum) {
+ // enums use their toString
+ return new StringValue(value.toString());
} else if (value instanceof String) {
return new StringValue((String) value);
} else if (value instanceof Boolean) {
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java
index 386837f0a9..71463940cf 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java
@@ -164,6 +164,7 @@ public abstract class AbstractPropertySource implements PropertySource {
@Override
+ @Deprecated
public void setProperty(MultiValuePropertyDescriptor propertyDescriptor, V... values) {
checkValidPropertyDescriptor(propertyDescriptor);
propertyValuesByDescriptor.put(propertyDescriptor, Collections.unmodifiableList(Arrays.asList(values)));
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java
index 7b24644164..7a516714bd 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java
@@ -112,7 +112,10 @@ public interface PropertySource {
* @param propertyDescriptor The property descriptor for which to add a value
* @param values Values
* @param The type of the values
+ *
+ * @deprecated {@link MultiValuePropertyDescriptor} is deprecated
*/
+ @Deprecated
void setProperty(MultiValuePropertyDescriptor propertyDescriptor, V... values);
diff --git a/pmd-core/src/main/resources/rulesets/releases/6110.xml b/pmd-core/src/main/resources/rulesets/releases/6110.xml
new file mode 100644
index 0000000000..f0479f4339
--- /dev/null
+++ b/pmd-core/src/main/resources/rulesets/releases/6110.xml
@@ -0,0 +1,17 @@
+
+
+
+
+This ruleset contains links to rules that are new in PMD v6.11.0
+
+
+
+
+
+
+
+
+
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
index e8326ca32d..4827e8f544 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.xpath;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
@@ -52,6 +53,17 @@ public class AttributeAxisIteratorTest {
assertTrue(atts.containsKey("EndLine"));
}
+ @Test
+ public void testAttributeAxisIteratorWithEnum() {
+ DummyNodeWithEnum dummyNode = new DummyNodeWithEnum(1);
+
+ AttributeAxisIterator it = new AttributeAxisIterator(dummyNode);
+ Map atts = toMap(it);
+ Assert.assertEquals(8, atts.size());
+ assertTrue(atts.containsKey("Enum"));
+ assertEquals(DummyNodeWithEnum.MyEnum.FOO, atts.get("Enum").getValue());
+ }
+
private Map toMap(AttributeAxisIterator it) {
Map atts = new HashMap<>();
@@ -61,4 +73,19 @@ public class AttributeAxisIteratorTest {
}
return atts;
}
+
+ public static class DummyNodeWithEnum extends DummyNode {
+
+ public DummyNodeWithEnum(int id) {
+ super(id);
+ }
+
+ public enum MyEnum {
+ FOO, BAR
+ }
+
+ public MyEnum getEnum() {
+ return MyEnum.FOO;
+ }
+ }
}
diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml
index 0552cc11f7..5d0afa82cb 100644
--- a/pmd-cpp/pom.xml
+++ b/pmd-cpp/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml
index 8cb50f99fe..d915d20c47 100644
--- a/pmd-cs/pom.xml
+++ b/pmd-cs/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml
index d234675496..0aa8302284 100644
--- a/pmd-dist/pom.xml
+++ b/pmd-dist/pom.xml
@@ -8,11 +8,36 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
+
+ pmd-bin-${project.version}
+
+
+
+ maven-resources-plugin
+
+
+ copy-resources
+ prepare-package
+
+ copy-resources
+
+
+ ${basedir}/target/extra-resources
+
+
+ src/main/resources
+ false
+
+
+
+
+
+ maven-assembly-plugin
@@ -30,9 +55,9 @@
single
- pmd-bin-${project.version}
+ ${pmd.dist.bin.baseDirectory}
- src/main/assembly/bin.xml
+ src/main/resources/assemblies/pmd-bin.xml
@@ -45,7 +70,7 @@
pmd-src-${project.version}
- src/main/assembly/src.xml
+ src/main/resources/assemblies/pmd-src.xml
diff --git a/pmd-dist/LICENSE b/pmd-dist/src/main/resources/LICENSE
similarity index 100%
rename from pmd-dist/LICENSE
rename to pmd-dist/src/main/resources/LICENSE
diff --git a/pmd-dist/src/main/assembly/bin.xml b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml
similarity index 84%
rename from pmd-dist/src/main/assembly/bin.xml
rename to pmd-dist/src/main/resources/assemblies/pmd-bin.xml
index 2b44241aa9..8b0c0134b2 100644
--- a/pmd-dist/src/main/assembly/bin.xml
+++ b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml
@@ -1,13 +1,13 @@
- bin
+ pmd-binziptrue
- pmd-bin-${project.version}
+ ${pmd.dist.bin.baseDirectory}
@@ -18,7 +18,7 @@
designer.batpmd.bat
- src/main/scripts
+ target/extra-resources/scriptsbin07550755
@@ -29,7 +29,7 @@
run.sh
- src/main/scripts
+ target/extra-resources/scriptsbin07550755
@@ -40,6 +40,8 @@
LICENSE
+ target/extra-resources
+ .07550644
diff --git a/pmd-dist/src/main/assembly/src.xml b/pmd-dist/src/main/resources/assemblies/pmd-src.xml
similarity index 98%
rename from pmd-dist/src/main/assembly/src.xml
rename to pmd-dist/src/main/resources/assemblies/pmd-src.xml
index e69362fffc..8c8820d03c 100644
--- a/pmd-dist/src/main/assembly/src.xml
+++ b/pmd-dist/src/main/resources/assemblies/pmd-src.xml
@@ -1,7 +1,7 @@
- src
+ pmd-srczip
diff --git a/pmd-dist/src/main/scripts/bgastviewer.bat b/pmd-dist/src/main/resources/scripts/bgastviewer.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/bgastviewer.bat
rename to pmd-dist/src/main/resources/scripts/bgastviewer.bat
diff --git a/pmd-dist/src/main/scripts/cpd.bat b/pmd-dist/src/main/resources/scripts/cpd.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/cpd.bat
rename to pmd-dist/src/main/resources/scripts/cpd.bat
diff --git a/pmd-dist/src/main/scripts/cpdgui.bat b/pmd-dist/src/main/resources/scripts/cpdgui.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/cpdgui.bat
rename to pmd-dist/src/main/resources/scripts/cpdgui.bat
diff --git a/pmd-dist/src/main/scripts/designer.bat b/pmd-dist/src/main/resources/scripts/designer.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/designer.bat
rename to pmd-dist/src/main/resources/scripts/designer.bat
diff --git a/pmd-dist/src/main/scripts/designerold.bat b/pmd-dist/src/main/resources/scripts/designerold.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/designerold.bat
rename to pmd-dist/src/main/resources/scripts/designerold.bat
diff --git a/pmd-dist/src/main/scripts/pmd.bat b/pmd-dist/src/main/resources/scripts/pmd.bat
similarity index 100%
rename from pmd-dist/src/main/scripts/pmd.bat
rename to pmd-dist/src/main/resources/scripts/pmd.bat
diff --git a/pmd-dist/src/main/scripts/run.sh b/pmd-dist/src/main/resources/scripts/run.sh
similarity index 100%
rename from pmd-dist/src/main/scripts/run.sh
rename to pmd-dist/src/main/resources/scripts/run.sh
diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
index fd1c66249f..b37093098f 100644
--- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
+++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
@@ -5,6 +5,7 @@
package net.sourceforge.pmd.it;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
@@ -59,6 +60,7 @@ public class BinaryDistributionIT {
Set result = new HashSet<>();
String basedir = "pmd-bin-" + PMDVersion.VERSION + "/";
result.add(basedir);
+ result.add(basedir + "LICENSE");
result.add(basedir + "bin/run.sh");
result.add(basedir + "bin/pmd.bat");
result.add(basedir + "bin/cpd.bat");
@@ -81,7 +83,9 @@ public class BinaryDistributionIT {
zip.close();
- assertTrue(expectedFileNames.isEmpty());
+ if (!expectedFileNames.isEmpty()) {
+ fail("Missing files in archive: " + expectedFileNames);
+ }
}
@Test
diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml
index 0f56881346..837214c7bb 100644
--- a/pmd-doc/pom.xml
+++ b/pmd-doc/pom.xml
@@ -8,7 +8,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml
index 95882d573b..15f0f0568b 100644
--- a/pmd-fortran/pom.xml
+++ b/pmd-fortran/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml
index 4575e509ab..59c3390927 100644
--- a/pmd-go/pom.xml
+++ b/pmd-go/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml
index 34353d2920..66f24166be 100644
--- a/pmd-groovy/pom.xml
+++ b/pmd-groovy/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml
index 654e3602d7..ed1c2b3675 100644
--- a/pmd-java/pom.xml
+++ b/pmd-java/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java
index 725a4aae03..179ac6a6f1 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java
@@ -5,6 +5,8 @@
package net.sourceforge.pmd.lang.java;
import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
import net.sourceforge.pmd.lang.DataFlowHandler;
@@ -14,11 +16,16 @@ import net.sourceforge.pmd.lang.XPathHandler;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.DumpFacade;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
+import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade;
import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule;
+import net.sourceforge.pmd.lang.java.metrics.JavaMetricsComputer;
+import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
+import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
import net.sourceforge.pmd.lang.java.multifile.MultifileVisitorFacade;
import net.sourceforge.pmd.lang.java.qname.QualifiedNameResolver;
import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory;
@@ -30,6 +37,9 @@ import net.sourceforge.pmd.lang.java.xpath.MetricFunction;
import net.sourceforge.pmd.lang.java.xpath.TypeIsExactlyFunction;
import net.sourceforge.pmd.lang.java.xpath.TypeIsFunction;
import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
+import net.sourceforge.pmd.lang.metrics.MetricKey;
+import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
import net.sf.saxon.sxpath.IndependentContext;
@@ -42,6 +52,8 @@ import net.sf.saxon.sxpath.IndependentContext;
*/
public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler {
+ private final LanguageMetricsProvider myMetricsProvider = new JavaMetricsProvider();
+
@Override
public DataFlowHandler getDataFlowHandler() {
return new JavaDataFlowHandler();
@@ -147,4 +159,31 @@ public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler
public DFAGraphRule getDFAGraphRule() {
return new JavaDFAGraphRule();
}
+
+
+ @Override
+ public LanguageMetricsProvider getLanguageMetricsProvider() {
+ return myMetricsProvider;
+ }
+
+
+ private static class JavaMetricsProvider extends AbstractLanguageMetricsProvider {
+
+
+ JavaMetricsProvider() {
+ super(ASTAnyTypeDeclaration.class, MethodLikeNode.class, JavaMetricsComputer.getInstance());
+ }
+
+
+ @Override
+ public List extends MetricKey> getAvailableTypeMetrics() {
+ return Arrays.asList(JavaClassMetricKey.values());
+ }
+
+
+ @Override
+ public List extends MetricKey> getAvailableOperationMetrics() {
+ return Arrays.asList(JavaOperationMetricKey.values());
+ }
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java
index b96d66b93a..9d95cb4eda 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java
@@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.metrics;
import java.util.ArrayList;
import java.util.List;
+import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
@@ -20,12 +21,19 @@ import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
*/
public final class JavaMetricsComputer extends AbstractMetricsComputer {
- static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer();
+ private static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer();
private JavaMetricsComputer() {
}
+
+ @InternalApi
+ public static JavaMetricsComputer getInstance() {
+ return INSTANCE;
+ }
+
+
// TODO: doesn't consider lambdas
@Override
protected List findOperations(ASTAnyTypeDeclaration node) {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java
index 6ddd2e1df9..f239407db7 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java
@@ -33,7 +33,7 @@ class JavaMetricsFacade extends AbstractMetricsFacade getLanguageSpecificComputer() {
- return JavaMetricsComputer.INSTANCE;
+ return JavaMetricsComputer.getInstance();
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java
index 2d51621aa1..06ff9ed917 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java
@@ -96,5 +96,4 @@ public enum JavaClassMetricKey implements MetricKey {
return calculator.supports(node);
}
-
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ParserTstUtil.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ParserTstUtil.java
index cd3064565d..15352e90d1 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ParserTstUtil.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ParserTstUtil.java
@@ -205,12 +205,12 @@ public class ParserTstUtil {
}
- public static LanguageVersionHandler getLanguageVersionHandler(String version) {
- return LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler();
+ public static AbstractJavaHandler getLanguageVersionHandler(String version) {
+ return (AbstractJavaHandler) LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler();
}
- public static LanguageVersionHandler getDefaultLanguageVersionHandler() {
- return LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler();
+ public static AbstractJavaHandler getDefaultLanguageVersionHandler() {
+ return (AbstractJavaHandler) LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler();
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProviderTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProviderTest.java
new file mode 100644
index 0000000000..919253837e
--- /dev/null
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProviderTest.java
@@ -0,0 +1,77 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.metrics;
+
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+import net.sourceforge.pmd.lang.java.ParserTstUtil;
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
+import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
+import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
+import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
+import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
+import net.sourceforge.pmd.lang.metrics.MetricKey;
+
+
+/**
+ * @author Clément Fournier
+ */
+public class JavaMetricsProviderTest {
+
+ @Test
+ public void testComputeAllMetrics() {
+
+ LanguageMetricsProvider, ?> provider = ParserTstUtil.getLanguageVersionHandler("1.8").getLanguageMetricsProvider();
+
+ ASTCompilationUnit acu = ParserTstUtil.parseAndTypeResolveJava("1.8",
+ "class Foo { void bar() { System.out.println(1); } }");
+
+ ASTAnyTypeDeclaration type = acu.getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
+
+ Map, Double> results = provider.computeAllMetricsFor(type);
+
+ for (JavaClassMetricKey key : JavaClassMetricKey.values()) {
+ assertTrue(results.containsKey(key));
+ }
+
+ MethodLikeNode op = acu.getFirstDescendantOfType(MethodLikeNode.class);
+
+ Map, Double> opResults = provider.computeAllMetricsFor(op);
+
+ for (JavaOperationMetricKey key : JavaOperationMetricKey.values()) {
+ assertTrue(opResults.containsKey(key));
+ }
+ }
+
+
+ @Test
+ public void testThereIsNoMemoisation() {
+
+ LanguageMetricsProvider, ?> provider = ParserTstUtil.getLanguageVersionHandler("1.8").getLanguageMetricsProvider();
+
+ ASTAnyTypeDeclaration tdecl1 = ParserTstUtil.parseAndTypeResolveJava("1.8",
+ "class Foo { void bar() { System.out.println(1); } }").getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
+
+ Map, Double> reference = provider.computeAllMetricsFor(tdecl1);
+
+ ASTAnyTypeDeclaration tdecl2 = ParserTstUtil.parseAndTypeResolveJava("1.8",
+ // same name, different characteristics
+ "class Foo { void bar(){} \npublic void hey() { System.out.println(1); } }").getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
+
+ Map, Double> secondTest = provider.computeAllMetricsFor(tdecl2);
+
+ assertNotEquals(reference, secondTest);
+
+ }
+
+
+}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java
index eee8a7152b..b40fa44b5f 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java
@@ -74,7 +74,7 @@ public class ProjectMemoizerTest {
@Override
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
MetricMemoizer op = toplevel.getOperationMemoizer(node.getQualifiedName());
- result.add((int) JavaMetricsComputer.INSTANCE.computeForOperation(opMetricKey, node, force,
+ result.add((int) JavaMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force,
MetricOptions.emptyOptions(), op));
return super.visit(node, data);
}
@@ -83,7 +83,7 @@ public class ProjectMemoizerTest {
@Override
public Object visit(ASTAnyTypeDeclaration node, Object data) {
MetricMemoizer clazz = toplevel.getClassMemoizer(node.getQualifiedName());
- result.add((int) JavaMetricsComputer.INSTANCE.computeForType(classMetricKey, node, force,
+ result.add((int) JavaMetricsComputer.getInstance().computeForType(classMetricKey, node, force,
MetricOptions.emptyOptions(), clazz));
return super.visit(node, data);
}
diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml
index 9410e806dd..848229de5f 100644
--- a/pmd-java8/pom.xml
+++ b/pmd-java8/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml
index 92a22aa705..2633bde55f 100644
--- a/pmd-javascript/pom.xml
+++ b/pmd-javascript/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml
index bd00d84195..37c71999fb 100644
--- a/pmd-jsp/pom.xml
+++ b/pmd-jsp/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml
index 99d0e87ec9..3802679aae 100644
--- a/pmd-kotlin/pom.xml
+++ b/pmd-kotlin/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml
index a49d41ca1d..20f376e83b 100644
--- a/pmd-lang-test/pom.xml
+++ b/pmd-lang-test/pom.xml
@@ -12,7 +12,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml
index a112ae29a2..f286ba6516 100644
--- a/pmd-matlab/pom.xml
+++ b/pmd-matlab/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml
index 441a91a398..0cca0c1c0f 100644
--- a/pmd-objectivec/pom.xml
+++ b/pmd-objectivec/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml
index 85ba19d877..6a95565e49 100644
--- a/pmd-perl/pom.xml
+++ b/pmd-perl/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml
index d9fa196b39..26870c3f4d 100644
--- a/pmd-php/pom.xml
+++ b/pmd-php/pom.xml
@@ -7,7 +7,7 @@
net.sourceforge.pmdpmd
- 6.11.0-SNAPSHOT
+ 6.12.0-SNAPSHOT
diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt
index 066a9eab8a..f08f27c0cc 100644
--- a/pmd-plsql/etc/grammar/PldocAST.jjt
+++ b/pmd-plsql/etc/grammar/PldocAST.jjt
@@ -220,9 +220,10 @@ ASTInput Input() : {}
| LOOKAHEAD(6) Global()
| LOOKAHEAD(6) DDLCommand() //Ignore any other DDL Event
| LOOKAHEAD(2) SqlPlusCommand()
- | LOOKAHEAD(2) UpdateStatement()
- | LOOKAHEAD(2) DeleteStatement()
- |(