Skip to content

Commit 83fc421

Browse files
Copilotaschackmull
authored andcommitted
Cfg: Add consistency queries for the Ast module.
1 parent cfa1753 commit 83fc421

4 files changed

Lines changed: 184 additions & 0 deletions

File tree

csharp/ql/consistency-queries/AstConsistency.qll renamed to csharp/ql/consistency-queries/AstConsistency.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import csharp
2+
import ControlFlow::AstConsistency
23

34
query predicate missingLocation(Element e) {
45
(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import java
2+
import ControlFlow::AstConsistency
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
* Provides consistency queries for `AstSig`.
3+
*/
4+
overlay[local?]
5+
module;
6+
7+
private import codeql.util.Location
8+
private import ControlFlowGraph
9+
10+
module MakeAstConsistency<LocationSig Location, AstSig<Location> Ast> {
11+
private import Ast
12+
13+
private predicate astMemberChild(AstNode parent, AstNode child, string member) {
14+
parent.(Parameter).getDefaultValue() = child and member = "Parameter.getDefaultValue"
15+
or
16+
parent.(BlockStmt).getStmt(_) = child and member = "BlockStmt.getStmt"
17+
or
18+
parent.(BlockStmt).getLastStmt() = child and member = "BlockStmt.getLastStmt"
19+
or
20+
parent.(ExprStmt).getExpr() = child and member = "ExprStmt.getExpr"
21+
or
22+
parent.(IfStmt).getCondition() = child and member = "IfStmt.getCondition"
23+
or
24+
parent.(IfStmt).getThen() = child and member = "IfStmt.getThen"
25+
or
26+
parent.(IfStmt).getElse() = child and member = "IfStmt.getElse"
27+
or
28+
parent.(LoopStmt).getBody() = child and member = "LoopStmt.getBody"
29+
or
30+
parent.(WhileStmt).getCondition() = child and member = "WhileStmt.getCondition"
31+
or
32+
parent.(DoStmt).getCondition() = child and member = "DoStmt.getCondition"
33+
or
34+
parent.(ForStmt).getInit(_) = child and member = "ForStmt.getInit"
35+
or
36+
parent.(ForStmt).getCondition() = child and member = "ForStmt.getCondition"
37+
or
38+
parent.(ForStmt).getUpdate(_) = child and member = "ForStmt.getUpdate"
39+
or
40+
parent.(ForeachStmt).getVariable() = child and member = "ForeachStmt.getVariable"
41+
or
42+
parent.(ForeachStmt).getCollection() = child and member = "ForeachStmt.getCollection"
43+
or
44+
parent.(ReturnStmt).getExpr() = child and member = "ReturnStmt.getExpr"
45+
or
46+
parent.(Throw).getExpr() = child and member = "Throw.getExpr"
47+
or
48+
parent.(TryStmt).getBody() = child and member = "TryStmt.getBody"
49+
or
50+
parent.(TryStmt).getCatch(_) = child and member = "TryStmt.getCatch"
51+
or
52+
parent.(TryStmt).getFinally() = child and member = "TryStmt.getFinally"
53+
or
54+
getTryInit(parent, _) = child and member = "getTryInit"
55+
or
56+
getTryElse(parent) = child and member = "getTryElse"
57+
or
58+
parent.(CatchClause).getVariable() = child and member = "CatchClause.getVariable"
59+
or
60+
parent.(CatchClause).getCondition() = child and member = "CatchClause.getCondition"
61+
or
62+
parent.(CatchClause).getBody() = child and member = "CatchClause.getBody"
63+
or
64+
parent.(Switch).getExpr() = child and member = "Switch.getExpr"
65+
or
66+
parent.(Switch).getCase(_) = child and member = "Switch.getCase"
67+
or
68+
parent.(Switch).getStmt(_) = child and member = "Switch.getStmt"
69+
or
70+
parent.(Case).getPattern(_) = child and member = "Case.getPattern"
71+
or
72+
parent.(Case).getGuard() = child and member = "Case.getGuard"
73+
or
74+
parent.(Case).getBody() = child and member = "Case.getBody"
75+
or
76+
parent.(ConditionalExpr).getCondition() = child and member = "ConditionalExpr.getCondition"
77+
or
78+
parent.(ConditionalExpr).getThen() = child and member = "ConditionalExpr.getThen"
79+
or
80+
parent.(ConditionalExpr).getElse() = child and member = "ConditionalExpr.getElse"
81+
or
82+
parent.(BinaryExpr).getLeftOperand() = child and member = "BinaryExpr.getLeftOperand"
83+
or
84+
parent.(BinaryExpr).getRightOperand() = child and member = "BinaryExpr.getRightOperand"
85+
or
86+
parent.(UnaryExpr).getOperand() = child and member = "UnaryExpr.getOperand"
87+
or
88+
parent.(PatternMatchExpr).getExpr() = child and member = "PatternMatchExpr.getExpr"
89+
or
90+
parent.(PatternMatchExpr).getPattern() = child and member = "PatternMatchExpr.getPattern"
91+
}
92+
93+
final private class FinalAstNode = AstNode;
94+
95+
private class StructuredAstNode extends FinalAstNode {
96+
StructuredAstNode() {
97+
this instanceof Parameter or
98+
this instanceof BlockStmt or
99+
this instanceof ExprStmt or
100+
this instanceof IfStmt or
101+
this instanceof LoopStmt or
102+
this instanceof WhileStmt or
103+
this instanceof DoStmt or
104+
this instanceof ForStmt or
105+
this instanceof ForeachStmt or
106+
this instanceof ReturnStmt or
107+
this instanceof Throw or
108+
this instanceof TryStmt or
109+
this instanceof CatchClause or
110+
this instanceof Switch or
111+
this instanceof Case or
112+
this instanceof ConditionalExpr or
113+
this instanceof BinaryExpr or
114+
this instanceof UnaryExpr or
115+
this instanceof PatternMatchExpr
116+
}
117+
}
118+
119+
module Consistency {
120+
/** Holds if the consistency query `query` has `results` results. */
121+
query predicate consistencyOverview(string query, int results) {
122+
query = "multipleParents" and
123+
results = strictcount(AstNode child | multipleParents(child, _, _))
124+
or
125+
query = "childAtMultipleIndices" and
126+
results = strictcount(AstNode child | childAtMultipleIndices(_, child, _, _))
127+
or
128+
query = "siblingsWithIdenticalIndex" and
129+
results =
130+
strictcount(AstNode parent, int index | siblingsWithIdenticalIndex(parent, index, _, _))
131+
or
132+
query = "memberChildMissingFromGetChild" and
133+
results =
134+
strictcount(AstNode parent, AstNode child | memberChildMissingFromGetChild(parent, child, _))
135+
or
136+
query = "getChildMissingFromMember" and
137+
results = strictcount(AstNode parent, int index | getChildMissingFromMember(parent, index, _))
138+
}
139+
140+
/** Holds if `child` has multiple AST parents. */
141+
query predicate multipleParents(AstNode child, AstNode parent1, AstNode parent2) {
142+
getChild(parent1, _) = child and
143+
getChild(parent2, _) = child and
144+
parent1 != parent2
145+
}
146+
147+
/** Holds if `child` is assigned multiple child indices under `parent`. */
148+
query predicate childAtMultipleIndices(AstNode parent, AstNode child, int index1, int index2) {
149+
getChild(parent, index1) = child and
150+
getChild(parent, index2) = child and
151+
index1 < index2
152+
}
153+
154+
/** Holds if multiple children of `parent` share the same child index. */
155+
query predicate siblingsWithIdenticalIndex(
156+
AstNode parent, int index, AstNode child1, AstNode child2
157+
) {
158+
getChild(parent, index) = child1 and
159+
getChild(parent, index) = child2 and
160+
child1 != child2
161+
}
162+
163+
/** Holds if a member child relation is not reflected by `getChild`. */
164+
query predicate memberChildMissingFromGetChild(AstNode parent, AstNode child, string member) {
165+
exists(getEnclosingCallable(parent)) and
166+
exists(Expr grandparent | getChild(grandparent, _) = parent) and
167+
astMemberChild(parent, child, member) and
168+
not getChild(parent, _) = child
169+
}
170+
171+
/** Holds if a `getChild` relation for a structured AST node has no matching member predicate. */
172+
query predicate getChildMissingFromMember(StructuredAstNode parent, int index, AstNode child) {
173+
child = getChild(parent, index) and
174+
not astMemberChild(parent, child, _)
175+
}
176+
}
177+
}

shared/controlflow/codeql/controlflow/ControlFlowGraph.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
20702070
*/
20712071

20722072
private import PrintGraph as Pp
2073+
private import codeql.controlflow.AstConsistency
20732074

20742075
private class ControlFlowNodeAlias = ControlFlowNode;
20752076

@@ -2085,6 +2086,9 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
20852086

20862087
import Pp::PrintGraph<Location, PrintGraphInput>
20872088

2089+
/** Provides AST consistency queries. */
2090+
module AstConsistency = MakeAstConsistency<Location, Ast>::Consistency;
2091+
20882092
/** Provides a set of consistency queries. */
20892093
module Consistency {
20902094
/** Holds if the consistency query `query` has `results` results. */

0 commit comments

Comments
 (0)