You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PMD的XPath查找Java中的二元运算符重复表达式

用PMD检测Java中的二元运算符重复公共子表达式

需求说明

我需要用PMD查找Java代码中如下形式的公共子表达式:

z = a +b;
q = a +b;

我知道CPD可以处理这类场景,但它会返回文件中匹配的复制函数等内容,我只想定位与二元运算符关联的重复表达式。

AST结构分析

分析示例代码z = a + b时,对应的BlockStatement结构如下:

└─ BlockStatement
   └─ Statement
      └─ StatementExpression
         ├─ PrimaryExpression
         │  └─ PrimaryPrefix        //   z 
         │     └─ Name
         ├─ AssignmentOperator
         └─ Expression
            └─ AdditiveExpression   //   +
               ├─ PrimaryExpression
               │  └─ PrimaryPrefix  //   a 
               │     └─ Name
               └─ PrimaryExpression
                  └─ PrimaryPrefix  //   b
                     └─ Name

问题与尝试

我知道需要检查某个AdditiveExpression在方法中是否出现多次,但无法实现。目前有个疑惑:判定重复时,是需要比较表达式的全部三个部分,还是只需比较内部的AdditiveExpression节点即可?

我尝试过的错误XPath写法:

//AdditiveExpression[count(.) > 0]
//AdditiveExpression[.=../../../../BlockStatement/Statement/StatementExpression/Expression]/AdditiveExpression]

补充示例

Java代码示例

public class Example{
    public static void main(final String[] args){
    int i = 5;
    int k = 10;
    int z,h;
    z = i + k;
    h = i + k;
    }
}

对应的AST XML

<?xml version='1.0' encoding='UTF-8' ?>
<CompilationUnit Image='' PackageName='' declarationsAreInDefaultPackage='true'>
    <TypeDeclaration Image=''>
        <ClassOrInterfaceDeclaration Abstract='false' BinaryName='Example' Default='false' Final='false' Image='Example' Interface='false' Local='false' Modifiers='1' Native='false' Nested='false' NonSealed='false' PackagePrivate='false' Private='false' Protected='false' Public='true' Sealed='false' SimpleName='Example' Static='false' Strictfp='false' Synchronized='false' Transient='false' TypeKind='CLASS' Volatile='false'>
            <ClassOrInterfaceBody AnonymousInnerClass='false' EnumChild='false' Image=''>
                <ClassOrInterfaceBodyDeclaration AnonymousInnerClass='false' EnumChild='false' Image='' Kind='METHOD'>
                    <MethodDeclaration Abstract='false' Arity='1' Default='false' Final='false' Image='' InterfaceMember='false' Kind='METHOD' MethodName='main' Modifiers='17' Name='main' Native='false' PackagePrivate='false' Private='false' Protected='false' Public='true' Static='true' Strictfp='false' Synchronized='false' SyntacticallyAbstract='false' SyntacticallyPublic='true' Transient='false' Void='true' Volatile='false'>
                        <ResultType Image='' Void='true' returnsArray='false' />
                        <MethodDeclarator Image='main' ParameterCount='1'>
                            <FormalParameters Image='' ParameterCount='1' Size='1'>
                                <FormalParameter Abstract='false' Array='true' ArrayDepth='1' Default='false' ExplicitReceiverParameter='false' Final='true' Image='' Modifiers='32' Native='false' PackagePrivate='true' Private='false' Protected='false' Public='false' Static='false' Strictfp='false' Synchronized='false' Transient='false' TypeInferred='false' Varargs='false' Volatile='false'>
                                    <Type Array='true' ArrayDepth='1' ArrayType='true' Image='' TypeImage='String'>
                                        <ReferenceType Array='true' ArrayDepth='1' Image=''>
                                            <ClassOrInterfaceType AnonymousClass='false' Array='true' ArrayDepth='1' Image='String' ReferenceToClassSameCompilationUnit='false' />
                                        </ReferenceType>
                                    </Type>
                                    <VariableDeclaratorId Array='false' ArrayDepth='0' ArrayType='true' ExceptionBlockParameter='false' ExplicitReceiverParameter='false' Field='false' Final='true' ForeachVariable='false' FormalParameter='true' Image='args' LambdaParameter='false' LocalVariable='false' Name='args' PatternBinding='false' ResourceDeclaration='false' TypeInferred='false' VariableName='args' />
                                </FormalParameter>
                            </FormalParameters>
                        </MethodDeclarator>
                        <Block Image='' containsComment='false'>
                            <BlockStatement Allocation='false' Image=''>
                                <LocalVariableDeclaration Abstract='false' Array='false' ArrayDepth='0' Default='false' Final='false' Image='' Modifiers='0' Native='false' PackagePrivate='true' Private='false' Protected='false' Public='false' Static='false' Strictfp='false' Synchronized='false' Transient='false' TypeInferred='false' VariableName='i' Volatile='false'>
                                    <Type Array='false' ArrayDepth='0' ArrayType='false' Image='' TypeImage='int'>
                                        <PrimitiveType Array='false' ArrayDepth='0' Boolean='false' Image='int' />
                                    </Type>
                                    <VariableDeclarator Image='' Initializer='true' Name='i'>
                                        <VariableDeclaratorId Array='false' ArrayDepth='0' ArrayType='false' ExceptionBlockParameter='false' ExplicitReceiverParameter='false' Field='false' Final='false' ForeachVariable='false' FormalParameter='false' Image='i' LambdaParameter='false' LocalVariable='true' Name='i' PatternBinding='false' ResourceDeclaration='false' TypeInferred='false' VariableName='i' />
                                        <VariableInitializer Image=''>
                                            <Expression Image='' StandAlonePrimitive='true'>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Literal CharLiteral='false' DoubleLiteral='false' EscapedStringLiteral='5' FloatLiteral='false' Image='5' IntLiteral='true' LongLiteral='false' SingleCharacterStringLiteral='false' StringLiteral='false' TextBlock='false' TextBlockContent='5' ValueAsDouble='NaN' ValueAsFloat='NaN' ValueAsInt='5' ValueAsLong='5' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                            </Expression>
                                        </VariableInitializer>
                                    </VariableDeclarator>
                                </LocalVariableDeclaration>
                            </BlockStatement>
                            <BlockStatement Allocation='false' Image=''>
                                <LocalVariableDeclaration Abstract='false' Array='false' ArrayDepth='0' Default='false' Final='false' Image='' Modifiers='0' Native='false' PackagePrivate='true' Private='false' Protected='false' Public='false' Static='false' Strictfp='false' Synchronized='false' Transient='false' TypeInferred='false' VariableName='k' Volatile='false'>
                                    <Type Array='false' ArrayDepth='0' ArrayType='false' Image='' TypeImage='int'>
                                        <PrimitiveType Array='false' ArrayDepth='0' Boolean='false' Image='int' />
                                    </Type>
                                    <VariableDeclarator Image='' Initializer='true' Name='k'>
                                        <VariableDeclaratorId Array='false' ArrayDepth='0' ArrayType='false' ExceptionBlockParameter='false' ExplicitReceiverParameter='false' Field='false' Final='false' ForeachVariable='false' FormalParameter='false' Image='k' LambdaParameter='false' LocalVariable='true' Name='k' PatternBinding='false' ResourceDeclaration='false' TypeInferred='false' VariableName='k' />
                                        <VariableInitializer Image=''>
                                            <Expression Image='' StandAlonePrimitive='true'>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Literal CharLiteral='false' DoubleLiteral='false' EscapedStringLiteral='10' FloatLiteral='false' Image='10' IntLiteral='true' LongLiteral='false' SingleCharacterStringLiteral='false' StringLiteral='false' TextBlock='false' TextBlockContent='10' ValueAsDouble='NaN' ValueAsFloat='NaN' ValueAsInt='10' ValueAsLong='10' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                            </Expression>
                                        </VariableInitializer>
                                    </VariableDeclarator>
                                </LocalVariableDeclaration>
                            </BlockStatement>
                            <BlockStatement Allocation='false' Image=''>
                                <LocalVariableDeclaration Abstract='false' Array='false' ArrayDepth='0' Default='false' Final='false' Image='' Modifiers='0' Native='false' PackagePrivate='true' Private='false' Protected='false' Public='false' Static='false' Strictfp='false' Synchronized='false' Transient='false' TypeInferred='false' VariableName='z' Volatile='false'>
                                    <Type Array='false' ArrayDepth='0' ArrayType='false' Image='' TypeImage='int'>
                                        <PrimitiveType Array='false' ArrayDepth='0' Boolean='false' Image='int' />
                                    </Type>
                                    <VariableDeclarator Image='' Initializer='false' Name='z'>
                                        <VariableDeclaratorId Array='false' ArrayDepth='0' ArrayType='false' ExceptionBlockParameter='false' ExplicitReceiverParameter='false' Field='false' Final='false' ForeachVariable='false' FormalParameter='false' Image='z' LambdaParameter='false' LocalVariable='true' Name='z' PatternBinding='false' ResourceDeclaration='false' TypeInferred='false' VariableName='z' />
                                    </VariableDeclarator>
                                    <VariableDeclarator Image='' Initializer='false' Name='h'>
                                        <VariableDeclaratorId Array='false' ArrayDepth='0' ArrayType='false' ExceptionBlockParameter='false' ExplicitReceiverParameter='false' Field='false' Final='false' ForeachVariable='false' FormalParameter='false' Image='h' LambdaParameter='false' LocalVariable='true' Name='h' PatternBinding='false' ResourceDeclaration='false' TypeInferred='false' VariableName='h' />
                                    </VariableDeclarator>
                                </LocalVariableDeclaration>
                            </BlockStatement>
                            <BlockStatement Allocation='false' Image=''>
                                <Statement Image=''>
                                    <StatementExpression Image=''>
                                        <PrimaryExpression Image=''>
                                            <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                <Name Image='z' />
                                            </PrimaryPrefix>
                                        </PrimaryExpression>
                                        <AssignmentOperator Compound='false' Image='=' />
                                        <Expression Image='' StandAlonePrimitive='false'>
                                            <AdditiveExpression Image='+' Operator='+'>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Name Image='i' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Name Image='k' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                            </AdditiveExpression>
                                        </Expression>
                                    </StatementExpression>
                                </Statement>
                            </BlockStatement>
                            <BlockStatement Allocation='false' Image=''>
                                <Statement Image=''>
                                    <StatementExpression Image=''>
                                        <PrimaryExpression Image=''>
                                            <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                <Name Image='h' />
                                            </PrimaryPrefix>
                                        </PrimaryExpression>
                                        <AssignmentOperator Compound='false' Image='=' />
                                        <Expression Image='' StandAlonePrimitive='false'>
                                            <AdditiveExpression Image='+' Operator='+'>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Name Image='i' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                                <PrimaryExpression Image=''>
                                                    <PrimaryPrefix Image='' SuperModifier='false' ThisModifier='false'>
                                                        <Name Image='k' />
                                                    </PrimaryPrefix>
                                                </PrimaryExpression>
                                            </AdditiveExpression>
                                        </Expression>
                                    </StatementExpression>
                                </Statement>
                            </BlockStatement>
                        </Block>
                    </MethodDeclaration>
                </ClassOrInterfaceBodyDeclaration>
            </ClassOrInterfaceBody>
        </ClassOrInterfaceDeclaration>
    </TypeDeclaration>
</CompilationUnit>

内容的提问来源于stack exchange,提问作者Laschoking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 14:53:13