我想在以下场景中使用 XPATH 表达式创建 PMD 规则:
当方法的参数仅在日志中使用时,例如 @Slf4j 的 log.info、log.error、log.warn 或 log.debug,我希望 XPATH 捕获这种情况。防止参数不被使用(包括日志)
生成的 AST 树是这样的:
└─ CompilationUnit
└─ ClassOrInterfaceDeclaration
├─ ModifierList
└─ ClassOrInterfaceBody
├─ MethodDeclaration
│ ├─ ModifierList
│ ├─ VoidType
│ ├─ FormalParameters
│ │ └─ FormalParameter
│ │ ├─ ModifierList
│ │ ├─ ClassOrInterfaceType
│ │ └─ VariableDeclaratorId
│ └─ Block
│ └─ ExpressionStatement
│ └─ MethodCall
│ ├─ AmbiguousName
│ └─ ArgumentList
│ └─ VariableAccess
└─ MethodDeclaration
├─ ModifierList
├─ VoidType
├─ FormalParameters
└─ Block
└─ ExpressionStatement
└─ MethodCall
├─ AmbiguousName
└─ ArgumentList
public void test(final String value) {
log.info(value);
// must take
}
public void method(final String value) {
log.info(value);
this.otherMethod(value);
// must not take
}
public void method() {
log.info("value");
// must not take
}
我尝试了很多事情,最后一次尝试是这样但没有成功:
//MethodDeclaration[string(FormalParameters/FormalParameter/VariableDeclaratorId/@name) = string(//MethodCall/ArgumentList/VariableAccess/@name) and Block/ExpressionStatement/MethodCall]
给出这个java代码
public class PMDSource{
public void detectMe(final String value) {
log.info(value);
// must take
}
public void doNotDetectMe1(final String value) {
log.info(value);
this.otherMethod(value);
// must not take
}
public void doNotDetectMe2() {
log.info("value");
// must not take
}
public void detectMe2(final Integer speed) {
log.info(speed);
// must take
}
}
此 XPath 表达式将检测
detectMe
和 detectMe2
方法
//MethodDeclaration[FormalParameters[@Size=1]/FormalParameter/VariableDeclaratorId/@Name = ./Block[@Size=1]//MethodCall[AmbiguousName/@Name ="log"]/ArgumentList/VariableAccess/@Name]
可以测试生成 AST XML 转储
pmd ast-dump --format xml --language java --file PMDSource.java > PMDSource.java.xml
然后测试 XPath
xmllint --xpath '//MethodDeclaration[FormalParameters[@Size=1]/FormalParameter/VariableDeclaratorId/@Name = ./Block[@Size=1]//MethodCall[AmbiguousName/@Name ="log"]/ArgumentList/VariableAccess/@Name]/@Name' PMDSource.java.xml
结果
Name="detectMe"
Name="detectMe2"