C++: Move a bunch non-public dataflow node subtypes.

This commit is contained in:
Mathias Vorreiter Pedersen
2026-02-27 11:56:20 +00:00
parent edde4149aa
commit 6e0c5615fe
2 changed files with 856 additions and 1142 deletions

View File

@@ -946,3 +946,859 @@ module Public {
}
private import Public
/**
* A node representing an indirection of a parameter.
*/
final class IndirectParameterNode = AbstractIndirectParameterNode;
/**
* A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
*/
private class Node0 extends Node, TNode0 {
Node0Impl node;
Node0() { this = TNode0(node) }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override Declaration getFunction() { result = node.getFunction() }
override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = node.toString() }
override Type getType() { result = node.getType() }
override predicate isGLValue() { node.isGLValue() }
}
class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
int indirectionIndex;
Operand operand;
PostUpdateNodeImpl() { this = TPostUpdateNodeImpl(operand, indirectionIndex) }
override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
override DataFlowCallable getEnclosingCallable() {
result = this.getPreUpdateNode().getEnclosingCallable()
}
/** Gets the operand associated with this node. */
Operand getOperand() { result = operand }
/** Gets the indirection index associated with this node. */
override int getIndirectionIndex() { result = indirectionIndex }
override Location getLocationImpl() { result = operand.getLocation() }
final override Node getPreUpdateNode() {
indirectionIndex > 0 and
hasOperandAndIndex(result, operand, indirectionIndex)
or
indirectionIndex = 0 and
result.asOperand() = operand
}
final override Expr getDefinedExpr() {
result = operand.getDef().getUnconvertedResultExpression()
}
}
/**
* The node representing the value of a field after it has been updated.
*/
class PostFieldUpdateNode extends PostUpdateNodeImpl {
FieldAddress fieldAddress;
PostFieldUpdateNode() { operand = fieldAddress.getObjectAddressOperand() }
FieldAddress getFieldAddress() { result = fieldAddress }
Field getUpdatedField() { result = this.getFieldAddress().getField() }
override string toStringImpl() { result = this.getPreUpdateNode() + " [post update]" }
}
/**
* The base class for nodes that perform "partial definitions".
*
* In contrast to a normal "definition", which provides a new value for
* something, a partial definition is an expression that may affect a
* value, but does not necessarily replace it entirely. For example:
* ```
* x.y = 1; // a partial definition of the object `x`.
* x.y.z = 1; // a partial definition of the object `x.y` and `x`.
* x.setY(1); // a partial definition of the object `x`.
* setY(&x); // a partial definition of the object `x`.
* ```
*/
abstract private class PartialDefinitionNode extends PostUpdateNode {
/** Gets the indirection index of this node. */
abstract int getIndirectionIndex();
/** Gets the expression that is partially defined by this node. */
abstract Expr getDefinedExpr();
}
/**
* A node representing the indirection of a value after it
* has been returned from a function.
*/
class IndirectArgumentOutNode extends PostUpdateNodeImpl {
override ArgumentOperand operand;
int getArgumentIndex() {
exists(CallInstruction call | call.getArgumentOperand(result) = operand)
}
Operand getAddressOperand() { result = operand }
CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand }
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
override string toStringImpl() {
exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
// This string should be unique enough to be helpful but common enough to
// avoid storing too many different strings.
result = prefix + this.getStaticCallTarget().getName() + " output argument"
or
not exists(this.getStaticCallTarget()) and
result = prefix + "output argument"
)
}
}
/**
* Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
* `operand` represents a use of the fully converted value of `call`.
*/
private predicate hasOperand(Node node, CallInstruction call, int indirectionIndex, Operand operand) {
operandForFullyConvertedCall(operand, call) and
hasOperandAndIndex(node, operand, indirectionIndex)
}
/**
* Holds if `node` is an indirect instruction with columns `(instr, indirectionIndex)`, and
* `instr` represents a use of the fully converted value of `call`.
*
* Note that `hasOperand(node, _, _, _)` implies `not hasInstruction(node, _, _, _)`.
*/
private predicate hasInstruction(
Node node, CallInstruction call, int indirectionIndex, Instruction instr
) {
instructionForFullyConvertedCall(instr, call) and
hasInstructionAndIndex(node, instr, indirectionIndex)
}
/**
* A node representing the indirect value of a function call (i.e., a value hidden
* behind a number of indirections).
*/
class IndirectReturnOutNode extends Node {
CallInstruction call;
int indirectionIndex;
IndirectReturnOutNode() {
// Annoyingly, we need to pick the fully converted value as the output of the function to
// make flow through in the shared dataflow library work correctly.
hasOperand(this, call, indirectionIndex, _)
or
hasInstruction(this, call, indirectionIndex, _)
}
CallInstruction getCallInstruction() { result = call }
int getIndirectionIndex() { result = indirectionIndex }
/** Gets the operand associated with this node, if any. */
Operand getOperand() { hasOperand(this, call, indirectionIndex, result) }
/** Gets the instruction associated with this node, if any. */
Instruction getInstruction() { hasInstruction(this, call, indirectionIndex, result) }
}
/**
* An `IndirectReturnOutNode` which is used as a destination of a store operation.
* When it's used for a store operation it's useful to have this be a `PostUpdateNode` for
* the shared dataflow library's flow-through mechanism to detect flow in cases such as:
* ```cpp
* struct MyInt {
* int i;
* int& getRef() { return i; }
* };
* ...
* MyInt mi;
* mi.getRef() = source(); // this is detected as a store to `i` via flow-through.
* sink(mi.i);
* ```
*/
private class PostIndirectReturnOutNode extends IndirectReturnOutNode, PostUpdateNode {
PostIndirectReturnOutNode() {
any(StoreInstruction store).getDestinationAddressOperand() = this.getOperand()
}
override Node getPreUpdateNode() { result = this }
}
/**
* A node that represents the indirect value of an operand in the IR
* after `index` number of loads.
*/
private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
Node0Impl node;
int indirectionIndex;
RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
/** Gets the underlying instruction. */
Operand getOperand() { result = node.asOperand() }
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
override Declaration getFunction() { result = node.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override predicate isGLValue() { this.getOperand().isGLValue() }
override Type getType() {
exists(int sub, Type type, boolean isGLValue |
type = getOperandType(this.getOperand(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0
|
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
)
}
final override Location getLocationImpl() {
if exists(this.getOperand().getLocation())
then result = this.getOperand().getLocation()
else result instanceof UnknownLocation
}
override string toStringImpl() {
result = stars(this) + operandNode(this.getOperand()).toStringImpl()
}
}
/**
* A node that represents the indirect value of an instruction in the IR
* after `index` number of loads.
*/
private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
Node0Impl node;
int indirectionIndex;
RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
/** Gets the underlying instruction. */
Instruction getInstruction() { result = node.asInstruction() }
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
override Declaration getFunction() { result = node.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = node.getEnclosingCallable()
}
override predicate isGLValue() { this.getInstruction().isGLValue() }
override Type getType() {
exists(int sub, Type type, boolean isGLValue |
type = getInstructionType(this.getInstruction(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0
|
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
)
}
final override Location getLocationImpl() {
if exists(this.getInstruction().getLocation())
then result = this.getInstruction().getLocation()
else result instanceof UnknownLocation
}
override string toStringImpl() {
result = stars(this) + instructionNode(this.getInstruction()).toStringImpl()
}
}
/**
* A node that represents the indirect value of an operand in the IR
* after a number of loads.
*/
class RawIndirectOperand extends Node {
int indirectionIndex;
Operand operand;
RawIndirectOperand() {
exists(Node0Impl node | operand = node.asOperand() |
this = TRawIndirectOperand0(node, indirectionIndex)
or
this = TRawIndirectInstruction0(node, indirectionIndex)
)
}
/** Gets the operand associated with this node. */
Operand getOperand() { result = operand }
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
}
/**
* A node that represents the indirect value of an instruction in the IR
* after a number of loads.
*/
class RawIndirectInstruction extends Node {
int indirectionIndex;
Instruction instr;
RawIndirectInstruction() {
exists(Node0Impl node | instr = node.asInstruction() |
this = TRawIndirectOperand0(node, indirectionIndex)
or
this = TRawIndirectInstruction0(node, indirectionIndex)
)
}
/** Gets the instruction associated with this node. */
Instruction getInstruction() { result = instr }
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
}
/**
* A synthesized SSA node produced by the shared SSA library, viewed as a node
* in a data flow graph.
*/
class SsaSynthNode extends Node, TSsaSynthNode {
SsaImpl::SynthNode node;
SsaSynthNode() { this = TSsaSynthNode(node) }
/** Gets the synthesized SSA node associated with this node. */
SsaImpl::SynthNode getSynthNode() { result = node }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
override Type getType() { result = node.getSourceVariable().getType() }
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
final override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = node.toString() }
}
/**
* Dataflow nodes necessary for iterator flow
*/
class SsaIteratorNode extends Node, TSsaIteratorNode {
IteratorFlow::IteratorFlowNode node;
SsaIteratorNode() { this = TSsaIteratorNode(node) }
/** Gets the phi node associated with this node. */
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = node.getFunction() }
override Type getType() { result = node.getType() }
final override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = node.toString() }
}
/**
* A node representing a value after leaving a function.
*/
class SideEffectOperandNode extends Node instanceof IndirectOperand {
CallInstruction call;
int argumentIndex;
ArgumentOperand arg;
SideEffectOperandNode() {
arg = call.getArgumentOperand(argumentIndex) and
IndirectOperand.super.hasOperandAndIndirectionIndex(arg, _)
}
CallInstruction getCallInstruction() { result = call }
/** Gets the underlying operand and the underlying indirection index. */
predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex)
}
int getArgumentIndex() { result = argumentIndex }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = call.getEnclosingFunction() }
Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
}
/**
* A node representing the value of a global variable just before returning
* from a function body.
*/
class FinalGlobalValue extends Node, TFinalGlobalValue {
SsaImpl::GlobalUse globalUse;
FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
/** Gets the underlying SSA use. */
SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
override Type getType() {
exists(int indirectionIndex |
indirectionIndex = globalUse.getIndirectionIndex() and
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
)
}
final override Location getLocationImpl() { result = globalUse.getLocation() }
override string toStringImpl() { result = globalUse.toString() }
}
/**
* A node representing the value of a global variable just after entering
* a function body.
*/
class InitialGlobalValue extends Node, TInitialGlobalValue {
SsaImpl::GlobalDef globalDef;
InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
/** Gets the underlying SSA definition. */
SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = globalDef.getFunction() }
final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
override Type getType() { result = globalDef.getUnderlyingType() }
final override Location getLocationImpl() { result = globalDef.getLocation() }
override string toStringImpl() { result = globalDef.toString() }
}
/**
* A node representing a parameter for a function with no body.
*/
class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
Parameter p;
int indirectionIndex;
BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = p.getFunction() }
/** Gets the indirection index of this node. */
int getIndirectionIndex() { result = indirectionIndex }
override Type getType() {
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
}
final override Location getLocationImpl() {
result = unique( | | p.getLocation())
or
count(p.getLocation()) != 1 and
result instanceof UnknownLocation
}
final override string toStringImpl() {
exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
}
}
/**
* A data-flow node used to model flow summaries. That is, a dataflow node
* that is synthesized to represent a parameter, return value, or other part
* of a models-as-data modeled function.
*/
class FlowSummaryNode extends Node, TFlowSummaryNode {
/**
* Gets the models-as-data `SummaryNode` associated with this dataflow
* `FlowSummaryNode`.
*/
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
/**
* Gets the summarized callable that this node belongs to.
*/
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
result = this.getSummaryNode().getSummarizedCallable()
}
/**
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
* summarized function this node is part of.
*/
override DataFlowCallable getEnclosingCallable() {
result.asSummarizedCallable() = this.getSummarizedCallable()
}
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
override string toStringImpl() { result = this.getSummaryNode().toString() }
}
/**
* A node representing the indirection of a value that is
* about to be returned from a function.
*/
class IndirectReturnNode extends Node {
IndirectReturnNode() {
this instanceof FinalParameterNode
or
this.(IndirectOperand)
.hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
}
override SourceCallable getEnclosingCallable() { result.asSourceCallable() = this.getFunction() }
/**
* Holds if this node represents the value that is returned to the caller
* through a `return` statement.
*/
predicate isNormalReturn() { this instanceof IndirectOperand }
/**
* Holds if this node represents the value that is returned to the caller
* by writing to the `argumentIndex`'th argument of the call.
*/
predicate isParameterReturn(int argumentIndex) {
this.(FinalParameterNode).getArgumentIndex() = argumentIndex
}
/** Gets the indirection index of this indirect return node. */
int getIndirectionIndex() {
result = this.(FinalParameterNode).getIndirectionIndex()
or
this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result)
}
}
/**
* A node representing the value of an output parameter
* just before reaching the end of a function.
*/
class FinalParameterNode extends Node, TFinalParameterNode {
Parameter p;
int indirectionIndex;
FinalParameterNode() { this = TFinalParameterNode(p, indirectionIndex) }
/** Gets the parameter associated with this final use. */
Parameter getParameter() { result = p }
/** Gets the underlying indirection index. */
int getIndirectionIndex() { result = indirectionIndex }
/** Gets the argument index associated with this final use. */
final int getArgumentIndex() { result = p.getIndex() }
override Declaration getFunction() { result = p.getFunction() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
final override Location getLocationImpl() {
// Parameters can have multiple locations. When there's a unique location we use
// that one, but if multiple locations exist we default to an unknown location.
result = unique( | | p.getLocation())
or
not exists(unique( | | p.getLocation())) and
result instanceof UnknownLocation
}
override string toStringImpl() { result = stars(this) + p.toString() }
}
abstract private class AbstractParameterNode extends Node {
/**
* Holds if this node is the parameter of `f` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
predicate isSourceParameterOf(Function f, ParameterPosition pos) { none() }
/**
* Holds if this node is the parameter of `sc` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
predicate isSummaryParameterOf(
FlowSummaryImpl::Public::SummarizedCallable sc, ParameterPosition pos
) {
none()
}
/**
* Holds if this node is the parameter of `c` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
final predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.isSummaryParameterOf(c.asSummarizedCallable(), pos)
or
this.isSourceParameterOf(c.asSourceCallable(), pos)
}
/** Gets the `Parameter` associated with this node, if it exists. */
Parameter getParameter() { none() } // overridden by subclasses
}
abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
/** Gets the indirection index of this parameter node. */
abstract int getIndirectionIndex();
}
pragma[noinline]
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
) {
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
node.getArgumentIndex() = argumentIndex
}
pragma[noinline]
private predicate indirectPositionHasArgumentIndexAndIndex(
IndirectionPosition pos, int argumentIndex, int indirectionIndex
) {
pos.getArgumentIndex() = argumentIndex and
pos.getIndirectionIndex() = indirectionIndex
}
private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
{
InitializeParameterInstruction init;
IndirectInstructionParameterNode() {
IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _)
}
int getArgumentIndex() { init.hasIndex(result) }
override string toStringImpl() {
exists(string prefix | prefix = stars(this) |
result = prefix + this.getParameter().toString()
or
not exists(this.getParameter()) and
result = prefix + "this"
)
}
/** Gets the parameter whose indirection is initialized. */
override Parameter getParameter() { result = init.getParameter() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
}
override Declaration getFunction() { result = init.getEnclosingFunction() }
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
this.getFunction() = f and
exists(int argumentIndex, int indirectionIndex |
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
)
}
/** Gets the underlying operand and the underlying indirection index. */
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
}
final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
}
abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
/**
* A non-indirect parameter node that is represented as an `Instruction`.
*/
abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
final override InitializeParameterInstruction instr;
/**
* Gets the `IRVariable` that this parameter references.
*/
final IRVariable getIRVariable() { result = instr.getIRVariable() }
}
abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
/** An explicit positional parameter, not including `this` or `...`. */
private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
InstructionDirectParameterNode
{
ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
f.getParameter(pos.(DirectPosition).getArgumentIndex()) = instr.getParameter()
}
override string toStringImpl() { result = instr.getParameter().toString() }
override Parameter getParameter() { result = instr.getParameter() }
}
/**
* A parameter node that is part of a summary.
*/
class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
SummaryParameterNode() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
}
private ParameterPosition getPosition() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
}
override predicate isSummaryParameterOf(
FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
) {
c = this.getSummarizedCallable() and
p = this.getPosition()
}
}
private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
BodyLessParameterNodeImpl
{
DirectBodyLessParameterNode() { indirectionIndex = 0 }
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
this.getFunction() = f and
f.getParameter(pos.(DirectPosition).getArgumentIndex()) = p
}
override Parameter getParameter() { result = p }
}
private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
BodyLessParameterNodeImpl
{
IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
exists(int argumentPosition |
this.getFunction() = f and
f.getParameter(argumentPosition) = p and
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex)
)
}
override int getIndirectionIndex() {
result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
}
override Parameter getParameter() { result = p }
}
/**
* A `PostUpdateNode` that is part of a flow summary. These are synthesized,
* for example, when a models-as-data summary models a write to a field since
* the write needs to target a `PostUpdateNode`.
*/
class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
SummaryPostUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), _)
}
override Node getPreUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(),
result.(FlowSummaryNode).getSummaryNode())
}
}
/**
* Returns `t`, but stripped of the outermost pointer, reference, etc.
*
* For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
*/
private Type stripPointer(Type t) {
result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
or
result = t.(PointerToMemberType).getBaseType()
or
result = t.(FunctionPointerIshType).getBaseType()
}
/**
* Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
*/
private Type getTypeImpl0(Type t, int indirectionIndex) {
indirectionIndex = 0 and
result = t
or
indirectionIndex > 0 and
exists(Type stripped |
stripped = stripPointer(t.stripTopLevelSpecifiers()) and
stripped.getUnspecifiedType() != t.getUnspecifiedType() and
result = getTypeImpl0(stripped, indirectionIndex - 1)
)
}
/**
* Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
*
* If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
*/
bindingset[t, indirectionIndex]
pragma[inline_late]
Type getTypeImpl(Type t, int indirectionIndex) {
result = getTypeImpl0(t, indirectionIndex)
or
not exists(getTypeImpl0(t, indirectionIndex)) and
result instanceof UnknownType
}