# This file describes custom XPath functions per language # This is rendered using _includes/custom/xpath_fun_doc.html aliases: - &qname_param name: javaQualifiedName type: "xs:string" description: "The qualified name of a Java class, possibly with pairs of brackets to indicate an array type. Can also be a primitive type name." - &node_param name: element type: "xs:element" description: "Any element node" - &needs_typenode "The context node must be a {% jdoc jast::TypeNode %}" - &coord_fun_note | The function is not context-dependent, but takes a node as its first parameter. - &needs_node_ctx "The requires the context node to be an element" langs: - name: "All languages" ns: "pmd" header: "Functions available to all languages are in the namespace `pmd`." funs: - name: fileName returnType: "xs:string" shortDescription: "Returns the simple name of the current file" description: | Returns the current simple file name, without path but including the extension. This can be used to write rules that check file naming conventions. since: 6.38.0 notes: *needs_node_ctx examples: - code: "//b[pmd:fileName() = 'Foo.xml']" outcome: "Matches any `<b>` tags in files called `Foo.xml`." - name: startLine returnType: "xs:int" parameters: - *node_param shortDescription: "Returns the start line of the given node" description: | Returns the line where the node starts in the source file. Line numbers are 1-based. since: 6.44.0 notes: *coord_fun_note examples: - code: "//b[pmd:startLine(.) > 5]" outcome: "Matches any `<b>` node which starts after the fifth line." - name: endLine returnType: "xs:int" parameters: - *node_param shortDescription: "Returns the end line of the given node" description: | Returns the line where the node ends in the source file. Line numbers are 1-based. since: 6.44.0 notes: *coord_fun_note examples: - code: "//b[pmd:endLine(.) == pmd:startLine(.)]" outcome: "Matches any `<b>` node which doesn't span more than one line." - name: startColumn returnType: "xs:int" parameters: - *node_param shortDescription: "Returns the start column of the given node (inclusive)" description: | Returns the column number where the node starts in the source file. Column numbers are 1-based. The start column is inclusive. since: 6.44.0 notes: *coord_fun_note examples: - code: "//b[pmd:startColumn(.) = 1]" outcome: "Matches any `<b>` node which starts on the first column of a line" - name: endColumn returnType: "xs:int" parameters: - *node_param shortDescription: "Returns the end column of the given node (exclusive)" description: | Returns the column number where the node ends in the source file. Column numbers are 1-based. The end column is exclusive. since: 6.44.0 notes: *coord_fun_note examples: - code: "//b[pmd:startLine(.) = pmd:endLine(.) and pmd:endColumn(.) - pmd:startColumn(.) = 1]" outcome: "Matches any `<b>` node which spans exactly one character" - name: "Java" ns: "pmd-java" funs: - name: nodeIs returnType: "xs:boolean" shortDescription: "Tests the runtime type of the node instance" description: "Returns true if the runtime type of the AST node is a subtype of the given class. Contrary to typeIs, this tests the type of the AST node. For example, the AST node for a literal (e.g. `5d`) has type ASTNumericLiteral, and this function will ignore the static type of the expression (double)" parameters: - name: nodeClassName type: "xs:string" description: "Simple name of a class or interface in package {% jdoc_package :jast %}, without the 'AST' prefix" examples: - code: '//*[pmd-java:nodeIs("Expression")]' outcome: "Matches all nodes that implement {% jdoc jast::ASTExpression %}" - code: '//*[pmd-java:nodeIs("AnyTypeDeclaration")]' outcome: "Matches all nodes that implement {% jdoc jast::ASTAnyTypeDeclaration %}" - code: '//*[pmd-java:nodeIs("Foo")]' outcome: "Runtime error, there's no class ASTFoo in the package" - name: typeIs returnType: "xs:boolean" shortDescription: "Tests a node's static type" description: "Returns true if the context node's static Java type is a subtype of the given type. This tests for the resolved type of the Java construct, not the type of the AST node. For example, the AST node for a literal (e.g. `5d`) has type ASTNumericLiteral, however this function will compare the type of the literal (eg here, `double`) against the argument." notes: *needs_typenode parameters: - *qname_param examples: - code: '//FormalParameter[pmd-java:typeIs("java.lang.String[]")]' outcome: "Matches formal parameters of type `String[]` (including vararg parameters)" - code: '//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]' outcome: "Matches variable declarators of type `List` or any of its subtypes (including e.g. `ArrayList`)" - name: typeIsExactly returnType: "xs:boolean" shortDescription: "Tests a node's static type, ignoring subtypes" description: "Returns true if the context node's static type is exactly the given type. In particular, returns false if the context node's type is a subtype of the given type." notes: *needs_typenode parameters: - *qname_param examples: - code: '//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]' outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" - name: metric returnType: "xs:decimal?" shortDescription: "Computes and returns the value of a metric" description: Returns the value of the metric as evaluated on the context node. If the metric cannot be computed on that node, returns an empty sequence (which is falsy). parameters: - name: "metricKey" type: "xs:string" description: "The name of a metric in {% jdoc jmx::JavaMetrics %} (or an alias thereof)." examples: - code: "//ClassOrInterfaceDeclaration[metric('NCSS') > 200]" outcome: "" - code: "//MethodDeclaration[metric('CYCLO') > 10 and metric('NCSS') > 20]" outcome: "" - code: "//TypeParameter[metric('idontexist') > 50]" outcome: "Error: no such metric" - name: hasAnnotation returnType: "xs:boolean" shortDescription: "Tests whether an annotation is present on the node" description: "Returns true if the node has an annotation with the given qualified name" notes: "The context node must be an {% jdoc jast::Annotatable %}, otherwise this returns false" parameters: - name: annotationClassName type: "xs:string" description: "Canonical name of an annotation type" examples: - code: '//MethodDeclaration[pmd-java:hasAnnotation("java.lang.Override")]' outcome: "Matches all method declarations that are annotated with @Override" - name: modifiers returnType: "xs:string*" shortDescription: "Produce the effective modifiers of a node" description: >- Returns a sequence of the effective modifiers of a node as strings. This is documented on {% jdoc jast::ASTModifierList#getEffectiveModifiers() %}. notes: "The context node must be an {% jdoc jast::AccessNode %}, otherwise this returns an empty sequence" parameters: examples: - code: '//MethodDeclaration[pmd-java:modifiers() = "native"]' outcome: "Matches native method declarations" - code: '//MethodDeclaration[pmd-java:modifiers() = ("native", "static")]' outcome: >- Matches method declarations that have a 'native' OR a 'static' modifier. This may be counter-intuitive. - code: '//MethodDeclaration[pmd-java:modifiers() = "public"]' outcome: >- Matches method declarations that have a 'public' modifier, explicit or implicit. For example, this would match methods in interfaces, which implicitly have the modifier. Use the `explicitModifiers` function if you don't want the implicit part. Also note that `@Visibility = 'public'` is a better use of the API, in this particular instance. - name: explicitModifiers returnType: "xs:string*" shortDescription: "Produce the explicit modifiers of a node" description: >- Returns a sequence of the explicit modifiers of a node as strings. This is documented on {% jdoc jast::ASTModifierList#getExplicitModifiers() %}. notes: "The context node must be an {% jdoc jast::AccessNode %}, otherwise this returns an empty sequence" parameters: examples: - code: '//MethodDeclaration[pmd-java:explicitModifiers() = "public"]' outcome: "Matches method declarations that have an explicit 'public' modifier." - name: matchesSig returnType: "xs:boolean" shortDescription: "Matches the signature called by a method or constructor call" description: >- Uses an {% jdoc java::lang.java.types.TypeTestUtil.InvocationMatcher %} to test the method signature called by the context node. The format of the parameter is described on that class. notes: "The context node must be an {% jdoc jast::InvocationNode %}, otherwise this returns false" parameters: - name: "sig" type: "xs:string" description: "A signature, in the format described on {% jdoc java::lang.java.types.TypeTestUtil.InvocationMatcher %}" examples: - code: '//MethodCall[pmd-java:matchesSig("_#equals(java.lang.Object)")]' outcome: "Matches calls to the method `equals` on any receiver type" - code: '//MethodCall[pmd-java:matchesSig("java.lang.Enum#equals(java.lang.Object)")]' outcome: "Matches calls to the method `equals` on receiver that is a subtype of Enum" - code: '//MethodCall[pmd-java:matchesSig("java.lang.String#toString()")]' outcome: "Matches calls to the method `toString` on String receivers" - code: '//MethodCall[pmd-java:matchesSig("_#_(int,int)")]' outcome: "Matches calls to any method with 2 `int` parameters (!= argument)" - code: '//ConstructorCall[pmd-java:matchesSig("java.util.ArrayList#new(int)")]' outcome: "Matches constructors calls of ArrayList with a single int parameter"