I spent about 4 hours on this but XPath proved to be very painful to work with when developing fairly original custom rules.
For one part of my problem, I need PMD XPath to be able to distinguish between the following lines: int var = this.nocall; int var = nocall;
From AST, I see that PrimaryPrefix:this But I am unable to select the first statement with //PrimaryPrefix['this'] or //PrimaryExpression/PrimaryPrefix['this]] or //PrimaryPrefix[@image='this']
I wonder if anyone has a hint on how to retrieve all the expression with 'this.' in assignment part through XPath.
Example code trying to parse:
class testRuleOne {
private int nocall;
public void myMethod() {
int var = this.nocall;
var = this.getNoCall();
}
}
Here's the raw XML of AST:
<MethodDeclaration Abstract="false" BeginColumn="16" BeginLine="3" EndColumn="9" EndLine="6" Final="false" Image="" InterfaceMember="false" Label="" MethodName="myMethod" Modifiers="1" Native="false" PackagePrivate="false" Private="false" Protected="false" Public="true" Static="false" Strictfp="false" Synchronized="false" SyntacticallyAbstract="false" SyntacticallyPublic="true" Transient="false" Void="true" Volatile="false">
<ResultType BeginColumn="16" BeginLine="3" EndColumn="19" EndLine="3" Image="" Label="" Void="true" returnsArray="false"/>
<MethodDeclarator BeginColumn="21" BeginLine="3" EndColumn="30" EndLine="3" Image="myMethod" Label="" ParameterCount="0">
<FormalParameters BeginColumn="29" BeginLine="3" EndColumn="30" EndLine="3" Image="" Label="" ParameterCount="0"/>
</MethodDeclarator>
<Block BeginColumn="32" BeginLine="3" EndColumn="9" EndLine="6" Image="" Label="" containsComment="false">
<BlockStatement Allocation="false" BeginColumn="17" BeginLine="4" EndColumn="38" EndLine="4" Image="" Label="">
<LocalVariableDeclaration Abstract="false" Array="false" ArrayDepth="0" BeginColumn="17" BeginLine="4" EndColumn="37" EndLine="4" Final="false" Image="" Label="" Modifiers="0" Native="false" PackagePrivate="true" Private="false" Protected="false" Public="false" Static="false" Strictfp="false" Synchronized="false" Transient="false" VariableName="var" Volatile="false">
<Type Array="false" ArrayDepth="0" BeginColumn="17" BeginLine="4" EndColumn="19" EndLine="4" Image="" Label="" TypeImage="int">
<PrimitiveType Array="false" ArrayDepth="0" BeginColumn="17" BeginLine="4" Boolean="false" EndColumn="19" EndLine="4" Image="int" Label=""/>
</Type>
<VariableDeclarator BeginColumn="21" BeginLine="4" EndColumn="37" EndLine="4" Image="" Label="">
<VariableDeclaratorId Array="false" ArrayDepth="0" BeginColumn="21" BeginLine="4" EndColumn="23" EndLine="4" ExceptionBlockParameter="false" Image="var" Label=""/>
<VariableInitializer BeginColumn="27" BeginLine="4" EndColumn="37" EndLine="4" Image="" Label="">
<Expression BeginColumn="27" BeginLine="4" EndColumn="37" EndLine="4" Image="" Label="">
<PrimaryExpression BeginColumn="27" BeginLine="4" EndColumn="37" EndLine="4" Image="" Label="">
<PrimaryPrefix BeginColumn="27" BeginLine="4" EndColumn="30" EndLine="4" Image="" Label="this" SuperModifier="false" ThisModifier="true"/>
<PrimarySuffix ArgumentCount="" Arguments="false" ArrayDereference="false" BeginColumn="31" BeginLine="4" EndColumn="37" EndLine="4" Image="nocall" Label=""/>
</PrimaryExpression>
</Expression>
</VariableInitializer>
</VariableDeclarator>
</LocalVariableDeclaration>
</BlockStatement>
<BlockStatement Allocation="false" BeginColumn="17" BeginLine="5" EndColumn="39" EndLine="5" Image="" Label="">
Instead of Label, I would use ThisModifier - the reason is, that Label will not be available in PMD 5 anymore. Label is just a string representation (similar to toString()).
//PrimaryExpression[PrimaryPrefix/@ThisModifier='true']
This will work both with PMD 4.x and the future PMD 5 - so you won't need to fix the rule.
See also: https://sourceforge.net/projects/pmd/forums/forum/188194/topic/4971141