diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml
index 16874206b..361b1d838 100644
--- a/docs/_data/sidebars/pmd_sidebar.yml
+++ b/docs/_data/sidebars/pmd_sidebar.yml
@@ -3,7 +3,7 @@
entries:
- title: sidebar
- product: PMD Project
+ product: PMD
version: "!PMD_VERSION!"
folders:
@@ -105,6 +105,9 @@ entries:
- title: JSP Support
url: /pmd_languages_jsp.html
output: web, pdf
+ - title: Java code metrics
+ url: /pmd_java_metrics_index.html
+ output: web, pdf
- title: Developer Documentation
output: web, pdf
folderitems:
@@ -144,9 +147,6 @@ entries:
- title: Using code metrics in custom rules
url: /pmd_devdocs_metrics_howto.html
output: web, pdf
- - title: Index of code metrics
- url: /pmd_devdocs_metrics_index.html
- output: web, pdf
- title: Making Rulesets
url: /pmd_devdocs_making_rulesets.html
output: web, pdf
diff --git a/docs/pages/pmd/devdocs/metrics_howto.md b/docs/pages/pmd/devdocs/metrics_howto.md
index 9eb3294a0..71eedd01a 100644
--- a/docs/pages/pmd/devdocs/metrics_howto.md
+++ b/docs/pages/pmd/devdocs/metrics_howto.md
@@ -1,9 +1,9 @@
---
title: Using code metrics in custom rules
tags: [customizing]
-summary: "PMD was recently enhanced with the ability to compute code metrics on Java code (the so-called Metrics
-Framework). This framework provides developers with a straightforward interface to use code metrics in their rules, and
-to extend the framework with their own custom metrics."
+summary: "PMD was recently enhanced with the ability to compute code metrics on Java and Apex source (the so-called
+Metrics Framework). This framework provides developers with a straightforward interface to use code metrics in their
+rules, and to extend the framework with their own custom metrics."
last_updated: July 20, 2017
sidebar: pmd_sidebar
permalink: pmd_devdocs_metrics_howto.html
@@ -13,4 +13,73 @@ folder: pmd/devdocs
## Using the metrics framework
-## Writing custom metrics
\ No newline at end of file
+{%include note.html content="Using the metrics framework is for now restricted to Java rules (with plans to support
+XPath rules later)." %}
+
+To use the metrics framework in a custom rule, the first thing to do would be to enable metrics by adding the
+`metrics="true"` attribute to your rule's XML element.
+
+{%include note.html content="The following explains how to use the Java metrics framework. The Apex framework
+differs only by the name of its classes." %}
+
+In PMD's Metrics framework, a metric is an operation that can be carried out on nodes of a certain type and produces
+a numeric result. In the Java framework, metrics can be computed on operation declaration nodes (constructor and
+method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric
+object in the framework can only handle either types or operations, but not both.
+
+The framework provides a library of already implemented metrics. These metrics are referenced by `MetricKey` objects,
+which are listed in two public enums: `JavaClassMetricKey` and `JavaOperationMetricKey`. Metric keys wrap a metric, and
+know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class
+declaration node. Metrics that can be computed on operation and type declarations (e.g. NCSS) have one metric key in
+each enum.
+
+The static façade class `JavaMetrics` is the only entry point to compute metrics in the Java framework.
+This class provides the method `get` and its overloads. The following sections describes the interface of this class.
+
+### Basic usage
+
+The simplest overloads of `JavaMetrics.get` take two parameters: **a `MetricKey` and a node of the corresponding type.**
+Say you want to write a rule to report methods that have a high cyclomatic complexity. In your rule's visitor, you
+can get the value of Cyclo for a method node like so:
+```java
+public Object visit(ASTMethodDeclaration node, Object data) {
+ int cyclo = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node);
+ if (cyclo > 10) {
+ // add violation
+ }
+ return data;
+}
+```
+
+The same goes for class metrics: you select one among `JavaClassMetricKey`'s constants and pass it along with the node
+ to `JavaMetrics.get`.
+
+### Capability checking
+
+Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on
+abstract methods. Metric keys provides a `supports(Node)` boolean method to find out if the metric can be computed on
+the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .**
+If you're concerned about that, you can condition your call on whether the node is supported or not:
+```java
+public Object visit(ASTMethodDeclaration node, Object data) {
+ if (JavaOperationMetricKey.CYCLO.supports(node)) {
+ int cyclo = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node);
+ if (cyclo > 10) {
+ // add violation
+ }
+ return data;
+ }
+}
+```
+
+### Metric versions
+
+{%include important.html content="Metric versions are about to be revamped into options that can be combined
+together." %}
+
+
+### Result options
+
+## Writing custom metrics
+
+{%include warning.html content="WIP" %}
diff --git a/docs/pages/pmd/devdocs/metrics_index.md b/docs/pages/pmd/devdocs/metrics_index.md
deleted file mode 100644
index 4f558f2a6..000000000
--- a/docs/pages/pmd/devdocs/metrics_index.md
+++ /dev/null
@@ -1,111 +0,0 @@
----
-title: Index of code metrics
-tags: [customizing]
-summary: "Index of the code metrics available out of the box to Java rule developers."
-last_updated: July 20, 2017
-sidebar: pmd_sidebar
-permalink: pmd_devdocs_metrics_index.html
-folder: pmd/devdocs
-toc:
- minimumHeaders: 8
----
-# Index of code metrics
-
-## Access to Foreign Data (ATFD)
-
-*Operation metric, class metric.*
-
-### Description
-
-
-## Cyclomatic Complexity (CYCLO)
-
-*Operation metric.* Can be calculated on any non-abstract method.
-
-### Description
-
-Number of independent paths through a block of code \[[Lanza05](#Lanza05)\].
-Formally, given that the control flow graph of the block has n vertices, e edges and p connected components, the
-Cyclomatic complexity of the block is given by `CYCLO = e - n + 2p` \[[McCabe76](#McCabe76)\]. In practice it can be
-calculated by counting control flow statements following the standard rules given below.
-
-The standard version of the metric complies with McCabe's original definition:
-
-* Methods have a base complexity of 1.
-* +1 for every control flow statement (`if`, `case`, `catch`, `throw`, `do`, `while`, `for`, `break`, `continue`) and
-conditional expression (`?:`) \[[Sonarqube](#Sonarqube)\]. Notice switch cases count as one, but not the switch itself: the point is that
- a switch should have the same complexity value as the equivalent series of `if` statements.
-* `else`, `finally` and `default` don't count;
-* +1 for every boolean operator (`&&`, `||`) in the guard condition of a control flow statement. That's because
-Java has short-circuit evaluation semantics for boolean operators, which makes every boolean operator kind of a
-control flow statement in itself.
-
-### Versions
-
-* Version `CycloVersion#IGNORE_BOOLEAN_PATHS`: Boolean operators are not counted, nor are empty
- fall-through cases in `switch` statements. You can use this version to get results
- similar to those of the old `StdCyclomaticComplexityRule`, which is to be replaced.
-
-
-## Lines of Code (LoC)
-
-*Operation metric, class metric.* Can be calculated on any of those nodes.
-
-### Description
-
-Simply counts the number of lines of code the operation or class takes up in the source. This metric doesn't discount
- comments or blank lines.
-
-
-## Non-commenting source statements (NCSS)
-
-*Operation metric, class metric.* Can be calculated on any of those nodes.
-
-### Description
-
-Number of statements in a class or operation. That's roughly equivalent to counting the number of semicolons and
-opening braces in the program. Comments and blank lines are ignored, and statements spread on multiple lines count as
- only one (e.g. `int\n a;` counts a single statement).
-
-The standard version of the metric is based off JavaNCSS's version \[[JavaNcss](#JavaNcss)\]:
-
-* +1 for any of the following statements: `if`, `else`, `while`, `do`, `for`, `switch`, `break`, `continue`, `return`,
-`throw`, `synchronized`, `catch`, `finally`.
-* +1 for each assignment, variable declaration (except `for` loop initializers) or statement expression. We count
-variables declared on the same line (e.g. `int a, b, c;`) as a single statement.
-* Contrary to Sonarqube, but as JavaNCSS, we count type declarations (class, interface, enum, annotation),
-and method and field declarations \[[Sonarqube](#Sonarqube)\].
-* Contrary to JavaNCSS, but as Sonarqube, we do not count package declaration and import declarations as statements.
-This makes it easier to compare nested classes to outer classes. Besides, it makes for class metric results that
-actually represent the size of the class and not of the file. If you don't like that behaviour, use the `JAVANCSS`
-version.
-
-
-### Versions
-
-* Version `NcssVersion#JAVANCSS`: Import and package statements are counted as well. This version fully complies with
- JavaNCSS.
-
-
-## Weighted Method Count (WMC)
-
-*Class metric.* Can be computed on classes and enums
-
-### Description
-
-Sum of the statistical complexity of the operations in the class. We use [CYCLO](#cyclomatic-complexity-cyclo) to
-quantify the complexity of an operation \[[Lanza05](#Lanza05)\].
-
-### Versions
-
-WMC uses the same versions as CYCLO, which have the effect of summing that version of CYCLO to calculate the metric.
-
-# References
-
-Lanza05: Lanza, Marinescu; Object-Oriented Metrics in Practice, 2005.
-
-McCabe76: McCabe, A Complexity Measure, in Proceedings of the 2nd ICSE (1976).
-
-Sonarqube: [Sonarqube online documentation.](https://docs.sonarqube.org/display/SONAR/Metric+Definitions)
-
-JavaNcss: [JavaNCSS online documentation.](http://www.kclee.de/clemens/java/javancss/)
\ No newline at end of file
diff --git a/docs/pages/pmd/languages/java_metrics_index.md b/docs/pages/pmd/languages/java_metrics_index.md
new file mode 100644
index 000000000..f73b31b4e
--- /dev/null
+++ b/docs/pages/pmd/languages/java_metrics_index.md
@@ -0,0 +1,228 @@
+---
+title: Index of code metrics
+tags: [customizing]
+summary: "Index of the code metrics available out of the box to Java rule developers."
+last_updated: July 20, 2017
+sidebar: pmd_sidebar
+permalink: pmd_java_metrics_index.html
+folder: pmd/languages
+toc:
+ minimumHeaders: 8
+---
+# Index of code metrics
+
+## Access to Foreign Data (ATFD)
+
+*Operation metric, class metric.*
+
+### Description
+
+
+## Cyclomatic Complexity (CYCLO)
+
+*Operation metric.* Can be calculated on any non-abstract operation.
+
+### Description
+
+Number of independent paths through a block of code \[[Lanza05](#Lanza05)\].
+Formally, given that the control flow graph of the block has n vertices, e edges and p connected components, the
+cyclomatic complexity of the block is given by `CYCLO = e - n + 2p` \[[McCabe76](#McCabe76)\]. In practice it can be
+calculated by counting control flow statements following the standard rules given below.
+
+The standard version of the metric complies with McCabe's original definition:
+
+* Methods have a base complexity of 1.
+* +1 for every control flow statement (`if`, `case`, `catch`, `throw`, `do`, `while`, `for`, `break`, `continue`) and
+ conditional expression (`?:`) \[[Sonarqube](#Sonarqube)\]. Notice switch cases count as one, but not the switch
+ itself: the point is that a switch should have the same complexity value as the equivalent series of `if` statements.
+* `else`, `finally` and `default` don't count;
+* +1 for every boolean operator (`&&`, `||`) in the guard condition of a control flow statement. That's because
+ Java has short-circuit evaluation semantics for boolean operators, which makes every boolean operator kind of a
+ control flow statement in itself.
+
+### Code examples
+
+```java
+class Foo {
+ void baseCyclo() { // Cyclo = 1
+ highCyclo();
+ }
+
+ void highCyclo() { // Cyclo = 10
+ int x = 0, y = 2;
+ boolean a = false, b = true;
+
+ if (a && (y == 1 ? b : true)) { // +3
+ if (y == x) { // +1
+ while (true) { // +1
+ if (x++ < 20) { // +1
+ break; // +1
+ }
+ }
+ } else if (y == t && !d) { // +2
+ x = a ? y : x; // +1
+ } else {
+ x = 2;
+ }
+ }
+ }
+}
+```
+### Versions
+
+* Version `CycloVersion#IGNORE_BOOLEAN_PATHS`: Boolean operators are not counted, nor are empty
+ fall-through cases in `switch` statements. You can use this version to get results
+ similar to those of the old `StdCyclomaticComplexityRule`, which is to be replaced.
+
+
+## Lines of Code (LoC)
+
+*Operation metric, class metric.* Can be calculated on any of those nodes.
+
+### Description
+
+Simply counts the number of lines of code the operation or class takes up in the source. This metric doesn't discount
+comments or blank lines. See also [NCSS](#non-commenting-source-statements-ncss).
+
+
+## Non-commenting source statements (NCSS)
+
+*Operation metric, class metric.* Can be calculated on any of those nodes.
+
+### Description
+
+Number of statements in a class or operation. That's roughly equivalent to counting the number of semicolons and
+opening braces in the program. Comments and blank lines are ignored, and statements spread on multiple lines count as
+ only one (e.g. `int\n a;` counts a single statement).
+
+The standard version of the metric is based off JavaNCSS's version \[[JavaNcss](#JavaNcss)\]:
+
+* +1 for any of the following statements: `if`, `else`, `while`, `do`, `for`, `switch`, `break`, `continue`, `return`,
+ `throw`, `synchronized`, `catch`, `finally`.
+* +1 for each assignment, variable declaration (except `for` loop initializers) or statement expression. We count
+ variables declared on the same line (e.g. `int a, b, c;`) as a single statement.
+* Contrary to Sonarqube, but as JavaNCSS, we count type declarations (class, interface, enum, annotation),
+ and method and field declarations \[[Sonarqube](#Sonarqube)\].
+* Contrary to JavaNCSS, but as Sonarqube, we do not count package declaration and import declarations as statements.
+ This makes it easier to compare nested classes to outer classes. Besides, it makes for class metric results that
+ actually represent the size of the class and not of the file. If you don't like that behaviour, use the `JAVANCSS`
+ version.
+
+### Code example
+```java
+import java.util.Collections; // +0
+import java.io.IOException; // +0
+
+class Foo { // +1, total Ncss = 12
+
+ public void bigMethod() // +1
+ throws IOException {
+ int x = 0, y = 2; // +1
+ boolean a = false, b = true; // +1
+
+ if (a || b) { // +1
+ try { // +1
+ do { // +1
+ x += 2; // +1
+ } while (x < 12);
+
+ System.exit(0); // +1
+ } catch (IOException ioe) { // +1
+ throw new PatheticFailException(ioe); // +1
+ }
+ } else {
+ assert false; // +1
+ }
+ }
+}
+```
+
+
+### Versions
+
+* Version `NcssVersion#JAVANCSS`: Import and package statements are counted as well. This version fully complies with
+ JavaNCSS.
+
+## NPath complexity (NPath)
+
+*Operation metric.* Can be computed on any non-abstract operation.
+
+### Description
+
+Number of acyclic execution paths through a piece of code. This is related to cyclomatic complexity, but the two
+metrics don't count the same thing: NPath counts the number of distinct *full* paths from the beginning to the end of
+the method, while Cyclo only counts the number of decision points. NPath is not computed as simply as Cyclo. With
+NPath, two decision points appearing sequentially have their complexity multiplied.
+
+The fact that NPath multiplies the complexity of statements makes it grow exponentially: 10 `if` - `else` statements in
+a row would give an NPath of 1024, while Cyclo would evaluate to 20. Methods with an NPath complexity over 200 are
+generally considered too complex.
+
+We compute NPath recursively, with the following set of rules:
+* An empty block has a complexity of 1.
+* The complexity of a block is the product of the NPath complexity of its statements, calculated as follows:
+ * The complexity of `for`, `do` and `while` statements is 1, plus the complexity of the block, plus the complexity of
+ the guard condition.
+ * The complexity of a cascading `if` statement (`if .. else if ..`) is the number of `if` statements in the chain,
+ plus the complexity of their guard condition, plus the complexity of the unguarded `else` block (or 1 if there is
+ none).
+ * The complexity of a `switch` statement is the number of cases, plus the complexity of each `case` block. It's
+ equivalent to the complexity of the equivalent cascade of `if` statements.
+ * The complexity of a ternary expression (`?:`) is the complexity of the guard condition, plus the
+ complexity of both expressions. It's equivalent to the complexity of the equivalent `if .. else` construct.
+ * The complexity of a `try .. catch` statement is the complexity of the `try` block, plus the complexity of each
+ catch block.
+ * The complexity of a `return` statement is the complexity of the expression (or 1 if there is none).
+ * All other statements have a complexity of 1 and are discarded from the product.
+
+### Code example
+
+```java
+void fun(boolean a, boolean b, boolean c) { // NPath = 6
+
+ // block #0
+
+ if (a) {
+ // block #1
+ } else {
+ // block #2
+ }
+
+ // block #3
+
+ if (b) {
+ // block #4
+ } else if (c) {
+ // block #5
+ }
+
+ // block #6
+}
+```
+After block 0, the control flow can either execute block 1 or 2 before jumping to block 3. From block three, the
+control flow will again have the choice between blocks 4 and 5 before jumping to block 6. The first `if` offers 2
+choices, the second offers 3, so the cyclomatic complexity of this method is 2 + 3 = 5. NPath, however, sees 2 * 3 =
+6 full paths from the beginning to the end.
+
+## Weighted Method Count (WMC)
+
+*Class metric.* Can be computed on classes and enums
+
+### Description
+
+Sum of the statistical complexity of the operations in the class. We use [CYCLO](#cyclomatic-complexity-cyclo) to
+quantify the complexity of an operation \[[Lanza05](#Lanza05)\].
+
+### Versions
+
+WMC uses the same versions as CYCLO, which have the effect of summing that version of CYCLO to calculate the metric.
+
+# References
+
+Lanza05: Lanza, Marinescu; Object-Oriented Metrics in Practice, 2005.
+
+McCabe76: McCabe, A Complexity Measure, in Proceedings of the 2nd ICSE (1976).
+
+Sonarqube: [Sonarqube online documentation.](https://docs.sonarqube.org/display/SONAR/Metric+Definitions)
+
+JavaNcss: [JavaNCSS online documentation.](http://www.kclee.de/clemens/java/javancss/)
\ No newline at end of file
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/DefaultNcssVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/DefaultNcssVisitor.java
index 082e55cea..79da9a5e2 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/DefaultNcssVisitor.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/DefaultNcssVisitor.java
@@ -7,6 +7,7 @@
import org.apache.commons.lang3.mutable.MutableInt;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement;
import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
@@ -220,4 +221,10 @@ public Object visit(ASTInitializer node, Object data) {
return super.visit(node, data);
}
+ @Override
+ public Object visit(ASTAssertStatement node, Object data) {
+ ((MutableInt) data).increment();
+ return super.visit(node, data);
+ }
+
}
diff --git a/pmd-java/src/main/resources/rulesets/java/metrics.xml b/pmd-java/src/main/resources/rulesets/java/metrics.xml
index 422a7e56f..5a35fb5bb 100644
--- a/pmd-java/src/main/resources/rulesets/java/metrics.xml
+++ b/pmd-java/src/main/resources/rulesets/java/metrics.xml
@@ -15,52 +15,47 @@
class="net.sourceforge.pmd.lang.java.metrics.rule.CyclomaticComplexityRule"
metrics="true"
externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#CyclomaticComplexity">
-
-
+
3
@@ -71,24 +66,38 @@ public class Foo { // This has a Cyclomatic Complexity = 12
since="3.9"
class="net.sourceforge.pmd.lang.java.metrics.rule.NcssCountRule"
metrics="true"
- externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#NcssTypeCount">
+ externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#NcssCount">
- This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of lines
- of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm,
- lines of code that are split are counted as one.
+ This rule uses the NCSS (Non-Commenting Source Statements) metric to determine the number of lines
+ of code in a class, method or constructor. NCSS ignores comments, blank lines, and only counts actual
+ statements. For more details on the calculation, see the documentation ofthe[NCSSmetric](/pmd_java_metrics_index.html#non-commenting-source-statements-ncss).
3
@@ -103,41 +112,51 @@ public class Foo extends Bar {
externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#NPathComplexity">
The NPath complexity of a method is the number of acyclic execution paths through that method.
+ While cyclomatic complexity counts the number of decision points in a method, NPath counts the number of
+ full paths from the beginning to the end of the block of the method. That metric grows exponentially, as
+ it multiplies the complexity of statements in the same block. For more details on the calculation, see the
+ documentation of the [NPath metric](/pmd_java_metrics_index.html#npath-complexity-npath).
+
A threshold of 200 is generally considered the point where measures should be taken to reduce
complexity and increase readability.
3
r) {
- doSomething();
- while (f < 5 ) {
- anotherThing();
- f -= 27;
- }
- } else {
- tryThis();
- }
+public class Foo {
+ public static void bar() { // Ncss = 252: reported!
+ boolean a, b = true;
+ try { // 2 * 2 + 2 = 6
+ if (true) { // 2
+ List buz = new ArrayList();
+ }
+
+ for(int i = 0; i < 19; i++) { // * 2
+ List buz = new ArrayList();
+ }
+ } catch(Exception e) {
+ if (true) { // 2
+ e.printStackTrace();
}
}
- if ( r - n > 45) {
- while (doMagic()) {
- findRabbits();
- }
+
+ while (j++ < 20) { // * 2
+ List buz = new ArrayList();
}
- try {
- doSomethingDangerous();
- } catch (Exception ex) {
- makeAmends();
- } finally {
- dontDoItAgain();
+
+ switch(j) { // * 7
+ case 1:
+ case 2: break;
+ case 3: j = 5; break;
+ case 4: if (b && a) { bar(); } break;
+ default: break;
}
+
+ do { // * 3
+ List buz = new ArrayList();
+ } while (a && j++ < 30);
}
}
-
]]>
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/NcssTest.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/NcssTest.xml
index ecf84267f..80c26d932 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/NcssTest.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/NcssTest.xml
@@ -104,6 +104,7 @@
e.printStackTrace();
} catch (ThemAll pokemon) {
pokemon.train();
+ assert pokemon.level > 12;
} finally {
// Do nothing
}
@@ -125,11 +126,11 @@
true
5
- 'com.company.money.Foo' has value 65 highest 20.
+ 'com.company.money.Foo' has value 66 highest 21.
'com.company.money.Foo#Foo()' has value 2.
'com.company.money.Foo#Foo(int)' has value 13.
'com.company.money.Foo#foo()' has value 14.
- 'com.company.money.Foo#main(String)' has value 20.
+ 'com.company.money.Foo#main(String)' has value 21.
@@ -140,11 +141,11 @@
javaNcss
5
- 'com.company.money.Foo' has value 68 highest 20.
+ 'com.company.money.Foo' has value 69 highest 21.
'com.company.money.Foo#Foo()' has value 2.
'com.company.money.Foo#Foo(int)' has value 13.
'com.company.money.Foo#foo()' has value 14.
- 'com.company.money.Foo#main(String)' has value 20.
+ 'com.company.money.Foo#main(String)' has value 21.
diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md
index 4503e587a..5e45ae798 100644
--- a/src/site/markdown/overview/changelog.md
+++ b/src/site/markdown/overview/changelog.md
@@ -157,8 +157,9 @@ Al existing rules have been updated to reflect these changes. If you have custom
* [#524](https://github.com/pmd/pmd/pull/524): \[java] Add support for explicit type arguments with method invocation - [Bendegúz Nagy](https://github.com/WinterGrascph)
* [#525](https://github.com/pmd/pmd/pull/525): \[core] Fix line ending and not ignored files issues - [Matias Comercio](https://github.com/MatiasComercio)
* [#528](https://github.com/pmd/pmd/pull/528): \[core] Fix typo - [Ayoub Kaanich](https://github.com/kayoub5)
+* [#529](https://github.com/pmd/pmd/pull/529): \[java] Abstracted the Java metrics framework - [Clément Fournier](https://github.com/oowekyala)
* [#530](https://github.com/pmd/pmd/pull/530): \[java] Fix issue #527: Lombok getter annotation on enum is not recognized correctly - [Clément Fournier](https://github.com/oowekyala)
* [#535](https://github.com/pmd/pmd/pull/535): \[apex] Fix broken Apex visitor adapter - [Clément Fournier](https://github.com/oowekyala)
-* [#529](https://github.com/pmd/pmd/pull/529): \[java] Abstracted the Java metrics framework - [Clément Fournier](https://github.com/oowekyala)
* [#542](https://github.com/pmd/pmd/pull/542): \[java] Metrics abstraction - [Clément Fournier](https://github.com/oowekyala)
+* [#548](https://github.com/pmd/pmd/pull/548): \[java] Metrics documentation - [Clément Fournier](https://github.com/oowekyala)