1
votes

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="">
2

2 Answers

2
votes

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

1
votes

Use:

//PrimaryExpression[PrimaryPrefix/@Label='this']

When this XPath expression is evaluated on the provided XML (it is severely malformed, but I corrected it):

<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=""/>
    </Block>
</MethodDeclaration>

the wanted element is selected:

<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>