2.9 KiB
XPath Patterns for Method Calls and Annotations
← Back to XPath Patterns Index
Method Call Patterns
Ban System.debug (non-test classes)
//MethodCallExpression[@FullMethodName='System.debug']
[not(ancestor::UserClass[ModifierNode[@Test = true()]])]
AST evidence: MethodCallExpression has @FullMethodName='System.debug'. Test classes have ModifierNode[@Test = true()].
Catches: System.debug('anything'); in production classes
Does NOT catch (correct): Same call inside @IsTest classes
Ban Database.query (dynamic SOQL — SOQL injection risk)
//MethodCallExpression[@FullMethodName='Database.query']
AST evidence: MethodCallExpression[@FullMethodName='Database.query'] (line 118 of verified AST)
To exclude test classes:
//MethodCallExpression[@FullMethodName='Database.query']
[not(ancestor::UserClass[ModifierNode[@Test = true()]])]
Ban Test.isRunningTest() in production code
//MethodCallExpression[@FullMethodName='Test.isRunningTest']
[not(ancestor::UserClass[ModifierNode[@Test = true()]])]
Ban specific method calls (generic pattern)
//MethodCallExpression[@FullMethodName='ClassName.methodName']
Common examples:
@FullMethodName='System.debug'@FullMethodName='Database.query'@FullMethodName='Test.isRunningTest'@FullMethodName='UserInfo.getUserId'@FullMethodName='Limits.getQueries'
Annotation Patterns
@AuraEnabled without cacheable=true
//Method/ModifierNode/Annotation[@Name='AuraEnabled'
and not(AnnotationParameter[@Name='cacheable' and @Value='true'])]
AST evidence: Annotation[@Name='AuraEnabled'] with child AnnotationParameter[@Name='cacheable'][@Value='true']
Catches: @AuraEnabled public static ... (no cacheable)
Does NOT catch (correct): @AuraEnabled(cacheable=true) public static ...
@future methods (recommend Queueable instead)
//Method/ModifierNode/Annotation[@Name='Future']
AST evidence: Annotation @Name='Future' (note: PMD normalizes @future → Future in the Name attribute, but @RawName='future')
@SuppressWarnings usage (audit/ban)
//Annotation[@Name='SuppressWarnings']
AST evidence: Annotation[@Name='SuppressWarnings'] with AnnotationParameter[@Name='value'][@Value='PMD.RuleName']
To flag specific suppressions:
//Annotation[@Name='SuppressWarnings']/AnnotationParameter[contains(@Value, 'ApexCRUDViolation')]
@IsTest without testFor parameter
From GitHub issue #2008:
//UserClass/ModifierNode/Annotation[
@Name='IsTest'
and not(AnnotationParameter[@Name='testFor'])
]
@IsTest class without System.runAs
//UserClass[ModifierNode[@Test = true()]]
/Method[ModifierNode[@Test = true()]]
/BlockStatement[not(.//RunAsBlockStatement)]
AST evidence: RunAsBlockStatement is the node for System.runAs(...) { } blocks.