C++: Refactor to separate out InstructionNode

This commit prepares the IR data-flow library for having more than one
type of data-flow node.
This commit is contained in:
Jonas Jensen
2020-02-04 10:32:38 +01:00
parent b5f3d776bf
commit 73e34f1447
2 changed files with 50 additions and 34 deletions

View File

@@ -7,17 +7,17 @@ private import DataFlowDispatch
* A data flow node that occurs as the argument of a call and is passed as-is
* to the callable. Instance arguments (`this` pointer) are also included.
*/
class ArgumentNode extends Node {
ArgumentNode() { exists(CallInstruction call | this.asInstruction() = call.getAnArgument()) }
class ArgumentNode extends InstructionNode {
ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) }
/**
* Holds if this argument occurs at the given position in the given call.
* The instance argument is considered to have index `-1`.
*/
predicate argumentOf(DataFlowCall call, int pos) {
this.asInstruction() = call.getPositionalArgument(pos)
this.getInstruction() = call.getPositionalArgument(pos)
or
this.asInstruction() = call.getThisArgument() and pos = -1
this.getInstruction() = call.getThisArgument() and pos = -1
}
/** Gets the call in which this node is an argument. */
@@ -36,15 +36,15 @@ class ReturnKind extends TReturnKind {
}
/** A data flow node that occurs as the result of a `ReturnStmt`. */
class ReturnNode extends Node {
ReturnNode() { exists(ReturnValueInstruction ret | this.asInstruction() = ret.getReturnValue()) }
class ReturnNode extends InstructionNode {
ReturnNode() { exists(ReturnValueInstruction ret | this.getInstruction() = ret.getReturnValue()) }
/** Gets the kind of this returned value. */
ReturnKind getKind() { result = TNormalReturnKind() }
}
/** A data flow node that represents the output of a call. */
class OutNode extends Node {
class OutNode extends InstructionNode {
override CallInstruction instr;
/** Gets the underlying call. */
@@ -181,7 +181,7 @@ private predicate suppressUnusedType(Type t) { any() }
// Java QL library compatibility wrappers
//////////////////////////////////////////////////////////////////////////////
/** A node that performs a type cast. */
class CastNode extends Node {
class CastNode extends InstructionNode {
CastNode() { none() } // stub implementation
}

View File

@@ -13,7 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
* `Instruction`. This ensures we can add `Node`s that are not `Instruction`s
* in the future.
*/
private newtype TIRDataFlowNode = MkIRDataFlowNode(Instruction i)
private newtype TIRDataFlowNode = TInstructionNode(Instruction i)
/**
* A node in a data flow graph.
@@ -23,21 +23,19 @@ private newtype TIRDataFlowNode = MkIRDataFlowNode(Instruction i)
* `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
*/
class Node extends TIRDataFlowNode {
Instruction instr;
Node() { this = MkIRDataFlowNode(instr) }
/**
* INTERNAL: Do not use. Alternative name for `getFunction`.
*/
Function getEnclosingCallable() { result = this.getFunction() }
Function getFunction() { result = instr.getEnclosingFunction() }
/** Gets the function to which this node belongs. */
Function getFunction() { none() } // overridden in subclasses
/** Gets the type of this node. */
Type getType() { result = instr.getResultType() }
Type getType() { none() } // overridden in subclasses
Instruction asInstruction() { this = MkIRDataFlowNode(result) }
/** Gets the instruction corresponding to this node, if any. */
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
@@ -45,22 +43,19 @@ class Node extends TIRDataFlowNode {
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
Expr asExpr() {
result.getConversion*() = instr.getConvertedResultExpression() and
not result instanceof Conversion
}
Expr asExpr() { result = this.(ExprNode).getExpr() }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
Expr asConvertedExpr() { result = instr.getConvertedResultExpression() }
Expr asConvertedExpr() { result = this.(ExprNode).getConvertedExpr() }
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
/** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() }
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
/**
* DEPRECATED: See UninitializedNode.
@@ -76,7 +71,7 @@ class Node extends TIRDataFlowNode {
Type getTypeBound() { result = getType() }
/** Gets the location of this element. */
Location getLocation() { result = instr.getLocation() }
Location getLocation() { none() } // overridden by subclasses
/**
* Holds if this element is at the specified location.
@@ -91,18 +86,36 @@ class Node extends TIRDataFlowNode {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
string toString() {
/** Gets a textual representation of this element. */
string toString() { none() } // overridden by subclasses
}
class InstructionNode extends Node, TInstructionNode {
Instruction instr;
InstructionNode() { this = TInstructionNode(instr) }
/** Gets the instruction corresponding to this node. */
Instruction getInstruction() { result = instr }
override Function getFunction() { result = instr.getEnclosingFunction() }
override Type getType() { result = instr.getResultType() }
override Location getLocation() { result = instr.getLocation() }
override string toString() {
// This predicate is overridden in subclasses. This default implementation
// does not use `Instruction.toString` because that's expensive to compute.
result = this.asInstruction().getOpcode().toString()
result = this.getInstruction().getOpcode().toString()
}
}
/**
* An expression, viewed as a node in a data flow graph.
*/
class ExprNode extends Node {
ExprNode() { exists(this.asExpr()) }
class ExprNode extends InstructionNode {
ExprNode() { exists(instr.getConvertedResultExpression()) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
@@ -110,13 +123,16 @@ class ExprNode extends Node {
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
Expr getExpr() { result = this.asExpr() }
Expr getExpr() {
result.getConversion*() = instr.getConvertedResultExpression() and
not result instanceof Conversion
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
Expr getConvertedExpr() { result = this.asConvertedExpr() }
Expr getConvertedExpr() { result = instr.getConvertedResultExpression() }
override string toString() { result = this.asConvertedExpr().toString() }
}
@@ -125,7 +141,7 @@ class ExprNode extends Node {
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node {
class ParameterNode extends InstructionNode {
override InitializeParameterInstruction instr;
/**
@@ -139,7 +155,7 @@ class ParameterNode extends Node {
override string toString() { result = instr.getParameter().toString() }
}
private class ThisParameterNode extends Node {
private class ThisParameterNode extends InstructionNode {
override InitializeThisInstruction instr;
override string toString() { result = "this" }
@@ -176,7 +192,7 @@ deprecated class UninitializedNode extends Node {
* This class exists to match the interface used by Java. There are currently no non-abstract
* classes that extend it. When we implement field flow, we can revisit this.
*/
abstract class PostUpdateNode extends Node {
abstract class PostUpdateNode extends InstructionNode {
/**
* Gets the node before the state update.
*/
@@ -193,7 +209,7 @@ abstract class PostUpdateNode extends Node {
* returned. This node will have its `getArgument()` equal to `&x` and its
* `getVariableAccess()` equal to `x`.
*/
class DefinitionByReferenceNode extends Node {
class DefinitionByReferenceNode extends InstructionNode {
override WriteSideEffectInstruction instr;
/** Gets the argument corresponding to this node. */
@@ -223,7 +239,7 @@ class DefinitionByReferenceNode extends Node {
/**
* Gets the node corresponding to `instr`.
*/
Node instructionNode(Instruction instr) { result.asInstruction() = instr }
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }