forked from phoedos/pmd
[doc] Update rule writing docs (#2511)
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
{% for lang in site.data.xpath_funs.langs %}
|
{% for lang in site.data.xpath_funs.langs %}
|
||||||
|
|
||||||
<!-- Generates the documentation of XPath functions. -->
|
<!-- Generates the documentation of XPath functions from file docs/_data/xpath_funs.yml -->
|
||||||
|
|
||||||
### {{ lang.name }}
|
### {{ lang.name }}
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 168 KiB |
Binary file not shown.
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 159 KiB |
@ -2,7 +2,7 @@
|
|||||||
title: Introduction to writing PMD rules
|
title: Introduction to writing PMD rules
|
||||||
tags: [extending, userdocs, getting_started]
|
tags: [extending, userdocs, getting_started]
|
||||||
summary: "Writing your own PMD rules"
|
summary: "Writing your own PMD rules"
|
||||||
last_updated: February 2020 (6.22.0)
|
last_updated: December 2023 (7.0.0)
|
||||||
permalink: pmd_userdocs_extending_writing_rules_intro.html
|
permalink: pmd_userdocs_extending_writing_rules_intro.html
|
||||||
author: Clément Fournier <clement.fournier76@gmail.com>
|
author: Clément Fournier <clement.fournier76@gmail.com>
|
||||||
---
|
---
|
||||||
@ -14,19 +14,16 @@ team.
|
|||||||
## How rules work: the AST
|
## How rules work: the AST
|
||||||
|
|
||||||
Before running rules, PMD parses the source file into a data structure called an
|
Before running rules, PMD parses the source file into a data structure called an
|
||||||
**abstract syntax tree (AST)**. This tree represents the syntactic structure of the
|
**[abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree)**.
|
||||||
|
This tree represents the syntactic structure of the
|
||||||
code, and encodes syntactic relations between source code elements. For instance,
|
code, and encodes syntactic relations between source code elements. For instance,
|
||||||
in Java, method declarations belong to a class: in the AST, the nodes representing
|
in Java, method declarations belong to a class: in the AST, the nodes representing
|
||||||
method declarations will be descendants of a node representing the declaration of
|
method declarations will be descendants of a node representing the declaration of
|
||||||
their enclosing class. This representation is thus much richer than the original
|
their enclosing class. This representation is thus much richer than the original
|
||||||
source code (which, for a program, is just a chain of characters), or the token
|
source code (which, for a program, is just a chain of characters), or the token
|
||||||
chain produced by a lexer (which is e.g. what Checkstyle works on). For example:
|
chain produced by a lexer. For example:
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<colgroup>
|
|
||||||
<col width="40%" />
|
|
||||||
<col width="70%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="header">
|
<tr class="header">
|
||||||
<th>Sample code (Java)</th>
|
<th>Sample code (Java)</th>
|
||||||
@ -48,11 +45,11 @@ class Foo extends Object {
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
└─ CompilationUnit
|
└─ CompilationUnit
|
||||||
└─ TypeDeclaration
|
└─ ClassOrInterfaceDeclaration "Foo"
|
||||||
└─ ClassOrInterfaceDeclaration "Foo"
|
├─ ModifierList
|
||||||
├─ ExtendsList
|
├─ ExtendsList
|
||||||
│ └─ ClassOrInterfaceType "Object"
|
│ └─ ClassOrInterfaceType "Object"
|
||||||
└─ ClassOrInterfaceBody
|
└─ ClassOrInterfaceBody
|
||||||
```
|
```
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
@ -95,6 +92,8 @@ complicated processing, to which an XPath rule couldn't scale.
|
|||||||
In the end, choosing one strategy or the other depends on the difficulty of what
|
In the end, choosing one strategy or the other depends on the difficulty of what
|
||||||
your rule does. I'd advise to keep to XPath unless you have no other choice.
|
your rule does. I'd advise to keep to XPath unless you have no other choice.
|
||||||
|
|
||||||
|
Note: Despite that fact, the Java rules are written in Java, any language that PMD supports
|
||||||
|
can be analyzed. E.g. you can write a Java rule to analyze Apex source code.
|
||||||
|
|
||||||
## XML rule definition
|
## XML rule definition
|
||||||
|
|
||||||
@ -103,16 +102,18 @@ case for both XPath and Java rules. To do this, the `rule` element is used, but
|
|||||||
instead of mentioning the `ref` attribute, it mentions the `class` attribute,
|
instead of mentioning the `ref` attribute, it mentions the `class` attribute,
|
||||||
with the implementation class of your rule.
|
with the implementation class of your rule.
|
||||||
|
|
||||||
* **For Java rules:** this is the class extending AbstractRule (transitively)
|
* **For Java rules:** this is the concrete class extending AbstractRule (transitively)
|
||||||
* **For XPath rules:** this is `net.sourceforge.pmd.lang.rule.XPathRule`
|
* **For XPath rules:** this is `net.sourceforge.pmd.lang.rule.XPathRule`.
|
||||||
|
* **For XPath rules analyzing XML-based languages:** this is `net.sourceforge.pmd.lang.xml.rule.DomXPathRule`.
|
||||||
|
See [XPath rules in XML](pmd_languages_xml.html#xpath-rules-in-xml) for more info.
|
||||||
|
|
||||||
Example:
|
Example for Java rule:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<rule name="MyJavaRule"
|
<rule name="MyJavaRule"
|
||||||
language="java"
|
language="java"
|
||||||
message="Violation!"
|
message="Violation!"
|
||||||
class="com.me.MyJavaRule" >
|
class="com.me.MyJavaRule">
|
||||||
<description>
|
<description>
|
||||||
Description
|
Description
|
||||||
</description>
|
</description>
|
||||||
@ -120,11 +121,31 @@ Example:
|
|||||||
</rule>
|
</rule>
|
||||||
```
|
```
|
||||||
|
|
||||||
{% include note.html content="In PMD 7, the `language` attribute will be required on all `rule`
|
Example for XPath rule:
|
||||||
elements that declare a new rule. Some base rule classes set the language implicitly in their
|
|
||||||
constructor, and so this is not required in all cases for the rule to work. But this
|
```xml
|
||||||
behavior will be discontinued in PMD 7, so missing `language` attributes are
|
<rule name="MyXPathRule"
|
||||||
reported beginning with PMD 6.27.0 as a forward compatibility warning." %}
|
language="java"
|
||||||
|
message="Violation!"
|
||||||
|
class="net.sourceforge.pmd.lang.rule.XPathRule">
|
||||||
|
<description>
|
||||||
|
Description
|
||||||
|
</description>
|
||||||
|
<priority>3</priority>
|
||||||
|
<properties>
|
||||||
|
<property name="xpath">
|
||||||
|
<value><![CDATA[
|
||||||
|
//ClassOrInterfaceDeclaration
|
||||||
|
]]></value>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
{% include note.html content="Since PMD 7, the `language` attribute is required on all `rule`
|
||||||
|
elements that declare a new rule. In PMD 6, this was optional, as the base rule classes sometimes set
|
||||||
|
the language implicitly in their constructor." %}
|
||||||
|
|
||||||
## Resource index
|
## Resource index
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
title: Writing XPath rules
|
title: Writing XPath rules
|
||||||
tags: [extending, userdocs]
|
tags: [extending, userdocs]
|
||||||
summary: "This page describes XPath rule support in more details"
|
summary: "This page describes XPath rule support in more details"
|
||||||
last_updated: February 2020 (6.22.0)
|
last_updated: December 2023 (7.0.0)
|
||||||
permalink: pmd_userdocs_extending_writing_xpath_rules.html
|
permalink: pmd_userdocs_extending_writing_xpath_rules.html
|
||||||
author: Miguel Griffa <mikkey@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com>
|
author: Miguel Griffa <mikkey@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com>
|
||||||
---
|
---
|
||||||
@ -15,17 +15,19 @@ author: Miguel Griffa <mikkey@users.sourceforge.net>, Clément Fournier <clement
|
|||||||
|
|
||||||
|
|
||||||
This page describes some points of XPath rule support in more details. See
|
This page describes some points of XPath rule support in more details. See
|
||||||
also [the tutorial about how to write an XPath rule](pmd_userdocs_extending_your_first_rule.html).
|
also [the tutorial about how to write a first (XPath) rule](pmd_userdocs_extending_your_first_rule.html).
|
||||||
|
|
||||||
<!-- Later we can document the specific subset of XPath features our wrappers support -->
|
<!-- Later we can document the specific subset of XPath features our wrappers support -->
|
||||||
|
|
||||||
## XPath version
|
## XPath version
|
||||||
|
|
||||||
PMD uses XPath 3.1 for its XPath rules since PMD 7. Before then, the default version was XPath 1.0, with opt-in support for XPath 2.0.
|
PMD uses XPath 3.1 for its XPath rules since PMD 7. Before then, the default version was XPath 1.0,
|
||||||
|
with opt-in support for XPath 2.0.
|
||||||
|
|
||||||
See [the Saxonica documentation](https://www.saxonica.com/html/documentation/expressions/xpath31new.html) for an introduction to new features in XPath 3.1.
|
See [the Saxonica documentation](https://www.saxonica.com/html/documentation/expressions/xpath31new.html)
|
||||||
|
for an introduction to new features in XPath 3.1.
|
||||||
|
|
||||||
The property `version` of XPathRule is deprecated and will be removed.
|
The property `version` of {% jdoc core::lang.rule.XPathRule %} is deprecated and will be removed.
|
||||||
|
|
||||||
|
|
||||||
## DOM representation of ASTs
|
## DOM representation of ASTs
|
||||||
@ -38,11 +40,13 @@ defined on. Concretely, this means:
|
|||||||
* Some Java getters are exposed as XML attributes on those elements
|
* Some Java getters are exposed as XML attributes on those elements
|
||||||
* This means, that documentation for attributes can be found in our Javadocs. For
|
* This means, that documentation for attributes can be found in our Javadocs. For
|
||||||
example, the attribute `@SimpleName` of the Java node `EnumDeclaration` is backed
|
example, the attribute `@SimpleName` of the Java node `EnumDeclaration` is backed
|
||||||
by the Java getter {% jdoc java::lang.java.ast.ASTAnyTypeDeclaration#getSimpleName() %}.
|
by the Java getter {% jdoc java::lang.java.ast.AbstractAnyTypeDeclaration#getSimpleName() %}.
|
||||||
|
|
||||||
### Value conversion
|
### Value conversion
|
||||||
|
|
||||||
To represent attributes, we must map Java values to [XPath Data Model (XDM)](https://www.w3.org/TR/xpath-datamodel/) values. In the following table we refer to the type conversion function as `conv`, a function from Java types to XDM types.
|
To represent attributes, we must map Java values to [XPath Data Model (XDM)](https://www.w3.org/TR/xpath-datamodel/)
|
||||||
|
values. In the following table we refer to the type conversion function as `conv`, a function from Java types
|
||||||
|
to XDM types.
|
||||||
|
|
||||||
| Java type `T` | XSD type `conv(T)` |
|
| Java type `T` | XSD type `conv(T)` |
|
||||||
|---------------|---------------------------------------|
|
|---------------|---------------------------------------|
|
||||||
@ -73,14 +77,9 @@ The same `conv` function is used to translate rule property values to XDM values
|
|||||||
PMD provides some language-specific XPath functions to access semantic
|
PMD provides some language-specific XPath functions to access semantic
|
||||||
information from the AST.
|
information from the AST.
|
||||||
|
|
||||||
On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned.
|
The namespace of custom PMD functions must be explicitly mentioned.
|
||||||
|
|
||||||
{% render %}
|
{% render %}
|
||||||
{% include custom/xpath_fun_doc.html %}
|
{% include custom/xpath_fun_doc.html %}
|
||||||
{% endrender %}
|
{% endrender %}
|
||||||
|
|
||||||
{% include note.html content='There is also a `typeOf` function which is
|
|
||||||
deprecated and whose usages should be replaced with uses of `typeIs` or
|
|
||||||
`typeIsExactly`. That one will be removed with PMD 7.0.0.' %}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: Your first rule XPath
|
title: Your first rule
|
||||||
tags: [extending, userdocs]
|
tags: [extending, userdocs]
|
||||||
summary: "Introduction to rule writing through an example."
|
summary: "Introduction to rule writing through an example for a XPath rule."
|
||||||
last_updated: February 2020 (6.22.0)
|
last_updated: December 2023 (7.0.0)
|
||||||
permalink: pmd_userdocs_extending_your_first_rule.html
|
permalink: pmd_userdocs_extending_your_first_rule.html
|
||||||
author: Miguel Griffa <mikkey@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com>
|
author: Miguel Griffa <mikkey@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com>
|
||||||
---
|
---
|
||||||
@ -11,7 +11,7 @@ This page is a gentle introduction to rule writing, and the Rule Designer.
|
|||||||
|
|
||||||
Using the designer is useful both to write Java
|
Using the designer is useful both to write Java
|
||||||
rules and XPath rules, but it's more specifically geared towards XPath rules.
|
rules and XPath rules, but it's more specifically geared towards XPath rules.
|
||||||
This page uses a simple XPath rule to illustrate the common workflow. We assume
|
This page uses a **simple XPath rule** to illustrate the common workflow. We assume
|
||||||
here that you already know what XPath is and how to read basic XPath queries. W3C
|
here that you already know what XPath is and how to read basic XPath queries. W3C
|
||||||
has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if
|
has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if
|
||||||
you don't (in the context of XML only), and [the Saxon documentation](https://www.saxonica.com/documentation/index.html#!expressions)
|
you don't (in the context of XML only), and [the Saxon documentation](https://www.saxonica.com/documentation/index.html#!expressions)
|
||||||
@ -35,11 +35,11 @@ The interface looks like the following:
|
|||||||
{% include image.html file="userdocs/designer-overview-with-nums.png" alt="Designer overview" %}
|
{% include image.html file="userdocs/designer-overview-with-nums.png" alt="Designer overview" %}
|
||||||
|
|
||||||
The zone (2) is the **main editor**. When you write a code snippet in the
|
The zone (2) is the **main editor**. When you write a code snippet in the
|
||||||
code area to the left, you'll see that the tree to the right will be updated
|
code area to the left, you'll see that the tree to the right will be updated
|
||||||
automatically: it's the AST of the code.
|
automatically: it's the AST of the code.
|
||||||
Note that the code snippet must be a syntactically valid compilation unit for the
|
Note that the code snippet must be a syntactically valid compilation unit for the
|
||||||
language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level
|
language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level
|
||||||
type declaration.
|
type declaration.
|
||||||
|
|
||||||
If you select a node in the AST, its specific properties will also be displayed
|
If you select a node in the AST, its specific properties will also be displayed
|
||||||
in the panel (1): they're the XPath attributes of the node. More on that later.
|
in the panel (1): they're the XPath attributes of the node. More on that later.
|
||||||
@ -57,7 +57,7 @@ The basic development process is straightforward:
|
|||||||
2. Examine the AST and determine what node the violation should be reported on
|
2. Examine the AST and determine what node the violation should be reported on
|
||||||
3. Write an XPath expression matching that node in the XPath editor
|
3. Write an XPath expression matching that node in the XPath editor
|
||||||
4. Refine the XPath expression iteratively using different code snippets, so that
|
4. Refine the XPath expression iteratively using different code snippets, so that
|
||||||
it matches violation cases, but no other node
|
it matches violation cases, but no other nodes
|
||||||
5. Export your XPath expression to an XML rule element, and place it in your ruleset
|
5. Export your XPath expression to an XML rule element, and place it in your ruleset
|
||||||
|
|
||||||
Each time you test your rule against a different snippet, it's a good idea to
|
Each time you test your rule against a different snippet, it's a good idea to
|
||||||
@ -84,10 +84,10 @@ public class KeepingItSerious {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId
|
Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId
|
||||||
descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt
|
descendant, whose `Name` XPath attribute is exactly `bill`. You thus write your first attempt
|
||||||
in the XPath editor:
|
in the XPath editor:
|
||||||
```xpath
|
```xpath
|
||||||
//VariableDeclaratorId[@Image = "bill"]
|
//VariableDeclaratorId[@Name = "bill"]
|
||||||
```
|
```
|
||||||
|
|
||||||
You can see the XPath result list is updated with the variable declarator.
|
You can see the XPath result list is updated with the variable declarator.
|
||||||
@ -112,13 +112,14 @@ based on your examination of the Type node of the field and local variable
|
|||||||
declaration nodes.
|
declaration nodes.
|
||||||
|
|
||||||
```xpath
|
```xpath
|
||||||
//VariableDeclaratorId[@Image = "bill" and ../../Type[@TypeImage = "short"]]
|
//VariableDeclaratorId[@Image = "bill"][../../PrimitiveType[@Kind = "short"]]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Exporting to XML
|
### Exporting to XML
|
||||||
|
|
||||||
You estimate that your rule is now production ready, and you'd like to use it in your ruleset.
|
You estimate that your rule is now production ready, and you'd like to use it in your ruleset.
|
||||||
The `File > Export XPath to rule...` allows you to do that in a few clicks: just enter some
|
The second button in the toolbar above the XPath editor (Tooltip: `Export XPath to rule...`)
|
||||||
|
allows you to do that in a few clicks: just enter some
|
||||||
additional metadata for your rule, and the popup will generate an XML element that you can
|
additional metadata for your rule, and the popup will generate an XML element that you can
|
||||||
copy-paste into your ruleset XML. The resulting element looks like so:
|
copy-paste into your ruleset XML. The resulting element looks like so:
|
||||||
|
|
||||||
@ -126,16 +127,16 @@ copy-paste into your ruleset XML. The resulting element looks like so:
|
|||||||
<rule name="DontCallBossShort"
|
<rule name="DontCallBossShort"
|
||||||
language="java"
|
language="java"
|
||||||
message="Boss wants to talk to you."
|
message="Boss wants to talk to you."
|
||||||
class="net.sourceforge.pmd.lang.rule.XPathRule" >
|
class="net.sourceforge.pmd.lang.rule.XPathRule">
|
||||||
<description>
|
<description>
|
||||||
TODO
|
TODO
|
||||||
</description>
|
</description>
|
||||||
<priority>3</priority>
|
<priority>3</priority>
|
||||||
<properties>
|
<properties>
|
||||||
<property name="xpath">
|
<property name="xpath">
|
||||||
<value>
|
<value>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
//VariableDeclaratorId[../../Type[@TypeImage="short"] and @Image = "bill"]
|
//VariableDeclaratorId[@Image = "bill"][../../PrimitiveType[@Kind = "short"]]
|
||||||
]]>
|
]]>
|
||||||
</value>
|
</value>
|
||||||
</property>
|
</property>
|
||||||
|
@ -83,6 +83,10 @@ Once you have reviewed your ruleset(s), you can switch to PMD 7.
|
|||||||
Ideally, you have written good tests already for your custom rules - see [Testing your rules](pmd_userdocs_extending_testing.html).
|
Ideally, you have written good tests already for your custom rules - see [Testing your rules](pmd_userdocs_extending_testing.html).
|
||||||
This helps to identify problems early on.
|
This helps to identify problems early on.
|
||||||
|
|
||||||
|
#### Ruleset XML
|
||||||
|
The `<rule>` tag, that defines your custom rule, is required to have a `language` attribute now. This was always the
|
||||||
|
case for XPath rules, but is now a requirement for Java rules.
|
||||||
|
|
||||||
#### XPath rules
|
#### XPath rules
|
||||||
If you have **XPath based** rules, the first step will be to migrate to XPath 2.0 and then to XPath 3.1.
|
If you have **XPath based** rules, the first step will be to migrate to XPath 2.0 and then to XPath 3.1.
|
||||||
XPath 2.0 is available in PMD 6 already and can be used right away. PMD 7 will use by default XPath 3.1 and
|
XPath 2.0 is available in PMD 6 already and can be used right away. PMD 7 will use by default XPath 3.1 and
|
||||||
@ -93,6 +97,12 @@ After you have migrated your XPath rules to XPath 2.0, remove the "version" prop
|
|||||||
with PMD 7. PMD 7 by default uses XPath 3.1.
|
with PMD 7. PMD 7 by default uses XPath 3.1.
|
||||||
See below [XPath](#xpath-migrating-from-10-to-20) for details.
|
See below [XPath](#xpath-migrating-from-10-to-20) for details.
|
||||||
|
|
||||||
|
Additional infos:
|
||||||
|
* The custom XPath function `typeOf` has been removed (deprecated since 6.4.0).
|
||||||
|
Use the function `pmd-java:typeIs` or `pmd-java:typeIsExactly` instead.
|
||||||
|
See [PMD extension functions](pmd_userdocs_extending_writing_xpath_rules.html#pmd-extension-functions) for available
|
||||||
|
functions.
|
||||||
|
|
||||||
#### Java rules
|
#### Java rules
|
||||||
If you have **Java based rules**, and you are using rulechain, this works a bit different now. The RuleChain API
|
If you have **Java based rules**, and you are using rulechain, this works a bit different now. The RuleChain API
|
||||||
has changed, see [[core] Simplify the rulechain (#2490)](https://github.com/pmd/pmd/pull/2490) for the full details.
|
has changed, see [[core] Simplify the rulechain (#2490)](https://github.com/pmd/pmd/pull/2490) for the full details.
|
||||||
|
Reference in New Issue
Block a user