Added Customizing Pages
This commit is contained in:
@@ -44,6 +44,26 @@ entries:
|
||||
url: /mydoc_support.html
|
||||
output: web, pdf
|
||||
|
||||
- title: Customizing PMD
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
|
||||
- title: How PMD Works
|
||||
url: /how_pmd_works.html
|
||||
output: web, pdf
|
||||
|
||||
- title: Writing a Rule
|
||||
url: /writing_pmd_rules.html
|
||||
output: web, pdf
|
||||
|
||||
- title: Writing XPath Rules
|
||||
url: /writing_xpath_rules.html
|
||||
output: web, pdf
|
||||
|
||||
- title: Making Rulesets
|
||||
url: /making_rulesets.html
|
||||
output: web, pdf
|
||||
|
||||
- title: Release Notes
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
|
@@ -10,4 +10,5 @@ allowed-tags:
|
||||
- collaboration
|
||||
- news
|
||||
- troubleshooting
|
||||
- mobile
|
||||
- mobile
|
||||
- customizing
|
19
_includes/custom/series_customizing.html
Normal file
19
_includes/custom/series_customizing.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="seriesContext">
|
||||
<div class="btn-group">
|
||||
<button type="button" data-toggle="dropdown" class="btn btn-primary dropdown-toggle">Customizing PMD<span class="caret"></span></button>
|
||||
<ol class="dropdown-menu">
|
||||
{% assign pages = site.pages | sort:"weight" %}
|
||||
{% for p in pages %}
|
||||
{% if p.series == "Customizing PMD" %}
|
||||
{% if p.url == page.url %}
|
||||
<li class="active"> → {{p.weight}}. {{p.short_title}}</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{{p.url | remove: "/"}}">{{p.weight}}. {{p.short_title}}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
10
_includes/custom/series_customizing_next.html
Normal file
10
_includes/custom/series_customizing_next.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<p>{% assign series_pages = site.tags.series_customizing %}
|
||||
{% for p in pages %}
|
||||
{% if p.series == "Customizing PMD" %}
|
||||
{% assign nextTopic = page.weight | plus: "1" %}
|
||||
{% if p.weight == nextTopic %}
|
||||
<a href="{{p.url | remove: "/"}}"><button type="button" class="btn btn-primary">Next: {{p.weight}} {{p.short_title}}</button></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
10
_includes/custom/series_customizing_previous.html
Normal file
10
_includes/custom/series_customizing_previous.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<p>{% assign series_pages = site.tags.series_customizing %}
|
||||
{% for p in pages %}
|
||||
{% if p.series == "Customizing PMD" %}
|
||||
{% assign prevTopic = page.weight | minus: "1" %}
|
||||
{% if p.weight == prevTopic %}
|
||||
<a href="{{p.url | remove: "/"}}"><button type="button" class="btn btn-primary">Previous: {{p.weight}} {{p.short_title}}</button></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
@@ -11,7 +11,7 @@ folder: mydoc
|
||||
|
||||
## System requirements
|
||||
|
||||
>**Note:** PMD and CPD need at least a java7 runtime environment. For analyzing Salesforce.com Apex source code, you’ll need a java8 runtime environment.
|
||||
{% include note.html content="PMD and CPD need at least a java7 runtime environment. For analyzing Salesforce.com Apex source code, you’ll need a java8 runtime environment." %}
|
||||
|
||||
## New Supported Languages
|
||||
|
||||
|
33
pages/customizing/how_pmd_works.md
Normal file
33
pages/customizing/how_pmd_works.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: PMD How it Works
|
||||
short_title: How it Works
|
||||
tags: [customizing]
|
||||
summary: How PMD Works
|
||||
series: Customizing PMD
|
||||
weight: 1
|
||||
last_updated: July 3, 2016
|
||||
sidebar: mydoc_sidebar
|
||||
permalink: how_pmd_works.html
|
||||
folder: mydoc
|
||||
---
|
||||
|
||||
{% include custom/series_customizing.html %}
|
||||
|
||||
# How it works
|
||||
|
||||
PMD checks source code against rules and produces a report. Like this:
|
||||
|
||||
* Something passes a file name and a RuleSet into PMD
|
||||
* PMD hands an InputStream to the file off to a JavaCC-generated parser
|
||||
* PMD gets a reference to an Abstract Syntax Tree back from the parser
|
||||
* PMD hands the AST off to the symbol table layer which builds scopes, finds declarations, and find usages.
|
||||
* If any rules need data flow analysis, PMD hands the AST over to the DFA layer for building control flow graphs and data flow nodes.
|
||||
* Each Rule in the RuleSet gets to traverse the AST and check for problems. The rules can also poke around the symbol table and DFA nodes.
|
||||
* The Report is now filled with RuleViolations, and those get printed out in XML or HTML or whatever
|
||||
|
||||
Not much detail here… if you think this document can be improved, please post [here](http://sourceforge.net/p/pmd/discussion/188192) and let us know how. Thanks!
|
||||
|
||||
{% include custom/series_customizing_previous.html %}
|
||||
{% include custom/series_customizing_next.html %}
|
||||
|
||||
{% include links.html %}
|
145
pages/customizing/making_rulesets.md
Normal file
145
pages/customizing/making_rulesets.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
title: PMD Making Rulesets
|
||||
short_title: Making Custom Rulesets
|
||||
tags: [customizing]
|
||||
summary: Making Custom Rulesets for PMD
|
||||
series: Customizing PMD
|
||||
weight: 4
|
||||
last_updated: July 3, 2016
|
||||
sidebar: mydoc_sidebar
|
||||
permalink: making_rulesets.html
|
||||
folder: mydoc
|
||||
---
|
||||
|
||||
{% include custom/series_customizing.html %}
|
||||
|
||||
# How to make a new rule set
|
||||
|
||||
Say you want to pick specific rules from various rule sets and customize them. You can do this by making your own rule set.
|
||||
|
||||
## Create a new ruleset.xml file
|
||||
|
||||
Use one of the current rulesets as an example. Copy and paste it into your new file, delete all the old rules from it, and change the name and description. Like this:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom ruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
<description>
|
||||
This ruleset checks my code for bad stuff
|
||||
</description>
|
||||
</ruleset>
|
||||
````
|
||||
|
||||
## Add some rule references to it
|
||||
|
||||
After you add these references it’ll look something like this:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom ruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
This ruleset checks my code for bad stuff
|
||||
</description>
|
||||
|
||||
<!-- We'll use the entire 'strings' ruleset -->
|
||||
<rule ref="rulesets/java/strings.xml"/>
|
||||
|
||||
<!-- Here's some rules we'll specify one at a time -->
|
||||
<rule ref="rulesets/java/unusedcode.xml/UnusedLocalVariable"/>
|
||||
<rule ref="rulesets/java/unusedcode.xml/UnusedPrivateField"/>
|
||||
<rule ref="rulesets/java/imports.xml/DuplicateImports"/>
|
||||
<rule ref="rulesets/java/basic.xml/UnnecessaryConversionTemporary"/>
|
||||
|
||||
<!-- We want to customize this rule a bit, change the message and raise the priority -->
|
||||
<rule
|
||||
ref="rulesets/java/basic.xml/EmptyCatchBlock"
|
||||
message="Must handle exceptions">
|
||||
<priority>2</priority>
|
||||
</rule>
|
||||
|
||||
<!-- Now we'll customize a rule's property value -->
|
||||
<rule ref="rulesets/java/codesize.xml/CyclomaticComplexity">
|
||||
<properties>
|
||||
<property name="reportLevel" value="5"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- We want everything from braces.xml except WhileLoopsMustUseBraces -->
|
||||
<rule ref="rulesets/java/braces.xml">
|
||||
<exclude name="WhileLoopsMustUseBraces"/>
|
||||
</rule>
|
||||
</ruleset>
|
||||
```
|
||||
|
||||
>Notice that you can customize individual referenced rules. Everything but the class of the rule can be overridden in your custom ruleset.
|
||||
|
||||
## Excluding rules from a ruleset
|
||||
|
||||
You can also make a custom ruleset that excludes rules, like this:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="mybraces"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
<description>Just the braces rules I like</description>
|
||||
<rule ref="rulesets/java/braces.xml">
|
||||
<exclude name="WhileLoopsMustUseBraces"/>
|
||||
<exclude name="IfElseStmtsMustUseBraces"/>
|
||||
</rule>
|
||||
</ruleset>
|
||||
```
|
||||
|
||||
## Excluding files from a ruleset
|
||||
|
||||
You can also exclude certain files from being processed by a ruleset using exclude patterns, with an optional overriding include pattern. A file will be excluded from processing when there is a matching exclude pattern, but no matching include pattern. Path separators in the source file path are normalized to be the ‘/’ character, so the same ruleset can be used on multiple platforms transparently. Additionally, this exclude/include technique works regardless of how PMD is used (e.g. command line, IDE, Ant), making it easier to keep application of your PMD rules consistent throughout your environment. Here is an example:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="myruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
<description>My ruleset</description>
|
||||
<exclude-pattern>.*/some/package/.*</exclude-pattern>
|
||||
<exclude-pattern>.*/some/other/package/FunkyClassNamePrefix.*</exclude-pattern>
|
||||
<include-pattern>.*/some/package/ButNotThisClass.*</include-pattern>
|
||||
<rule>...
|
||||
</ruleset>
|
||||
```
|
||||
|
||||
## Reference it in your Ant task
|
||||
|
||||
You can specify the full path to your custom ruleset name alongside of the built-in PMD rulesets - like this:
|
||||
|
||||
```xml
|
||||
<pmd rulesetfiles="/home/tom/data/pmd/pmd/rulesets/java/design.xml,rulesets/java/unusedcode.xml">
|
||||
<formatter type="xml" toFile="foo.xml"/>
|
||||
<fileset dir="/home/tom/data/pmd/pmd/src">
|
||||
<include name="**/*.java"/>
|
||||
</fileset>
|
||||
</pmd>
|
||||
```
|
||||
|
||||
## To see it in your IDE, add it to rulesets/rulesets.properties
|
||||
|
||||
At least, that’s the way some of the IDE plugins do it. Some have other ways of adding custom rulesets.
|
||||
|
||||
## Send us feedback
|
||||
|
||||
If you have suggestions on clarifying this document, please post them to [the forum](http://sourceforge.net/p/pmd/discussion/188192). Thanks!
|
||||
|
||||
Finally, for many more details on building custom rulesets, pick up [PMD Applied](http://pmdapplied.com/)!
|
||||
|
||||
{% include custom/series_customizing_previous.html %}
|
||||
{% include custom/series_customizing_next.html %}
|
||||
|
||||
{% include links.html %}
|
380
pages/customizing/writing_pmd_rules.md
Normal file
380
pages/customizing/writing_pmd_rules.md
Normal file
File diff suppressed because it is too large
Load Diff
161
pages/customizing/writing_xpath_rules.md
Normal file
161
pages/customizing/writing_xpath_rules.md
Normal file
@@ -0,0 +1,161 @@
|
||||
---
|
||||
title: PMD Writing XPath Rules
|
||||
short_title: Writing XPath Rules
|
||||
tags: [customizing]
|
||||
summary: "Writing XPath rules for PMD"
|
||||
series: "Customizing PMD"
|
||||
weight: 3
|
||||
last_updated: July 3, 2016
|
||||
sidebar: mydoc_sidebar
|
||||
permalink: writing_xpath_rules.html
|
||||
folder: mydoc
|
||||
---
|
||||
|
||||
{% include custom/series_customizing.html %}
|
||||
|
||||
# XPath Rule tutorial
|
||||
|
||||
Writing PMD rules with XPath can be a bit easier than writing rules with Java code. Here’s an introduction on how to do that.
|
||||
|
||||
## Introduction
|
||||
|
||||
PMD provides a very handy method for writing rules by writing an XPath query. When the XPath query finds a match, a violation is added to the report. This document focuses on XPath rules. You can go [here](howtowritearule.html) for more information about writing a rule.
|
||||
|
||||
## What is the Abstract Syntax Tree (AST)?
|
||||
|
||||
From [FOLDOC](http://foldoc.org/abstract+syntax+tree) an AST is
|
||||
|
||||
> A data structure representing something which has been parsed, often used as a compiler or interpreter’s internal representation of a program while it is being optimised and from which code generation is performed.
|
||||
|
||||
In our context, this means that we basically have a tree representation of the Java source file. This tree can viewed as a structured document - just like XML. And since it’s conceptually similar to XML, it can be queried with XPath to find a pattern.
|
||||
|
||||
## Using Designer
|
||||
|
||||
PMD comes with a handy tool that you will love if you want to write an XPath rule. Designer, runnable from a script in `bin/`, is a very simple and useful utility for writing rules.
|
||||
|
||||
The basic steps involved in writing XPath rules are these:
|
||||
|
||||
1. Write a simple Java example source snippet in Designer
|
||||
2. See the AST for the class you wrote
|
||||
3. Write an XPath expression that matches the violation you are searching
|
||||
4. Modify the Java class and go back to previous step to refine the XPath expression
|
||||
|
||||
## Simple XPath expressions
|
||||
|
||||
This section provides hands-on examples of XPath queries over the AST. You will probably find this section more useful if you follow it with Designer and copy/paste the examples.
|
||||
|
||||
Copy the following Java source code to Designer:
|
||||
|
||||
```java
|
||||
public class a {
|
||||
int fOne;
|
||||
int fTwo;
|
||||
|
||||
private void run() {
|
||||
int one;
|
||||
int two;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let’s assume you want to match something on class variable names. You see in the ASTVviewer that VariableDeclaratorId contains the variable name - in XML terms, the name is in the `@Image` attribute. So you try an XPath expression as follows:
|
||||
|
||||
`//VariableDeclaratorId`
|
||||
|
||||
If you try this expression you’ll see that variables declared in methods are also matched. A more precise expression for matching field declarations is, well, using the FieldDeclaration node. This expression matches only the two fields declared in the class:
|
||||
|
||||
`//FieldDeclaration`
|
||||
|
||||
In a similar way, you can match only local variables with this expression
|
||||
|
||||
`//LocalVariableDeclaration`
|
||||
|
||||
With local variables we need to be more careful. Consider the following class:
|
||||
|
||||
```java
|
||||
public class a {
|
||||
private void run() {
|
||||
final int one;
|
||||
int two;
|
||||
|
||||
{
|
||||
int a;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Local variable declarations will match ‘a’, since it is a perfectly legal Java local variable. Now, a more interesting expression is to match variables declared in a method, and not on an internal block, nor in the class. Maybe you’ll start with an expression like this:
|
||||
|
||||
`//MethodDeclaration//LocalVariableDeclaration`
|
||||
|
||||
You’ll quickly see that all three local variables are matched. A possible solution for this is to request that the parent of the local variable declaration is the MethodDeclaration node:
|
||||
|
||||
`//LocalVariableDeclaration[name(../../..) = 'MethodDeclaration']`
|
||||
|
||||
## Matching variables by name
|
||||
|
||||
Let’s consider that we are writing rules for logger. Let’s assume we use the Java logging API and we want to find all classes that have more than one logger. The following expression returns all variable declarations whose type is ‘Logger’.
|
||||
|
||||
`//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']]`
|
||||
|
||||
Finding a class with more than one logger is quite easy now. This expression matches the classes we are looking for.
|
||||
|
||||
```xpath
|
||||
TypeDeclaration[count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']])>1
|
||||
```
|
||||
|
||||
But let’s refine this expression a little bit more. Consider the following class:
|
||||
|
||||
```java
|
||||
public class a {
|
||||
Logger log = null;
|
||||
Logger log = null;
|
||||
int b;
|
||||
|
||||
void myMethod() {
|
||||
Logger log = null;
|
||||
int a;
|
||||
}
|
||||
class c {
|
||||
Logger a;
|
||||
Logger a;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this class we will only be matching one violation, when we probably would have wanted to produce two violations (one for each class). The following refined expression matches classes that contain more than one logger.
|
||||
|
||||
```xpath
|
||||
//ClassOrInterfaceBodyDeclaration[count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']])>1]
|
||||
```
|
||||
|
||||
Let’s assume we have a Factory class, that could be always declared final. We’ll search an xpath expression that matches all declarations of Factory and reports a violation if it is not declared final. Consider the following class:
|
||||
|
||||
```java
|
||||
public class a {
|
||||
Factory f1;
|
||||
|
||||
void myMethod() {
|
||||
Factory f2;
|
||||
int a;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following expression does the magic we need:
|
||||
|
||||
```xpath
|
||||
//VariableDeclarator
|
||||
[../Type/ReferenceType/ClassOrInterfaceType
|
||||
[@Image = 'Factory'] and ..[@Final='false']]
|
||||
```
|
||||
|
||||
We recommend at this point that you experiment with Designer putting the final modifier to the Factory and verifying that the results produced are those expected.
|
||||
|
||||
Finally, for many more details on writing XPath rules, pick up [PMD Applied](http://pmdapplied.com/)!
|
||||
|
||||
{% include custom/series_customizing_next.html %}
|
||||
{% include custom/series_customizing_previous.html %}
|
||||
|
||||
{% include links.html %}
|
Reference in New Issue
Block a user