Java: Add PrintAST

This commit is contained in:
Joe
2020-09-10 10:47:47 +01:00
parent 159353d545
commit 19af3e5e30
11 changed files with 698 additions and 5 deletions

View File

@@ -86,6 +86,19 @@ class Top extends @top {
/** Gets a textual representation of this element. */
cached
string toString() { hasName(this, result) }
/**
* Gets the name of a primary CodeQL class to which this element belongs.
*
* For most elements, this is simply the most precise syntactic category to
* which they belong; for example, `AddExpr` is a primary class, but
* `BinaryExpr` is not.
*
* This predicate always has a result. If no primary class can be
* determined, the result is `"???"`. If multiple primary classes match,
* this predicate can have multiple results.
*/
string getAPrimaryQlClass() { result = "???" }
}
/** A location maps language elements to positions in source files. */

View File

@@ -72,6 +72,8 @@ class Annotation extends @annotation, Expr {
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
)
}
override string getAPrimaryQlClass() { result = "Annotation" }
}
/** An `Annotation` that applies to a declaration. */

View File

@@ -30,4 +30,6 @@ class CompilationUnit extends Element, File {
* Gets the module associated with this compilation unit, if any.
*/
Module getModule() { cumodule(this, result) }
override string getAPrimaryQlClass() { result = "CompilationUnit" }
}

View File

@@ -413,6 +413,8 @@ class ArrayAccess extends Expr, @arrayaccess {
Expr getIndexExpr() { result.isNthChildOf(this, 1) }
override string toString() { result = "...[...]" }
override string getAPrimaryQlClass() { result = "ArrayAccess" }
}
/**
@@ -450,6 +452,8 @@ class ArrayCreationExpr extends Expr, @arraycreationexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "new " + this.getType().toString() }
override string getAPrimaryQlClass() { result = "ArrayCreationExpr" }
}
/** An array initializer occurs in an array creation expression. */
@@ -467,6 +471,8 @@ class ArrayInit extends Expr, @arrayinit {
/** Gets a printable representation of this expression. */
override string toString() { result = "{...}" }
override string getAPrimaryQlClass() { result = "ArrayInit" }
}
/** A common super-class that represents all varieties of assignments. */
@@ -494,7 +500,9 @@ class Assignment extends Expr, @assignment {
*
* For example, `x = 23`.
*/
class AssignExpr extends Assignment, @assignexpr { }
class AssignExpr extends Assignment, @assignexpr {
override string getAPrimaryQlClass() { result = "AssignExpr" }
}
/**
* A common super-class to represent compound assignments, which include an implicit operator.
@@ -519,56 +527,78 @@ class AssignOp extends Assignment, @assignop {
/** A compound assignment expression using the `+=` operator. */
class AssignAddExpr extends AssignOp, @assignaddexpr {
override string getOp() { result = "+=" }
override string getAPrimaryQlClass() { result = "AssignAddExpr" }
}
/** A compound assignment expression using the `-=` operator. */
class AssignSubExpr extends AssignOp, @assignsubexpr {
override string getOp() { result = "-=" }
override string getAPrimaryQlClass() { result = "AssignSubExpr" }
}
/** A compound assignment expression using the `*=` operator. */
class AssignMulExpr extends AssignOp, @assignmulexpr {
override string getOp() { result = "*=" }
override string getAPrimaryQlClass() { result = "AssignMulExpr" }
}
/** A compound assignment expression using the `/=` operator. */
class AssignDivExpr extends AssignOp, @assigndivexpr {
override string getOp() { result = "/=" }
override string getAPrimaryQlClass() { result = "AssignDivExpr" }
}
/** A compound assignment expression using the `%=` operator. */
class AssignRemExpr extends AssignOp, @assignremexpr {
override string getOp() { result = "%=" }
override string getAPrimaryQlClass() { result = "AssignRemExpr" }
}
/** A compound assignment expression using the `&=` operator. */
class AssignAndExpr extends AssignOp, @assignandexpr {
override string getOp() { result = "&=" }
override string getAPrimaryQlClass() { result = "AssignAndExpr" }
}
/** A compound assignment expression using the `|=` operator. */
class AssignOrExpr extends AssignOp, @assignorexpr {
override string getOp() { result = "|=" }
override string getAPrimaryQlClass() { result = "AssignOrExpr" }
}
/** A compound assignment expression using the `^=` operator. */
class AssignXorExpr extends AssignOp, @assignxorexpr {
override string getOp() { result = "^=" }
override string getAPrimaryQlClass() { result = "AssignXorExpr" }
}
/** A compound assignment expression using the `<<=` operator. */
class AssignLShiftExpr extends AssignOp, @assignlshiftexpr {
override string getOp() { result = "<<=" }
override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
}
/** A compound assignment expression using the `>>=` operator. */
class AssignRShiftExpr extends AssignOp, @assignrshiftexpr {
override string getOp() { result = ">>=" }
override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
}
/** A compound assignment expression using the `>>>=` operator. */
class AssignURShiftExpr extends AssignOp, @assignurshiftexpr {
override string getOp() { result = ">>>=" }
override string getAPrimaryQlClass() { result = "AssignURShiftExpr" }
}
/** A common super-class to represent constant literals. */
@@ -597,25 +627,37 @@ class BooleanLiteral extends Literal, @booleanliteral {
or
result = false and getLiteral() = "false"
}
override string getAPrimaryQlClass() { result = "BooleanLiteral" }
}
/** An integer literal. For example, `23`. */
class IntegerLiteral extends Literal, @integerliteral {
/** Gets the int representation of this literal. */
int getIntValue() { result = getValue().toInt() }
override string getAPrimaryQlClass() { result = "IntegerLiteral" }
}
/** A long literal. For example, `23l`. */
class LongLiteral extends Literal, @longliteral { }
class LongLiteral extends Literal, @longliteral {
override string getAPrimaryQlClass() { result = "LongLiteral" }
}
/** A floating point literal. For example, `4.2f`. */
class FloatingPointLiteral extends Literal, @floatingpointliteral { }
class FloatingPointLiteral extends Literal, @floatingpointliteral {
override string getAPrimaryQlClass() { result = "FloatingPointLiteral" }
}
/** A double literal. For example, `4.2`. */
class DoubleLiteral extends Literal, @doubleliteral { }
class DoubleLiteral extends Literal, @doubleliteral {
override string getAPrimaryQlClass() { result = "DoubleLiteral" }
}
/** A character literal. For example, `'\n'`. */
class CharacterLiteral extends Literal, @characterliteral { }
class CharacterLiteral extends Literal, @characterliteral {
override string getAPrimaryQlClass() { result = "CharacterLiteral" }
}
/** A string literal. For example, `"hello world"`. */
class StringLiteral extends Literal, @stringliteral {
@@ -623,6 +665,8 @@ class StringLiteral extends Literal, @stringliteral {
* Gets the literal string without the quotes.
*/
string getRepresentedString() { result = getValue() }
override string getAPrimaryQlClass() { result = "StringLiteral" }
}
/** The null literal, written `null`. */
@@ -630,6 +674,8 @@ class NullLiteral extends Literal, @nullliteral {
override string getLiteral() { result = "null" }
override string getValue() { result = "null" }
override string getAPrimaryQlClass() { result = "NullLiteral" }
}
/** A common super-class to represent binary operator expressions. */
@@ -661,96 +707,134 @@ class BinaryExpr extends Expr, @binaryexpr {
/** A binary expression using the `*` operator. */
class MulExpr extends BinaryExpr, @mulexpr {
override string getOp() { result = " * " }
override string getAPrimaryQlClass() { result = "MulExpr" }
}
/** A binary expression using the `/` operator. */
class DivExpr extends BinaryExpr, @divexpr {
override string getOp() { result = " / " }
override string getAPrimaryQlClass() { result = "DivExpr" }
}
/** A binary expression using the `%` operator. */
class RemExpr extends BinaryExpr, @remexpr {
override string getOp() { result = " % " }
override string getAPrimaryQlClass() { result = "RemExpr" }
}
/** A binary expression using the `+` operator. */
class AddExpr extends BinaryExpr, @addexpr {
override string getOp() { result = " + " }
override string getAPrimaryQlClass() { result = "AddExpr" }
}
/** A binary expression using the `-` operator. */
class SubExpr extends BinaryExpr, @subexpr {
override string getOp() { result = " - " }
override string getAPrimaryQlClass() { result = "SubExpr" }
}
/** A binary expression using the `<<` operator. */
class LShiftExpr extends BinaryExpr, @lshiftexpr {
override string getOp() { result = " << " }
override string getAPrimaryQlClass() { result = "LShiftExpr" }
}
/** A binary expression using the `>>` operator. */
class RShiftExpr extends BinaryExpr, @rshiftexpr {
override string getOp() { result = " >> " }
override string getAPrimaryQlClass() { result = "RShiftExpr" }
}
/** A binary expression using the `>>>` operator. */
class URShiftExpr extends BinaryExpr, @urshiftexpr {
override string getOp() { result = " >>> " }
override string getAPrimaryQlClass() { result = "URShiftExpr" }
}
/** A binary expression using the `&` operator. */
class AndBitwiseExpr extends BinaryExpr, @andbitexpr {
override string getOp() { result = " & " }
override string getAPrimaryQlClass() { result = "AddBitwiseExpr" }
}
/** A binary expression using the `|` operator. */
class OrBitwiseExpr extends BinaryExpr, @orbitexpr {
override string getOp() { result = " | " }
override string getAPrimaryQlClass() { result = "OrBitwiseExpr" }
}
/** A binary expression using the `^` operator. */
class XorBitwiseExpr extends BinaryExpr, @xorbitexpr {
override string getOp() { result = " ^ " }
override string getAPrimaryQlClass() { result = "?XorBitwiseExpr" }
}
/** A binary expression using the `&&` operator. */
class AndLogicalExpr extends BinaryExpr, @andlogicalexpr {
override string getOp() { result = " && " }
override string getAPrimaryQlClass() { result = "AndLogicalExpr" }
}
/** A binary expression using the `||` operator. */
class OrLogicalExpr extends BinaryExpr, @orlogicalexpr {
override string getOp() { result = " || " }
override string getAPrimaryQlClass() { result = "OrLogicalExpr" }
}
/** A binary expression using the `<` operator. */
class LTExpr extends BinaryExpr, @ltexpr {
override string getOp() { result = " < " }
override string getAPrimaryQlClass() { result = "LTExpr" }
}
/** A binary expression using the `>` operator. */
class GTExpr extends BinaryExpr, @gtexpr {
override string getOp() { result = " > " }
override string getAPrimaryQlClass() { result = "GTExpr" }
}
/** A binary expression using the `<=` operator. */
class LEExpr extends BinaryExpr, @leexpr {
override string getOp() { result = " <= " }
override string getAPrimaryQlClass() { result = "LEExpr" }
}
/** A binary expression using the `>=` operator. */
class GEExpr extends BinaryExpr, @geexpr {
override string getOp() { result = " >= " }
override string getAPrimaryQlClass() { result = "GEExpr" }
}
/** A binary expression using the `==` operator. */
class EQExpr extends BinaryExpr, @eqexpr {
override string getOp() { result = " == " }
override string getAPrimaryQlClass() { result = "EQExpr" }
}
/** A binary expression using the `!=` operator. */
class NEExpr extends BinaryExpr, @neexpr {
override string getOp() { result = " != " }
override string getAPrimaryQlClass() { result = "NEExpr" }
}
/**
@@ -872,41 +956,57 @@ class UnaryAssignExpr extends UnaryExpr, @unaryassignment { }
/** A post-increment expression. For example, `i++`. */
class PostIncExpr extends UnaryAssignExpr, @postincexpr {
override string toString() { result = "...++" }
override string getAPrimaryQlClass() { result = "PostIncExpr" }
}
/** A post-decrement expression. For example, `i--`. */
class PostDecExpr extends UnaryAssignExpr, @postdecexpr {
override string toString() { result = "...--" }
override string getAPrimaryQlClass() { result = "PostDecExpr" }
}
/** A pre-increment expression. For example, `++i`. */
class PreIncExpr extends UnaryAssignExpr, @preincexpr {
override string toString() { result = "++..." }
override string getAPrimaryQlClass() { result = "PreIncExpr" }
}
/** A pre-decrement expression. For example, `--i`. */
class PreDecExpr extends UnaryAssignExpr, @predecexpr {
override string toString() { result = "--..." }
override string getAPrimaryQlClass() { result = "PreDecExpr" }
}
/** A unary minus expression. For example, `-i`. */
class MinusExpr extends UnaryExpr, @minusexpr {
override string toString() { result = "-..." }
override string getAPrimaryQlClass() { result = "MinusExpr" }
}
/** A unary plus expression. For example, `+i`. */
class PlusExpr extends UnaryExpr, @plusexpr {
override string toString() { result = "+..." }
override string getAPrimaryQlClass() { result = "PlusExpr" }
}
/** A bit negation expression. For example, `~x`. */
class BitNotExpr extends UnaryExpr, @bitnotexpr {
override string toString() { result = "~..." }
override string getAPrimaryQlClass() { result = "BitNotExpr" }
}
/** A logical negation expression. For example, `!b`. */
class LogNotExpr extends UnaryExpr, @lognotexpr {
override string toString() { result = "!..." }
override string getAPrimaryQlClass() { result = "LogNotExpr" }
}
/** A cast expression. */
@@ -919,6 +1019,8 @@ class CastExpr extends Expr, @castexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "(...)..." }
override string getAPrimaryQlClass() { result = "CastExpr" }
}
/** A class instance creation expression. */
@@ -985,6 +1087,8 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "new " + this.getConstructor().getName() + "(...)" }
override string getAPrimaryQlClass() { result = "ClassInstanceExpr" }
}
/** A functional expression is either a lambda expression or a member reference expression. */
@@ -1026,6 +1130,8 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "...->..." }
override string getAPrimaryQlClass() { result = "LambdaExpr" }
}
/**
@@ -1054,6 +1160,8 @@ class MemberRefExpr extends FunctionalExpr, @memberref {
/** Gets a printable representation of this expression. */
override string toString() { result = "...::..." }
override string getAPrimaryQlClass() { result = "MemberRefExpr" }
}
/** A conditional expression or a `switch` expression. */
@@ -1091,6 +1199,8 @@ class ConditionalExpr extends Expr, @conditionalexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "...?...:..." }
override string getAPrimaryQlClass() { result = "ConditionalExpr" }
}
/**
@@ -1130,6 +1240,8 @@ class SwitchExpr extends Expr, @switchexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "switch (...)" }
override string getAPrimaryQlClass() { result = "SwitchExpr" }
}
/**
@@ -1173,6 +1285,8 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = "...instanceof..." }
override string getAPrimaryQlClass() { result = "InstanceOfExpr" }
}
/**
@@ -1215,6 +1329,8 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
/** Gets a printable representation of this expression. */
override string toString() { result = this.getName() }
override string getAPrimaryQlClass() { result = "LocalVariableDeclExpr" }
}
/** An update of a variable or an initialization of the variable. */
@@ -1261,6 +1377,8 @@ class TypeLiteral extends Expr, @typeliteral {
/** Gets a printable representation of this expression. */
override string toString() { result = this.getTypeName().toString() + ".class" }
override string getAPrimaryQlClass() { result = "TypeLiteral" }
}
/**
@@ -1306,6 +1424,8 @@ class ThisAccess extends InstanceAccess, @thisaccess {
override string toString() {
if exists(this.getQualifier()) then result = this.getQualifier() + ".this" else result = "this"
}
override string getAPrimaryQlClass() { result = "ThisAccess" }
}
/**
@@ -1321,6 +1441,8 @@ class SuperAccess extends InstanceAccess, @superaccess {
then result = this.getQualifier() + ".super"
else result = "super"
}
override string getAPrimaryQlClass() { result = "SuperAccess" }
}
/**
@@ -1380,6 +1502,8 @@ class VarAccess extends Expr, @varaccess {
// the qualifier is either `super` or `A.super`, where `A` is the enclosing type.
getQualifier().(InstanceAccess).isOwnInstanceAccess()
}
override string getAPrimaryQlClass() { result = "VarAccess" }
}
/**
@@ -1472,6 +1596,8 @@ class MethodAccess extends Expr, Call, @methodaccess {
* `t`-qualified `this` or `super`.
*/
predicate isEnclosingMethodAccess(RefType t) { Qualifier::enclosingMemberAccess(this, t) }
override string getAPrimaryQlClass() { result = "MethodAccess" }
}
/** A type access is a (possibly qualified) reference to a type. */
@@ -1503,6 +1629,8 @@ class TypeAccess extends Expr, Annotatable, @typeaccess {
or
not this.hasQualifier() and result = this.getType().toString()
}
override string getAPrimaryQlClass() { result = "TypeAccess" }
}
/** An array type access is a type access of the form `String[]`. */
@@ -1518,6 +1646,8 @@ class ArrayTypeAccess extends Expr, @arraytypeaccess {
/** Gets a printable representation of this expression. */
override string toString() { result = "...[]" }
override string getAPrimaryQlClass() { result = "ArrayTypeAccss" }
}
/**
@@ -1531,6 +1661,8 @@ class UnionTypeAccess extends Expr, @uniontypeaccess {
/** Gets a printable representation of this expression. */
override string toString() { result = "...|..." }
override string getAPrimaryQlClass() { result = "UnionTypeAccess" }
}
/**
@@ -1567,12 +1699,16 @@ class IntersectionTypeAccess extends Expr, @intersectiontypeaccess {
/** Gets a printable representation of this expression. */
override string toString() { result = "...&..." }
override string getAPrimaryQlClass() { result = "IntersectionTypeAccess" }
}
/** A package access. */
class PackageAccess extends Expr, @packageaccess {
/** Gets a printable representation of this expression. */
override string toString() { result = "package" }
override string getAPrimaryQlClass() { result = "PackageAccess" }
}
/** A wildcard type access, which may have either a lower or an upper bound. */
@@ -1588,6 +1724,8 @@ class WildcardTypeAccess extends Expr, @wildcardtypeaccess {
/** Gets a printable representation of this expression. */
override string toString() { result = "? ..." }
override string getAPrimaryQlClass() { result = "WildcardTypeAccess" }
}
/**

View File

@@ -28,6 +28,8 @@ class ImportType extends Import {
RefType getImportedType() { imports(this, result, _, _) }
override string toString() { result = "import " + this.getImportedType().toString() }
override string getAPrimaryQlClass() { result = "ImportType" }
}
/**
@@ -48,6 +50,8 @@ class ImportOnDemandFromType extends Import {
NestedType getAnImport() { result.getEnclosingType() = this.getTypeHoldingImport() }
override string toString() { result = "import " + this.getTypeHoldingImport().toString() + ".*" }
override string getAPrimaryQlClass() { result = "ImportOnDemandFromTypw" }
}
/**
@@ -69,6 +73,8 @@ class ImportOnDemandFromPackage extends Import {
override string toString() {
result = "import " + this.getPackageHoldingImport().toString() + ".*"
}
override string getAPrimaryQlClass() { result = "ImportOnDemandFromPackage" }
}
/**
@@ -96,6 +102,8 @@ class ImportStaticOnDemand extends Import {
override string toString() {
result = "import static " + this.getTypeHoldingImport().toString() + ".*"
}
override string getAPrimaryQlClass() { result = "ImportStaticOnDemand" }
}
/**
@@ -135,4 +143,6 @@ class ImportStaticTypeMember extends Import {
override string toString() {
result = "import static " + this.getTypeHoldingImport().toString() + "." + this.getName()
}
override string getAPrimaryQlClass() { result = "ImportStaticTypeMember" }
}

View File

@@ -411,6 +411,8 @@ class Method extends Callable, @method {
not isFinal() and
not getDeclaringType().isFinal()
}
override string getAPrimaryQlClass() { result = "Method" }
}
/** A method that is the same as its source declaration. */
@@ -504,6 +506,8 @@ class Constructor extends Callable, @constructor {
override Constructor getSourceDeclaration() { constrs(this, _, _, _, _, result) }
override string getSignature() { constrs(this, _, result, _, _, _) }
override string getAPrimaryQlClass() { result = "Constructor" }
}
/**
@@ -548,6 +552,8 @@ class FieldDeclaration extends ExprParent, @fielddecl, Annotatable {
then result = this.getTypeAccess() + " " + this.getField(0) + ";"
else result = this.getTypeAccess() + " " + this.getField(0) + ", ...;"
}
override string getAPrimaryQlClass() { result = "FieldDeclaration" }
}
/** A class or instance field. */

View File

@@ -0,0 +1,432 @@
/**
* Provides queries to pretty-print a Java AST as a graph.
*
* By default, this will print the AST for all elements in the database. To change this behavior,
* extend `PrintAstConfiguration` and override `shouldPrint` to hold for only the elements
* you wish to view the AST for.
*/
import java
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
/**
* The query can extend this class to control which elements are printed.
*/
class PrintAstConfiguration extends TPrintAstConfiguration {
/**
* Gets a textual representation of this `PrintAstConfiguration`.
*/
string toString() { result = "PrintAstConfiguration" }
/**
* Controls whether the `Element` should be considered for AST printing.
* By default it checks whether the `Element` `e` belongs to `Location` `l`.
*/
predicate shouldPrint(Element e, Location l) { e.fromSource() and l = e.getLocation() }
}
private predicate shouldPrint(Element e, Location l) {
exists(PrintAstConfiguration config | config.shouldPrint(e, l))
}
private class ExprOrStmt extends Element {
ExprOrStmt() { this instanceof Expr or this instanceof Stmt }
ExprOrStmt getParent() {
result = this.(Expr).getParent()
or
result = this.(Stmt).getParent()
}
Callable getEnclosingCallable() {
result = this.(Expr).getEnclosingCallable()
or
result = this.(Stmt).getEnclosingCallable()
}
}
/** Holds if the given element does not need to be rendered in the AST, due to being compiler-generated. */
private predicate isNotNeeded(Element el) {
exists(InitializerMethod im |
el = im
or
exists(ExprOrStmt e | e = el |
e.getEnclosingCallable() = im and
not e.getParent*() = any(Field f).getInitializer() and
not isInitBlock(im.getDeclaringType(), e.getParent*())
)
)
}
/**
* Retrieves the canonical QL class(es) for entity `el`
*/
private string getQlClass(Element el) {
result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] "
// Alternative implementation -- do not delete. It is useful for QL class discovery.
// result = "[" + concat(el.getAQlClass(), ",") + "] "
}
private predicate locationSortKeys(Element ast, string file, int line, int column) {
exists(Location loc |
loc = ast.getLocation() and
file = loc.getFile().toString() and
line = loc.getStartLine() and
column = loc.getStartColumn()
)
or
not exists(ast.getLocation()) and
file = "" and
line = 0 and
column = 0
}
/**
* Printed AST nodes are mostly `Element`s of the underlying AST.
*/
private newtype TPrintAstNode =
TElementNode(Element el) { shouldPrint(el, _) } or
TAnnotationsNode(Annotatable ann) { shouldPrint(ann, _) and ann.hasAnnotation() } or
TParametersNode(Callable c) { shouldPrint(c, _) and not c.hasNoParameters() } or
TBaseTypesNode(ClassOrInterface ty) { shouldPrint(ty, _) }
/**
* A node in the output tree.
*/
class PrintAstNode extends TPrintAstNode {
/**
* Gets a textual representation of this node in the PrintAst output tree.
*/
string toString() { none() }
/**
* Gets the child node at index `childIndex`. Child indices must be unique,
* but need not be contiguous.
*/
PrintAstNode getChild(int childIndex) { none() }
/**
* Gets a child of this node.
*/
final PrintAstNode getAChild() { result = getChild(_) }
/**
* Gets the parent of this node, if any.
*/
final PrintAstNode getParent() { result.getAChild() = this }
/**
* Gets the location of this node in the source code.
*/
Location getLocation() { none() }
/**
* Gets the value of the property of this node, where the name of the property
* is `key`.
*/
string getProperty(string key) {
key = "semmle.label" and
result = toString()
}
/**
* Gets the label for the edge from this node to the specified child. By
* default, this is just the index of the child, but subclasses can override
* this.
*/
string getChildEdgeLabel(int childIndex) {
exists(getChild(childIndex)) and
result = childIndex.toString()
}
}
/** A top-level AST node. */
class TopLevelPrintAstNode extends PrintAstNode {
TopLevelPrintAstNode() { not exists(this.getParent()) }
private int getOrder() {
this =
rank[result](TopLevelPrintAstNode n, Location l |
l = n.getLocation()
|
n
order by
l.getFile().getRelativePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn()
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and
result = this.getOrder().toString()
}
}
/**
* A node representing an AST node with an underlying `Element`.
*/
abstract class ElementNode extends PrintAstNode, TElementNode {
Element element;
ElementNode() { this = TElementNode(element) and not isNotNeeded(element) }
override string toString() { result = getQlClass(element) + element.toString() }
override Location getLocation() { result = element.getLocation() }
/**
* Gets the `Element` represented by this node.
*/
final Element getElement() { result = element }
}
/**
* An node representing an `Expr` or a `Stmt`.
*/
final class ExprStmtNode extends ElementNode {
ExprStmtNode() { element instanceof ExprOrStmt }
override PrintAstNode getChild(int childIndex) {
exists(Element el | result.(ElementNode).getElement() = el |
el.(Expr).isNthChildOf(element, childIndex)
or
el.(Stmt).isNthChildOf(element, childIndex)
or
childIndex = -4 and
el = element.(ClassInstanceExpr).getAnonymousClass()
or
childIndex = 0 and
el = element.(LocalClassDeclStmt).getLocalClass()
)
or
childIndex = -2 and
result.(AnnotationsNode).getAnnotated() = element.(LocalVariableDeclExpr).getVariable()
}
}
/**
* A node representing a `Callable`, such as method declaration.
*/
final class CallableNode extends ElementNode {
Callable callable;
CallableNode() { callable = element }
override PrintAstNode getChild(int childIndex) {
// TODO: javadoc
childIndex = 0 and
result.(AnnotationsNode).getAnnotated() = callable
or
childIndex = 1 and
result.(ElementNode).getElement().(Expr).isNthChildOf(callable, -1) // return type
or
childIndex = 2 and
result.(ParametersNode).getCallable() = callable
or
childIndex = 3 and
result.(ElementNode).getElement() = callable.getBody()
}
}
/**
* A node representing a `Parameter` of a `Callable`.
*/
final class ParameterNode extends ElementNode {
Parameter p;
ParameterNode() { p = element }
override PrintAstNode getChild(int childIndex) {
childIndex = -1 and
result.(AnnotationsNode).getAnnotated() = p
or
childIndex = 0 and
result.(ElementNode).getElement().(Expr).getParent() = p
}
}
private predicate isInitBlock(Class c, Block b) {
exists(InitializerMethod m | b.getParent() = m.getBody() and m.getDeclaringType() = c)
}
/**
* A node representing a `Class` or an `Interface`.
*/
final class ClassInterfaceNode extends ElementNode {
ClassOrInterface ty;
ClassInterfaceNode() { ty = element }
private Element getADeclaration() {
result.(Callable).getDeclaringType() = ty
or
result.(FieldDeclaration).getAField().getDeclaringType() = ty
or
result.(NestedType).getEnclosingType().getSourceDeclaration() = ty and
not result instanceof AnonymousClass and
not result instanceof LocalClass
or
isInitBlock(ty, result)
}
override PrintAstNode getChild(int childIndex) {
// TODO: generic params, javadoc?
childIndex = -2 and
result.(AnnotationsNode).getAnnotated() = ty
or
childIndex = -1 and
result.(BaseTypesNode).getClassOrInterface() = ty
or
childIndex >= 0 and
result.(ElementNode).getElement() =
rank[childIndex](Element e, string file, int line, int column |
e = getADeclaration() and locationSortKeys(e, file, line, column)
|
e order by file, line, column
)
}
}
/**
* A node representing a `FieldDeclaration`.
*/
final class FieldDeclNode extends ElementNode {
FieldDeclaration decl;
FieldDeclNode() { decl = element }
override PrintAstNode getChild(int childIndex) {
childIndex = -2 and
result.(AnnotationsNode).getAnnotated() = decl.getAField()
or
childIndex = -1 and
result.(ElementNode).getElement() = decl.getTypeAccess()
or
childIndex >= 0 and
result.(ElementNode).getElement() = decl.getField(childIndex).getInitializer()
}
}
/**
* A node representing a `CompilationUnit`.
*/
final class CompilationUnitNode extends ElementNode {
CompilationUnit cu;
CompilationUnitNode() { cu = element }
private Element getADeclaration() {
cu.hasChildElement(result)
or
result.(Import).getCompilationUnit() = cu
}
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() =
rank[childIndex](Element e, string file, int line, int column |
e = getADeclaration() and locationSortKeys(e, file, line, column)
|
e order by file, line, column
)
}
}
/**
* A node representing an `Import`.
*/
final class ImportNode extends ElementNode {
ImportNode() { element instanceof Import }
}
/**
* A node representing the annotations of an `Annotatable`.
* Only rendered if there is at least one annotation.
*/
final class AnnotationsNode extends PrintAstNode, TAnnotationsNode {
Annotatable ann;
AnnotationsNode() { this = TAnnotationsNode(ann) }
override string toString() { result = "(Annotations)" }
override Location getLocation() { result = ann.getLocation() }
override ElementNode getChild(int childIndex) {
result.getElement() =
rank[childIndex](Element e, string file, int line, int column |
e = ann.getAnAnnotation() and locationSortKeys(e, file, line, column)
|
e order by file, line, column
)
}
/**
* Gets the underlying `Annotatable`.
*/
Annotatable getAnnotated() { result = ann }
}
/**
* A node representing the parameters of a `Callable`.
* Only rendered if there is at least one parameter.
*/
final class ParametersNode extends PrintAstNode, TParametersNode {
Callable c;
ParametersNode() { this = TParametersNode(c) }
override string toString() { result = "(Parameters)" }
override Location getLocation() { result = c.getLocation() }
override ElementNode getChild(int childIndex) { result.getElement() = c.getParameter(childIndex) }
/**
* Gets the underlying `Callable`.
*/
Callable getCallable() { result = c }
}
/**
* A node representing the base types of a `Class` or `Interface` that it extends or implements.
* Only redered if there is at least one such type.
*/
final class BaseTypesNode extends PrintAstNode, TBaseTypesNode {
ClassOrInterface ty;
BaseTypesNode() { this = TBaseTypesNode(ty) and exists(TypeAccess ta | ta.getParent() = ty) }
override string toString() { result = "(Base Types)" }
override ElementNode getChild(int childIndex) {
result.getElement().(TypeAccess).isNthChildOf(ty, -2 - childIndex)
}
ClassOrInterface getClassOrInterface() { result = ty }
}
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
query predicate nodes(PrintAstNode node, string key, string value) { value = node.getProperty(key) }
/**
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
* given `value`.
*/
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
exists(int childIndex |
target = source.getChild(childIndex) and
(
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex)
or
key = "semmle.order" and value = childIndex.toString()
)
)
}
/** Holds if property `key` of the graph has the given `value`. */
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}

View File

@@ -77,7 +77,10 @@ class BlockStmt extends Stmt, @block {
override string pp() { result = "{ ... }" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "BlockStmt" }
override string getAPrimaryQlClass() { result = "BlockStmt" }
}
/**
@@ -137,6 +140,8 @@ class IfStmt extends ConditionalStmt, @ifstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "IfStmt" }
override string getAPrimaryQlClass() { result = "IfStmt" }
}
/** A `for` loop. */
@@ -202,6 +207,8 @@ class ForStmt extends ConditionalStmt, @forstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ForStmt" }
override string getAPrimaryQlClass() { result = "ForStmt" }
}
/** An enhanced `for` loop. (Introduced in Java 5.) */
@@ -220,6 +227,8 @@ class EnhancedForStmt extends Stmt, @enhancedforstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "EnhancedForStmt" }
override string getAPrimaryQlClass() { result = "EnhancedForStmt" }
}
/** A `while` loop. */
@@ -241,6 +250,8 @@ class WhileStmt extends ConditionalStmt, @whilestmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "WhileStmt" }
override string getAPrimaryQlClass() { result = "WhileStmt" }
}
/** A `do` loop. */
@@ -262,6 +273,8 @@ class DoStmt extends ConditionalStmt, @dostmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "DoStmt" }
override string getAPrimaryQlClass() { result = "DoStmt" }
}
/**
@@ -349,6 +362,8 @@ class TryStmt extends Stmt, @trystmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "TryStmt" }
override string getAPrimaryQlClass() { result = "TryStmt" }
}
/** A `catch` clause in a `try` statement. */
@@ -378,6 +393,9 @@ class CatchClause extends Stmt, @catchclause {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "CatchClause" }
override string getAPrimaryQlClass() { result = "CatchClause" }
}
/** A `switch` statement. */
@@ -411,6 +429,8 @@ class SwitchStmt extends Stmt, @switchstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "SwitchStmt" }
override string getAPrimaryQlClass() { result = "SwitchStmt" }
}
/**
@@ -472,6 +492,8 @@ class ConstCase extends SwitchCase {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ConstCase" }
override string getAPrimaryQlClass() { result = "ConstCase" }
}
/** A `default` case of a `switch` statement */
@@ -483,6 +505,8 @@ class DefaultCase extends SwitchCase {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "DefaultCase" }
override string getAPrimaryQlClass() { result = "DefaultCase" }
}
/** A `synchronized` statement. */
@@ -498,6 +522,8 @@ class SynchronizedStmt extends Stmt, @synchronizedstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "SynchronizedStmt" }
override string getAPrimaryQlClass() { result = "SynchonizedStmt" }
}
/** A `return` statement. */
@@ -510,6 +536,8 @@ class ReturnStmt extends Stmt, @returnstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ReturnStmt" }
override string getAPrimaryQlClass() { result = "ReturnStmt" }
}
/** A `throw` statement. */
@@ -552,6 +580,8 @@ class ThrowStmt extends Stmt, @throwstmt {
getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType().(RefType)) and
not this.getEnclosingStmt+() = result
}
override string getAPrimaryQlClass() { result = "ThrowStmt" }
}
/** A `break`, `yield` or `continue` statement. */
@@ -617,6 +647,8 @@ class BreakStmt extends Stmt, @breakstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "BreakStmt" }
override string getAPrimaryQlClass() { result = "BreakStmt" }
}
/**
@@ -631,6 +663,8 @@ class YieldStmt extends Stmt, @yieldstmt {
override string pp() { result = "yield ..." }
override string getHalsteadID() { result = "YieldStmt" }
override string getAPrimaryQlClass() { result = "YieldStmt" }
}
/** A `continue` statement. */
@@ -648,6 +682,8 @@ class ContinueStmt extends Stmt, @continuestmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ContinueStmt" }
override string getAPrimaryQlClass() { result = "ContinusStmt" }
}
/** The empty statement. */
@@ -657,6 +693,8 @@ class EmptyStmt extends Stmt, @emptystmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "EmptyStmt" }
override string getAPrimaryQlClass() { result = "EmptyStmt" }
}
/**
@@ -685,6 +723,8 @@ class ExprStmt extends Stmt, @exprstmt {
fdl.getStartColumn() = sl.getStartColumn()
)
}
override string getAPrimaryQlClass() { result = "ExprStmt" }
}
/** A labeled statement. */
@@ -700,6 +740,8 @@ class LabeledStmt extends Stmt, @labeledstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = this.getLabel() + ":" }
override string getAPrimaryQlClass() { result = "LabelStmt" }
}
/** An `assert` statement. */
@@ -717,6 +759,8 @@ class AssertStmt extends Stmt, @assertstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "AssertStmt" }
override string getAPrimaryQlClass() { result = "AssertStmt" }
}
/** A statement that declares one or more local variables. */
@@ -738,6 +782,8 @@ class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "LocalVariableDeclStmt" }
override string getAPrimaryQlClass() { result = "LocalVariableDeclStmt" }
}
/** A statement that declares a local class. */
@@ -750,6 +796,8 @@ class LocalClassDeclStmt extends Stmt, @localclassdeclstmt {
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "LocalClassDeclStmt" }
override string getAPrimaryQlClass() { result = "LocalClassDeclStmt" }
}
/** An explicit `this(...)` constructor invocation. */
@@ -791,6 +839,8 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ConstructorInvocationStmt" }
override string getAPrimaryQlClass() { result = "ThisConstructorInvocationStmt" }
}
/** An explicit `super(...)` constructor invocation. */
@@ -833,4 +883,6 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "SuperConstructorInvocationStmt" }
override string getAPrimaryQlClass() { result = "SuperConstructorInvocationStmt" }
}

View File

@@ -613,6 +613,8 @@ class Class extends RefType, @class {
result = this.getASupertype().(Class).getAnAnnotation()
)
}
override string getAPrimaryQlClass() { result = "Class" }
}
/**
@@ -696,6 +698,8 @@ class AnonymousClass extends NestedClass {
* the string `"<anonymous class>"` as a placeholder.
*/
override string getQualifiedName() { result = "<anonymous class>" }
override string getAPrimaryQlClass() { result = "AnonymousClass" }
}
/** A local class. */
@@ -704,6 +708,8 @@ class LocalClass extends NestedClass {
/** Gets the statement that declares this local class. */
LocalClassDeclStmt getLocalClassDeclStmt() { isLocalClass(this, result) }
override string getAPrimaryQlClass() { result = "LocalClass" }
}
/** A top-level type. */
@@ -807,6 +813,8 @@ class Interface extends RefType, @interface {
// JLS 9.1.1.1: "Every interface is implicitly abstract"
any()
}
override string getAPrimaryQlClass() { result = "Interface" }
}
/** A class or interface. */

View File

@@ -96,4 +96,6 @@ class Parameter extends Element, @param, LocalScopeVariable {
call.getCallee().getSourceDeclaration().getAParameter() = this
)
}
override string getAPrimaryQlClass() { result = "Parameter" }
}