[doc] Update rule writing docs (#2511)

This commit is contained in:
Andreas Dangel 2023-12-07 10:42:40 +01:00
parent c6d55ca059
commit add430b038
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
7 changed files with 84 additions and 53 deletions

View File

@ -1,6 +1,6 @@
{% 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 }}

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

View File

@ -2,7 +2,7 @@
title: Introduction to writing PMD rules
tags: [extending, userdocs, getting_started]
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
author: Clément Fournier <clement.fournier76@gmail.com>
---
@ -14,19 +14,16 @@ team.
## How rules work: the AST
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,
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
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
chain produced by a lexer (which is e.g. what Checkstyle works on). For example:
chain produced by a lexer. For example:
<table>
<colgroup>
<col width="40%" />
<col width="70%" />
</colgroup>
<thead>
<tr class="header">
<th>Sample code (Java)</th>
@ -48,11 +45,11 @@ class Foo extends Object {
```java
└─ CompilationUnit
└─ TypeDeclaration
└─ ClassOrInterfaceDeclaration "Foo"
├─ ExtendsList
│ └─ ClassOrInterfaceType "Object"
└─ ClassOrInterfaceBody
└─ ClassOrInterfaceDeclaration "Foo"
├─ ModifierList
├─ ExtendsList
│ └─ ClassOrInterfaceType "Object"
└─ ClassOrInterfaceBody
```
</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
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
@ -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,
with the implementation class of your rule.
* **For Java rules:** this is the class extending AbstractRule (transitively)
* **For XPath rules:** this is `net.sourceforge.pmd.lang.rule.XPathRule`
* **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 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
<rule name="MyJavaRule"
language="java"
message="Violation!"
class="com.me.MyJavaRule" >
class="com.me.MyJavaRule">
<description>
Description
</description>
@ -120,11 +121,31 @@ Example:
</rule>
```
{% include note.html content="In PMD 7, the `language` attribute will be required on all `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
behavior will be discontinued in PMD 7, so missing `language` attributes are
reported beginning with PMD 6.27.0 as a forward compatibility warning." %}
Example for XPath rule:
```xml
<rule name="MyXPathRule"
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

View File

@ -2,7 +2,7 @@
title: Writing XPath rules
tags: [extending, userdocs]
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
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
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 -->
## 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
@ -38,11 +40,13 @@ defined on. Concretely, this means:
* Some Java getters are exposed as XML attributes on those elements
* This means, that documentation for attributes can be found in our Javadocs. For
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
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)` |
|---------------|---------------------------------------|
@ -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
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 %}
{% include custom/xpath_fun_doc.html %}
{% 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.' %}

View File

@ -1,8 +1,8 @@
---
title: Your first rule XPath
title: Your first rule
tags: [extending, userdocs]
summary: "Introduction to rule writing through an example."
last_updated: February 2020 (6.22.0)
summary: "Introduction to rule writing through an example for a XPath rule."
last_updated: December 2023 (7.0.0)
permalink: pmd_userdocs_extending_your_first_rule.html
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
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
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)
@ -35,11 +35,11 @@ The interface looks like the following:
{% 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
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.
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
type declaration.
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.
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
type declaration.
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.
@ -57,7 +57,7 @@ The basic development process is straightforward:
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
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
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
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:
```xpath
//VariableDeclaratorId[@Image = "bill"]
//VariableDeclaratorId[@Name = "bill"]
```
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.
```xpath
//VariableDeclaratorId[@Image = "bill" and ../../Type[@TypeImage = "short"]]
//VariableDeclaratorId[@Image = "bill"][../../PrimitiveType[@Kind = "short"]]
```
### Exporting to XML
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
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"
language="java"
message="Boss wants to talk to you."
class="net.sourceforge.pmd.lang.rule.XPathRule" >
class="net.sourceforge.pmd.lang.rule.XPathRule">
<description>
TODO
TODO
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//VariableDeclaratorId[../../Type[@TypeImage="short"] and @Image = "bill"]
<![CDATA[
//VariableDeclaratorId[@Image = "bill"][../../PrimitiveType[@Kind = "short"]]
]]>
</value>
</property>

View File

@ -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).
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
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
@ -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.
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
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.