A few general notes:
? character.(relation lvar lvar) , where an lvar can either be a logic variable, or a value.42true"Hello world":FieldDeclarationbefore and after ASTs can be considered values.General-purpose relations:
fresh (creates new scope ; logical and)conde (logical or)fails (logical not)==!=debug (for println-style debugging)AST navigation relations:
ast (check type of AST node)has (get a specific child)child+ (get a descendant)parent (get the parent)parent+ (get an ancestor)contains (retrieve an element of a list property)Other/compound relations:
literal-value (get the primitive value in a Literal AST node)corresponding-method (relate a method in before and after)name-equals, type-equals (check if two identifiers/types are equal)ast-equals (deep equality check on two AST nodes)ast-str-equals (Compare the .toString()/source code representation of an AST node to a specific String)method-method|same-signature (test whether two methods have the same signature)value|null, value|list, value|primitive (test if something is a null value, list value, or primitive value)ast|invocation, ast|invocation, ast|expression, ast|localvariable (more restrictive variants of the ast relation)ast-ast-typedeclaration|encompassing, ast-methoddeclaration|encompassing (relate a node to its container)field|introduced (check if a new field was added in after that did not exist in before)str-starts-with, str-ends-with, str-containsfresh (fresh [?a ?b ?c]
clauses)
; Example
(fresh [?root ?field]
(child+ ?root ?field)
(ast :FieldDeclaration ?field)
)
Creates a new scope in which the listed local logic variables can be used.
Also acts as a logical and: all clauses in a fresh must be true for the entire fresh relation to be true.
== (== ?a ?b)
Unifies two logic variables. In other words, ?a and ?b must have the same value.
Note: do not use this to check whether two AST nodes look the same (but may actually be two different objects in memory) ; you can use ast-equals for that purpose.
!= (!= ?a ?b)
?a and ?b cannot have the same value.
conde (conde clauses)
; Example
(fresh [?node])
(conde
(ast :FieldDeclaration ?node)
(ast :MethodDeclaration ?node)
)
Logical or. At least one of its clauses must be true for the conde relation to be true.
fails (fails clause)
; Example
(fails (== 1 2))
Logical not. Its one clause must be false, for the fails relation to be true.
debug (debug ?var)
Prints all possible values (+ the type) of ?var as determined at this point in the query.
(This relation always succeeds, so it does not affect the query's semantics.)
There also is 2-parameter variant of debug:
(debug "Hello" ?var)
This is equivalent to the 1-parameter variant, except that the output is prefixed with "Hello". (This is convenient to distinguish between multiple debugs in a query.)
ast(ast :MethodDeclaration ?node)
This relation holds if ?node is a AST node of type MethodDeclaration.
To know which type you're looking for, see the "Element kind" column in the AST browser.
Alternatively, you can check the list of all AST node types.
has(has :property ?node ?child)
;Example
(has :name ?typedeclaration ?classname)
Retrieve a specific ?child of ?node. Each child is identified with a property name, :property.
The above example retrieves the name of a type declaration (a class).
To know which property you're looking for, see the "Description" column in the AST browser.
Note that some properties will produce a list of AST nodes instead of just one node. (e.g. the parameters: property of a MethodDeclaration returns the list of all formal parameters) To obtain an element from the list, see the contains relation.
Alternatively, you can also check the list of all types of AST nodes. For a given type of AST node, you'll see several fields that end in _PROPERTY. For instance, a TypeDeclaration has a MODIFIERS_PROPERTY field, i.e. a property called MODIFIERS. In Qwalkeko this is reformatted as :modifiers.
child+(child+ ?node ?descendant)
Relate ?node to one of its descendants, ?descendant
parent (parent ?x ?parent)
Retrieve the ?parent AST node of ?x
(?x can be both an AST node or a primitive value)
parent+(parent+ ?node ?ancestor)
Relate ?node to one of its ancestors, ?ancestor
contains(contains ?list ?element)
; Example
(ast :MethodDeclaration ?method)
(has :parameters ?method ?param-list)
(contains ?param-list ?param)
Retrieve an element in a list. (A list is obtained by retrieving a list property in a has relation. The example above retrieves the :parameters list property in a method declaration, which returns the list of formal parameters, then uses contains to retrieve a parameter from the list.)
literal-value(literal-value ?node ?value)
Relate an AST node representing a literal (e.g. a node of type BooleanLiteral) to its value
corresponding-method(corresponding-method ?before-method before ?after-method after)
This relation holds if ?before-method in the before-version of the code, corresponds to ?after-method in the after-version of the code.
name-equals, type-equals (name-equals ?name1 ?name2)
name-equals: Checks whether two name AST nodes refer to the same identifier (?name1/?name2 can be of type SimpleName or QualifiedName)type-equals: Checks whether two type AST nodes (e.g. SimpleType) refer to the same typeast-equals (ast-equals ?ast1 ?ast2)
Performs a deep equality check on two AST nodes. (That is, the entire trees of ?ast1 and ast2 are visited to check if they are the same.)
ast-str-equals (ast-str-equals ?ast "some string")
;Example
(ast :MarkerAnnotation ?annotation)
(ast-str-equals ?annotation "@Override")
Compares the source code representation of an AST node to a specific String. Note that the second parameter must be a concrete String value; using a logic variable here is not supported.
This relation is convenient to avoid any "redundant navigation". The above example looks for an @Override notation. We can already check for the name of the annotation given a node of type MarkerAnnotation, even though the annotation name itself is actually stored in a descendant node.
method-method|same-signature (method-method|same-signature ?method-a ?method-b)
Test whether two method declarations have the same parameter list.
value|null , value|list , value|primitive (value|null ?x)
value|null : Checks whether ?x is null
value|list : Checks whether ?x is a list node
value|primitive : Checks whether ?x is a primitive value (not an AST node)
ast|invocation, ast|expression, ast|localvariable(ast|invocation ?type ?node)
These relations are equivalent to ast. They relate AST node ?node to its type, but these relations add an additional constraint on the type:
ast|invocation: ?node must be some kind of invocation (a method call, super call, constructor call, ...)ast|expression: ?node must be some kind of expressionast|localvariable: ?node must be some kind of use of a local variableast-typedeclaration|encompassing, ast-methoddeclaration|encompassing (ast-typedeclaration|encompassing ?node ?t)
ast-typedeclaration|encompassing: Given an AST node ?node, retrieve its encompassing type declaration. (i.e. the class/interface that contains ?node)ast-methoddeclaration|encompassing: Given an AST node ?node, retrieve its encompassing method declaration. (i.e. the method that contains ?node)field|introduced (field|introduced before after ?field)
Field declaration ?field must exist in after, but not in before.
str-starts-with, str-ends-with, str-contains (str-starts-with ?string ?prefix)
str-starts-with: Test if a String starts with a certain prefixstr-ends-with: Test if a String ends with a certain suffixstr-contains: Test if a String contains a certain substring