@@ -60,16 +60,144 @@ class StmtCfgNode extends AstCfgNode {
6060 Stmt getStmt ( ) { result = s }
6161}
6262
63+ /**
64+ * A class for mapping parent-child AST nodes to parent-child CFG nodes.
65+ */
66+ abstract private class ChildMapping extends Ast {
67+ /**
68+ * Holds if `child` is a (possibly nested) child of this expression
69+ * for which we would like to find a matching CFG child.
70+ */
71+ abstract predicate relevantChild ( Ast child ) ;
72+
73+ pragma [ nomagic]
74+ abstract predicate reachesBasicBlock ( Ast child , CfgNode cfn , BasicBlock bb ) ;
75+
76+ /**
77+ * Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn`
78+ * is a control-flow node for this expression, and `cfnChild` is a control-flow
79+ * node for `child`.
80+ *
81+ * The path never escapes the syntactic scope of this expression.
82+ */
83+ cached
84+ predicate hasCfgChild ( Ast child , CfgNode cfn , CfgNode cfnChild ) {
85+ this .reachesBasicBlock ( child , cfn , cfnChild .getBasicBlock ( ) ) and
86+ cfnChild .getAstNode ( ) = child
87+ }
88+ }
89+
90+ /**
91+ * A class for mapping parent-child AST nodes to parent-child CFG nodes.
92+ */
93+ abstract private class ExprChildMapping extends Expr , ChildMapping {
94+ pragma [ nomagic]
95+ override predicate reachesBasicBlock ( Ast child , CfgNode cfn , BasicBlock bb ) {
96+ this .relevantChild ( child ) and
97+ cfn .getAstNode ( ) = this and
98+ bb .getANode ( ) = cfn
99+ or
100+ exists ( BasicBlock mid |
101+ this .reachesBasicBlock ( child , cfn , mid ) and
102+ bb = mid .getAPredecessor ( ) and
103+ not mid .getANode ( ) .getAstNode ( ) = child
104+ )
105+ }
106+ }
107+
108+ /**
109+ * A class for mapping parent-child AST nodes to parent-child CFG nodes.
110+ */
111+ abstract private class NonExprChildMapping extends ChildMapping {
112+ NonExprChildMapping ( ) { not this instanceof Expr }
113+
114+ pragma [ nomagic]
115+ override predicate reachesBasicBlock ( Ast child , CfgNode cfn , BasicBlock bb ) {
116+ this .relevantChild ( child ) and
117+ cfn .getAstNode ( ) = this and
118+ bb .getANode ( ) = cfn
119+ or
120+ exists ( BasicBlock mid |
121+ this .reachesBasicBlock ( child , cfn , mid ) and
122+ bb = mid .getASuccessor ( ) and
123+ not mid .getANode ( ) .getAstNode ( ) = child
124+ )
125+ }
126+ }
127+
63128/** Provides classes for control-flow nodes that wrap AST expressions. */
64- module ExprNodes { }
129+ module ExprNodes {
130+ private class VarAccessChildMapping extends ExprChildMapping , VarAccess {
131+ override predicate relevantChild ( Ast n ) { none ( ) }
132+ }
133+
134+ class VarAccessCfgNode extends ExprCfgNode {
135+ override string getAPrimaryQlClass ( ) { result = "VarAccessCfgNode" }
136+
137+ override VarAccessChildMapping e ;
138+
139+ override VarAccess getExpr ( ) { result = super .getExpr ( ) }
140+ }
141+
142+ private class VarReadAccessChildMapping extends VarAccessChildMapping , VarReadAccess { }
143+
144+ class VarReadAccessCfgNode extends VarAccessCfgNode {
145+ override string getAPrimaryQlClass ( ) { result = "VarReadAccessCfgNode" }
146+
147+ override VarReadAccessChildMapping e ;
148+
149+ override VarReadAccess getExpr ( ) { result = super .getExpr ( ) }
150+ }
151+
152+ private class VarWriteAccessChildMapping extends VarAccessChildMapping , VarWriteAccess { }
153+
154+ class VariableWriteAccessCfgNode extends VarAccessCfgNode {
155+ override string getAPrimaryQlClass ( ) { result = "VarWriteAccessCfgNode" }
156+
157+ override VarWriteAccessChildMapping e ;
158+
159+ override VarWriteAccess getExpr ( ) { result = super .getExpr ( ) }
160+
161+ Variable getVariable ( ) { result = e .getVariable ( ) }
162+
163+ predicate isExplicitWrite ( StmtNodes:: AssignStmtCfgNode assignment ) {
164+ this = assignment .getLeftHandSide ( )
165+ }
166+ }
167+ }
65168
66169module StmtNodes {
170+ private class CmdChildMapping extends NonExprChildMapping , Cmd {
171+ override predicate relevantChild ( Ast n ) { n = this .getElement ( _) }
172+ }
173+
67174 /** A control-flow node that wraps a `Cmd` AST expression. */
68- class CallCfgNode extends StmtCfgNode {
69- override string getAPrimaryQlClass ( ) { result = "CallCfgNode " }
175+ class CmdCfgNode extends StmtCfgNode {
176+ override string getAPrimaryQlClass ( ) { result = "CmdCfgNode " }
70177
71- override Cmd s ;
178+ override CmdChildMapping s ;
72179
73180 override Cmd getStmt ( ) { result = super .getStmt ( ) }
74181 }
182+
183+ private class AssignStmtChildMapping extends NonExprChildMapping , AssignStmt {
184+ override predicate relevantChild ( Ast n ) {
185+ n = this .getLeftHandSide ( ) or n = this .getRightHandSide ( )
186+ }
187+ }
188+
189+ /** A control-flow node that wraps an `AssignStmt` AST expression. */
190+ class AssignStmtCfgNode extends StmtCfgNode {
191+ override string getAPrimaryQlClass ( ) { result = "AssignCfgNode" }
192+
193+ override AssignStmtChildMapping s ;
194+
195+ override AssignStmt getStmt ( ) { result = super .getStmt ( ) }
196+
197+ /** Gets the LHS of this assignment. */
198+ final ExprCfgNode getLeftHandSide ( ) { s .hasCfgChild ( s .getLeftHandSide ( ) , this , result ) }
199+
200+ /** Gets the RHS of this assignment. */
201+ final StmtCfgNode getRightHandSide ( ) { s .hasCfgChild ( s .getRightHandSide ( ) , this , result ) }
202+ }
75203}
0 commit comments