diff --git a/ql/docs/learn-ql/ast.dot b/ql/docs/learn-ql/ast.dot
index eca1e0c4e7b..fbf32b744ed 100644
--- a/ql/docs/learn-ql/ast.dot
+++ b/ql/docs/learn-ql/ast.dot
@@ -1,19 +1,20 @@
digraph ast {
+ graph [dpi=300];
"x" [shape=rect];
"y" [shape=rect];
- "z" [shape=rect];
"x + y" [shape=rect];
"(x + y)" [shape=rect];
+ "z" [shape=rect];
"(x + y) * z" [shape=rect];
invis1 [style=invis];
invis2 [style=invis];
invis3 [style=invis];
- "(x + y) * z" -> "(x + y)" [label=0];
- "(x + y) * z" -> "z" [label=1];
- "(x + y)" -> "x + y" [label=0];
- "x + y" -> "x" [label=0];
- "x + y" -> "y" [label=1];
+ "(x + y) * z" -> "(x + y)" [label=" 0"];
+ "(x + y) * z" -> "z" [label=" 1"];
+ "(x + y)" -> "x + y" [label=" 0"];
+ "x + y" -> "x" [label=" 0"];
+ "x + y" -> "y" [label=" 1"];
"z" -> invis1 [style=invis];
invis1 -> invis2 [style=invis];
diff --git a/ql/docs/learn-ql/ast.png b/ql/docs/learn-ql/ast.png
index 46098b6f0d5..61a9f29b80a 100644
Binary files a/ql/docs/learn-ql/ast.png and b/ql/docs/learn-ql/ast.png differ
diff --git a/ql/docs/learn-ql/cfg.dot b/ql/docs/learn-ql/cfg.dot
index 1d4114467f0..47db3df4c57 100644
--- a/ql/docs/learn-ql/cfg.dot
+++ b/ql/docs/learn-ql/cfg.dot
@@ -1,4 +1,5 @@
digraph cfg {
+ graph [dpi=300];
rankdir=LR;
"x := 0" -> "p != nil";
"p != nil" -> "x = p.f";
diff --git a/ql/docs/learn-ql/cfg.png b/ql/docs/learn-ql/cfg.png
index 87c5187344f..1290dadb870 100644
Binary files a/ql/docs/learn-ql/cfg.png and b/ql/docs/learn-ql/cfg.png differ
diff --git a/ql/docs/learn-ql/cfg2.dot b/ql/docs/learn-ql/cfg2.dot
index 525eddb774e..b8dcd71ee25 100644
--- a/ql/docs/learn-ql/cfg2.dot
+++ b/ql/docs/learn-ql/cfg2.dot
@@ -1,4 +1,5 @@
digraph cfg2 {
+ graph [dpi=300];
rankdir=LR;
"p != nil is true" [shape=box];
diff --git a/ql/docs/learn-ql/cfg2.png b/ql/docs/learn-ql/cfg2.png
index adff43adf97..617fe4fe4dc 100644
Binary files a/ql/docs/learn-ql/cfg2.png and b/ql/docs/learn-ql/cfg2.png differ
diff --git a/ql/docs/learn-ql/dfg.dot b/ql/docs/learn-ql/dfg.dot
index 7a59581117e..82253c9b133 100644
--- a/ql/docs/learn-ql/dfg.dot
+++ b/ql/docs/learn-ql/dfg.dot
@@ -1,4 +1,5 @@
digraph dfg {
+ graph [dpi=300];
rankdir=LR;
"x" [shape=diamond];
diff --git a/ql/docs/learn-ql/dfg.png b/ql/docs/learn-ql/dfg.png
index d6c585c5e6c..6727af7b4ac 100644
Binary files a/ql/docs/learn-ql/dfg.png and b/ql/docs/learn-ql/dfg.png differ
diff --git a/ql/docs/learn-ql/introduce-libraries.rst b/ql/docs/learn-ql/introduce-libraries.rst
index 9b1b16d4568..c92f6f66c2f 100644
--- a/ql/docs/learn-ql/introduce-libraries.rst
+++ b/ql/docs/learn-ql/introduce-libraries.rst
@@ -35,6 +35,9 @@ about which function may be invoked by a given call (taking virtual dispatch thr
account), as well as control-flow information about the order in which different operations may be
executed at runtime.
+As a rule of thumb, you normally want to use the AST only for superficial syntactic queries. Any
+analysis involving deeper semantic properties of the program should be done on the DFG.
+
The rest of this tutorial briefly summarizes the most important classes and predicates provided by
this library, including references to the `detailed API documentation
`__ where applicable. We start by giving an overview of the AST
@@ -114,7 +117,7 @@ Statements
- ``CompoundAssignStmt``: an assignment statement with a compound operator, such as ``lhs += rhs``
- ``IncStmt``, ``DecStmt``: an increment statement or a decrement statement, respectively; use
- ``getExpr()`` to access the expression being incremented or decremented
+ ``getOperand()`` to access the expression being incremented or decremented
- ``BlockStmt``: a block of statements between curly braces; use ``getStmt(i)`` to access the
``i``\ th statement in a block
- ``IfStmt``: an ``if`` statement; use ``getInit()``, ``getCond()``, ``getThen()``, and
@@ -136,6 +139,8 @@ Statements
deferred
- ``SendStmt``: a send statement; use ``getChannel()`` and ``getValue()`` to access the channel and
the value being sent over the channel, respectively
+- ``RecvStmt``: a receive statement in a ``select`` statement; use ``getExpr()`` to access the
+ receiver expression, and ``getLhs(i)`` to access the ``i``\ th left-hand side
- ``ReturnStmt``: a ``return`` statement; use ``getExpr(i)`` to access the ``i``\ th returned
expression; if there is only a single returned expression you can use ``getExpr()`` instead
- ``BranchStmt``: a statement that interrupts structured control flow; use ``getLabel()`` to get the
@@ -152,7 +157,7 @@ Statements
- ``SwitchStmt``: a ``switch`` statement; use ``getInit()`` to access the (optional) init statement,
and ``getCase(i)`` to access the ``i``\ th ``case`` or ``default`` clause
- - ``ExprSwitchStmt``: a ``switch`` statement examining the value of an expression
+ - ``ExpressionSwitchStmt``: a ``switch`` statement examining the value of an expression
- ``TypeSwitchStmt``: a ``switch`` statement examining the type of an expression
- ``CaseClause``: a ``case`` or ``default`` clause in a ``switch`` statement; use ``getExpr(i)`` to
@@ -421,10 +426,10 @@ In CodeQL, data-flow nodes are represented by class ``DataFlow::Node``, and the
are captured by the predicate ``DataFlow::localFlowStep``. The predicate ``DataFlow::localFlow``
generalizes this from a single flow step to zero or more flow steps.
-Most expressions have a corresponding data-flow node (exceptions include type expressions, statement
-labels, and other expressions that do not have a value). To map from the AST node of an expression to
-the corresponding DFG node, use ``DataFlow::exprNode``. Note that the AST node and the DFG node are
-different entities and cannot be used interchangeably.
+Most expressions have a corresponding data-flow node; exceptions include type expressions, statement
+labels and other expressions that do not have a value, as well as short-circuiting operators. To map
+from the AST node of an expression to the corresponding DFG node, use ``DataFlow::exprNode``. Note
+that the AST node and the DFG node are different entities and cannot be used interchangeably.
There is also a predicate ``asExpr()`` on ``DataFlow::Node`` that allows you to recover the
expression underlying a DFG node. However, this predicate should be used with caution, since many
@@ -445,16 +450,17 @@ Important subclasses of ``DataFlow::Node`` include:
corresponding AST node
- ``DataFlow::BinaryOperationNode``: an operation involving a binary operator; each ``BinaryExpr``
has a corresponding ``BinaryOperationNode``, but there are also binary operations that are not
- explicit at the AST level, such as those arising from compound assignments and increment/
- decrement statements; at the AST level, ``x + 1``, ``x += 1``, and ``x++`` are represented by
- different kinds of AST nodes, while at the DFG level they are all modeled as a binary
- operation node with operands ``x`` and ``1``
+ explicit at the AST level, such as those arising from compound assignments and
+ increment/decrement statements; at the AST level, ``x + 1``, ``x += 1``, and ``x++`` are
+ represented by different kinds of AST nodes, while at the DFG level they are all modeled as a
+ binary operation node with operands ``x`` and ``1``
- ``DataFlow::UnaryOperationNode``: analogous, but for unary operators
- - ``DataFlow::PointerDereferenceNode``: a pointer dereference, either explicit in an expression of
- the form ``*p``, or implicit in a field or method reference through a pointer
- - ``DataFlow::AddressOperationNode``: analogous, but for taking the address of an entity
- - ``DataFlow::RelationalComparisonNode``, ``DataFlow::EqualityTestNode``: data-flow nodes
- corresponding to ``RelationalComparisonExpr`` and ``EqualityTestExpr`` AST nodes
+
+ - ``DataFlow::PointerDereferenceNode``: a pointer dereference, either explicit in an expression
+ of the form ``*p``, or implicit in a field or method reference through a pointer
+ - ``DataFlow::AddressOperationNode``: analogous, but for taking the address of an entity
+ - ``DataFlow::RelationalComparisonNode``, ``DataFlow::EqualityTestNode``: data-flow nodes
+ corresponding to ``RelationalComparisonExpr`` and ``EqualityTestExpr`` AST nodes
Finally, classes ``Read`` and ``Write`` represent, respectively, a read or a write of a variable, a
field, or an element of an array, a slice or a map. Use their member predicates ``readsVariable``,
diff --git a/ql/docs/learn-ql/ssa.dot b/ql/docs/learn-ql/ssa.dot
index f33579ad51d..c8bfb8c62a0 100644
--- a/ql/docs/learn-ql/ssa.dot
+++ b/ql/docs/learn-ql/ssa.dot
@@ -1,4 +1,5 @@
digraph ssa {
+ graph [dpi=300];
rankdir=LR;
"x1" [shape=diamond,label=1>];
diff --git a/ql/docs/learn-ql/ssa.png b/ql/docs/learn-ql/ssa.png
index a29bbe4633b..cd5ba3f29de 100644
Binary files a/ql/docs/learn-ql/ssa.png and b/ql/docs/learn-ql/ssa.png differ
diff --git a/ql/src/InconsistentCode/ConstantLengthComparison.ql b/ql/src/InconsistentCode/ConstantLengthComparison.ql
index bc4c9b0aa00..6058e287dec 100644
--- a/ql/src/InconsistentCode/ConstantLengthComparison.ql
+++ b/ql/src/InconsistentCode/ConstantLengthComparison.ql
@@ -16,7 +16,7 @@ from
ControlFlow::ConditionGuardNode cond, DataFlow::CallNode lenA
where
// `i` is incremented in `fs`
- fs.getPost().(IncStmt).getExpr() = i.getAReference() and
+ fs.getPost().(IncStmt).getOperand() = i.getAReference() and
// `idx` reads `a[i]`
idx.reads(a.getANode(), i.getARead()) and
// `lenA` is `len(a)`
diff --git a/ql/src/InconsistentCode/InconsistentLoopOrientation.ql b/ql/src/InconsistentCode/InconsistentLoopOrientation.ql
index 7eea9dbbeab..fa5051ed5c7 100644
--- a/ql/src/InconsistentCode/InconsistentLoopOrientation.ql
+++ b/ql/src/InconsistentCode/InconsistentLoopOrientation.ql
@@ -36,7 +36,7 @@ predicate bounds(RelationalComparisonExpr test, Variable v, string direction) {
* downward.
*/
predicate updates(IncDecStmt upd, Variable v, string direction) {
- upd.getExpr() = v.getAReference() and
+ upd.getOperand() = v.getAReference() and
(
upd instanceof IncStmt and direction = "upward"
or
diff --git a/ql/src/semmle/go/Expr.qll b/ql/src/semmle/go/Expr.qll
index 2ccd8f8f565..fa8de1369d3 100644
--- a/ql/src/semmle/go/Expr.qll
+++ b/ql/src/semmle/go/Expr.qll
@@ -1253,7 +1253,7 @@ class ReferenceExpr extends Expr {
predicate isLvalue() {
this = any(Assignment assgn).getLhs(_)
or
- this = any(IncDecStmt ids).getExpr()
+ this = any(IncDecStmt ids).getOperand()
or
exists(RangeStmt rs |
this = rs.getKey() or
@@ -1271,7 +1271,7 @@ class ReferenceExpr extends Expr {
or
this = any(CompoundAssignStmt cmp).getLhs(_)
or
- this = any(IncDecStmt ids).getExpr()
+ this = any(IncDecStmt ids).getOperand()
}
}
diff --git a/ql/src/semmle/go/Stmt.qll b/ql/src/semmle/go/Stmt.qll
index a0d84869556..7a1a951c974 100644
--- a/ql/src/semmle/go/Stmt.qll
+++ b/ql/src/semmle/go/Stmt.qll
@@ -103,8 +103,8 @@ class SendStmt extends @sendstmt, Stmt {
* An increment or decrement statement.
*/
class IncDecStmt extends @incdecstmt, Stmt {
- /** Gets the expression. */
- Expr getExpr() { result = getChildExpr(0) }
+ /** Gets the expression being incremented or decremented. */
+ Expr getOperand() { result = getChildExpr(0) }
/** Gets the increment or decrement operator. */
string getOperator() { none() }
diff --git a/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll b/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll
index f02df29cc8a..d86f717dbc9 100644
--- a/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll
+++ b/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll
@@ -309,7 +309,7 @@ newtype TWriteTarget =
)
)
or
- exists(IncDecStmt ids | write = MkIncDecNode(ids) | lhs = ids.getExpr().stripParens())
+ exists(IncDecStmt ids | write = MkIncDecNode(ids) | lhs = ids.getOperand().stripParens())
or
exists(ParameterOrReceiver parm | write = MkParameterInit(parm) | lhs = parm.getDeclaration())
or
@@ -1385,7 +1385,7 @@ module CFG {
}
private class IncDecTree extends ControlFlowTree, IncDecStmt {
- override predicate firstNode(ControlFlow::Node first) { firstNode(getExpr(), first) }
+ override predicate firstNode(ControlFlow::Node first) { firstNode(getOperand(), first) }
override predicate lastNode(ControlFlow::Node last, Completion cmpl) {
ControlFlowTree.super.lastNode(last, cmpl)
@@ -1395,7 +1395,7 @@ module CFG {
}
override predicate succ(ControlFlow::Node pred, ControlFlow::Node succ) {
- lastNode(getExpr(), pred, normalCompletion()) and
+ lastNode(getOperand(), pred, normalCompletion()) and
succ = MkImplicitOne(this)
or
pred = MkImplicitOne(this) and
diff --git a/ql/src/semmle/go/controlflow/IR.qll b/ql/src/semmle/go/controlflow/IR.qll
index bca948f9f7d..b3c655b12b7 100644
--- a/ql/src/semmle/go/controlflow/IR.qll
+++ b/ql/src/semmle/go/controlflow/IR.qll
@@ -843,7 +843,7 @@ module IR {
/** Gets the corresponding increment or decrement statement. */
IncDecStmt getStmt() { result = ids }
- override Type getResultType() { result = ids.getExpr().getType() }
+ override Type getResultType() { result = ids.getOperand().getType() }
override ControlFlow::Root getRoot() { result.isRootOf(ids) }
@@ -867,7 +867,7 @@ module IR {
/** Gets the corresponding increment or decrement statement. */
IncDecStmt getStmt() { result = ids }
- override Type getResultType() { result = ids.getExpr().getType() }
+ override Type getResultType() { result = ids.getOperand().getType() }
override ControlFlow::Root getRoot() { result.isRootOf(ids) }
diff --git a/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll b/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll
index 466a18d8b04..4bdf572789f 100644
--- a/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll
+++ b/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll
@@ -536,7 +536,7 @@ class BinaryOperationNode extends Node {
exists(IR::EvalIncDecRhsInstruction rhs, IncDecStmt ids |
rhs = asInstruction() and ids = rhs.getStmt()
|
- left = exprNode(ids.getExpr()) and
+ left = exprNode(ids.getOperand()) and
right = instructionNode(any(IR::EvalImplicitOneInstruction one | one.getStmt() = ids)) and
op = ids.getOperator().charAt(0)
)