Skip to content

Commit c4c2bc8

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

4 files changed

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

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)