|
4 | 4 | */
|
5 | 5 |
|
6 | 6 | import csharp
|
7 |
| - |
8 |
| -/** Gets the declaration referenced by the expression `e`, if any. */ |
9 |
| -private Declaration referenceAttribute(Expr e) { |
10 |
| - result = e.(MethodCall).getTarget() |
11 |
| - or |
12 |
| - result = e.(ObjectCreation).getTarget() |
13 |
| - or |
14 |
| - result = e.(Access).getTarget() |
15 |
| -} |
16 |
| - |
17 |
| -/** Gets the AST node kind element `e`. */ |
18 |
| -private int elementKind(ControlFlowElement e) { |
19 |
| - expressions(e, result, _) |
20 |
| - or |
21 |
| - exists(int k | statements(e, k) | result = -k) |
22 |
| -} |
23 |
| - |
24 |
| -private int getNumberOfActualChildren(ControlFlowElement e) { |
25 |
| - if e.(MemberAccess).targetIsThisInstance() |
26 |
| - then result = e.getNumberOfChildren() - 1 |
27 |
| - else result = e.getNumberOfChildren() |
28 |
| -} |
29 |
| - |
30 |
| -/** |
31 |
| - * A configuration for performing structural comparisons of program elements |
32 |
| - * (expressions and statements). |
33 |
| - * |
34 |
| - * The predicate `candidate()` must be overridden, in order to identify the |
35 |
| - * elements for which to perform structural comparison. |
36 |
| - * |
37 |
| - * Each use of the library is identified by a unique string value. |
38 |
| - */ |
39 |
| -abstract class StructuralComparisonConfiguration extends string { |
40 |
| - bindingset[this] |
41 |
| - StructuralComparisonConfiguration() { any() } |
42 |
| - |
43 |
| - /** |
44 |
| - * Holds if elements `x` and `y` are candidates for testing structural |
45 |
| - * equality. |
46 |
| - * |
47 |
| - * Subclasses are expected to override this predicate to identify the |
48 |
| - * top-level elements which they want to compare. Care should be |
49 |
| - * taken to avoid identifying too many pairs of elements, as in general |
50 |
| - * there are very many structurally equal subtrees in a program, and |
51 |
| - * in order to keep the computation feasible we must focus attention. |
52 |
| - * |
53 |
| - * Note that this relation is not expected to be symmetric -- it's |
54 |
| - * fine to include a pair `(x, y)` but not `(y, x)`. |
55 |
| - * In fact, not including the symmetrically implied fact will save |
56 |
| - * half the computation time on the structural comparison. |
57 |
| - */ |
58 |
| - abstract predicate candidate(ControlFlowElement x, ControlFlowElement y); |
59 |
| - |
60 |
| - private predicate candidateInternal(ControlFlowElement x, ControlFlowElement y) { |
61 |
| - candidate(x, y) |
62 |
| - or |
63 |
| - exists(ControlFlowElement xParent, ControlFlowElement yParent, int i | |
64 |
| - candidateInternalChild(xParent, i, x, yParent) |
65 |
| - | |
66 |
| - y = yParent.getChild(i) |
67 |
| - ) |
68 |
| - } |
69 |
| - |
70 |
| - pragma[noinline] |
71 |
| - private predicate candidateInternalChild( |
72 |
| - ControlFlowElement x, int i, ControlFlowElement xChild, ControlFlowElement y |
73 |
| - ) { |
74 |
| - candidateInternal(x, y) and |
75 |
| - xChild = x.getChild(i) |
76 |
| - } |
77 |
| - |
78 |
| - private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) } |
79 |
| - |
80 |
| - pragma[nomagic] |
81 |
| - private predicate sameByValueAux(Expr x, Expr y, string value) { |
82 |
| - candidateInternal(x, y) and |
83 |
| - value = x.getValue() |
84 |
| - } |
85 |
| - |
86 |
| - private ControlFlowElement getRankedChild(ControlFlowElement cfe, int rnk, int i) { |
87 |
| - (candidateInternal(cfe, _) or candidateInternal(_, cfe)) and |
88 |
| - i = |
89 |
| - rank[rnk](int j | |
90 |
| - exists(ControlFlowElement child | child = cfe.getChild(j) | |
91 |
| - not (j = -1 and cfe.(MemberAccess).targetIsThisInstance()) |
92 |
| - ) |
93 |
| - ) and |
94 |
| - result = cfe.getChild(i) |
95 |
| - } |
96 |
| - |
97 |
| - pragma[nomagic] |
98 |
| - private predicate sameByStructure0( |
99 |
| - ControlFlowElement x, ControlFlowElement y, int elementKind, int children |
100 |
| - ) { |
101 |
| - candidateInternal(x, y) and |
102 |
| - elementKind = elementKind(x) and |
103 |
| - children = getNumberOfActualChildren(x) and |
104 |
| - not (x.(Expr).hasValue() and y.(Expr).hasValue()) |
105 |
| - } |
106 |
| - |
107 |
| - pragma[nomagic] |
108 |
| - private predicate sameByStructure(ControlFlowElement x, ControlFlowElement y, int i) { |
109 |
| - i = 0 and |
110 |
| - // At least one of `x` and `y` must not have a value, they must have |
111 |
| - // the same kind, and the same number of children |
112 |
| - sameByStructure0(x, y, elementKind(y), getNumberOfActualChildren(y)) and |
113 |
| - // If one of them has a reference attribute, they should both reference |
114 |
| - // the same node |
115 |
| - (exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and |
116 |
| - // x is a member access on `this` iff y is |
117 |
| - (x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and |
118 |
| - (y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance()) |
119 |
| - or |
120 |
| - exists(int j | sameByStructure(x, y, i - 1) | |
121 |
| - sameInternal(getRankedChild(x, i, j), getRankedChild(y, i, j)) |
122 |
| - ) |
123 |
| - } |
124 |
| - |
125 |
| - pragma[nomagic] |
126 |
| - private predicate sameInternal(ControlFlowElement x, ControlFlowElement y) { |
127 |
| - sameByValue(x, y) |
128 |
| - or |
129 |
| - sameByStructure(x, y, getNumberOfActualChildren(x)) |
130 |
| - } |
131 |
| - |
132 |
| - /** |
133 |
| - * Holds if elements `x` and `y` structurally equal. `x` and `y` must be |
134 |
| - * flagged as candidates for structural equality, that is, |
135 |
| - * `candidate(x, y)` must hold. |
136 |
| - */ |
137 |
| - predicate same(ControlFlowElement x, ControlFlowElement y) { |
138 |
| - candidate(x, y) and |
139 |
| - sameInternal(x, y) |
140 |
| - } |
141 |
| -} |
142 |
| - |
143 |
| -/** |
144 |
| - * INTERNAL: Do not use. |
145 |
| - * |
146 |
| - * A verbatim copy of the class `StructuralComparisonConfiguration` for internal |
147 |
| - * use. |
148 |
| - * |
149 |
| - * A copy is needed in order to use structural comparison within the standard |
150 |
| - * library without running into caching issues. |
151 |
| - */ |
152 |
| -module Internal { |
153 |
| - // Import all uses of the internal library to make sure caching works |
154 |
| - private import semmle.code.csharp.controlflow.Guards as G |
155 |
| - |
156 |
| - /** |
157 |
| - * A configuration for performing structural comparisons of program elements |
158 |
| - * (expressions and statements). |
159 |
| - * |
160 |
| - * The predicate `candidate()` must be overridden, in order to identify the |
161 |
| - * elements for which to perform structural comparison. |
162 |
| - * |
163 |
| - * Each use of the library is identified by a unique string value. |
164 |
| - */ |
165 |
| - abstract class InternalStructuralComparisonConfiguration extends string { |
166 |
| - bindingset[this] |
167 |
| - InternalStructuralComparisonConfiguration() { any() } |
168 |
| - |
169 |
| - /** |
170 |
| - * Holds if elements `x` and `y` are candidates for testing structural |
171 |
| - * equality. |
172 |
| - * |
173 |
| - * Subclasses are expected to override this predicate to identify the |
174 |
| - * top-level elements which they want to compare. Care should be |
175 |
| - * taken to avoid identifying too many pairs of elements, as in general |
176 |
| - * there are very many structurally equal subtrees in a program, and |
177 |
| - * in order to keep the computation feasible we must focus attention. |
178 |
| - * |
179 |
| - * Note that this relation is not expected to be symmetric -- it's |
180 |
| - * fine to include a pair `(x, y)` but not `(y, x)`. |
181 |
| - * In fact, not including the symmetrically implied fact will save |
182 |
| - * half the computation time on the structural comparison. |
183 |
| - */ |
184 |
| - abstract predicate candidate(ControlFlowElement x, ControlFlowElement y); |
185 |
| - |
186 |
| - private predicate candidateInternal(ControlFlowElement x, ControlFlowElement y) { |
187 |
| - candidate(x, y) |
188 |
| - or |
189 |
| - exists(ControlFlowElement xParent, ControlFlowElement yParent, int i | |
190 |
| - candidateInternalChild(xParent, i, x, yParent) |
191 |
| - | |
192 |
| - y = yParent.getChild(i) |
193 |
| - ) |
194 |
| - } |
195 |
| - |
196 |
| - pragma[noinline] |
197 |
| - private predicate candidateInternalChild( |
198 |
| - ControlFlowElement x, int i, ControlFlowElement xChild, ControlFlowElement y |
199 |
| - ) { |
200 |
| - candidateInternal(x, y) and |
201 |
| - xChild = x.getChild(i) |
202 |
| - } |
203 |
| - |
204 |
| - private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) } |
205 |
| - |
206 |
| - pragma[nomagic] |
207 |
| - private predicate sameByValueAux(Expr x, Expr y, string value) { |
208 |
| - candidateInternal(x, y) and |
209 |
| - value = x.getValue() |
210 |
| - } |
211 |
| - |
212 |
| - private ControlFlowElement getRankedChild(ControlFlowElement cfe, int rnk, int i) { |
213 |
| - (candidateInternal(cfe, _) or candidateInternal(_, cfe)) and |
214 |
| - i = |
215 |
| - rank[rnk](int j | |
216 |
| - exists(ControlFlowElement child | child = cfe.getChild(j) | |
217 |
| - not (j = -1 and cfe.(MemberAccess).targetIsThisInstance()) |
218 |
| - ) |
219 |
| - ) and |
220 |
| - result = cfe.getChild(i) |
221 |
| - } |
222 |
| - |
223 |
| - pragma[nomagic] |
224 |
| - private predicate sameByStructure0( |
225 |
| - ControlFlowElement x, ControlFlowElement y, int elementKind, int children |
226 |
| - ) { |
227 |
| - candidateInternal(x, y) and |
228 |
| - elementKind = elementKind(x) and |
229 |
| - children = getNumberOfActualChildren(x) and |
230 |
| - not (x.(Expr).hasValue() and y.(Expr).hasValue()) |
231 |
| - } |
232 |
| - |
233 |
| - pragma[nomagic] |
234 |
| - private predicate sameByStructure(ControlFlowElement x, ControlFlowElement y, int i) { |
235 |
| - i = 0 and |
236 |
| - // At least one of `x` and `y` must not have a value, they must have |
237 |
| - // the same kind, and the same number of children |
238 |
| - sameByStructure0(x, y, elementKind(y), getNumberOfActualChildren(y)) and |
239 |
| - // If one of them has a reference attribute, they should both reference |
240 |
| - // the same node |
241 |
| - (exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and |
242 |
| - // x is a member access on `this` iff y is |
243 |
| - (x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and |
244 |
| - (y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance()) |
245 |
| - or |
246 |
| - exists(int j | sameByStructure(x, y, i - 1) | |
247 |
| - sameInternal(getRankedChild(x, i, j), getRankedChild(y, i, j)) |
248 |
| - ) |
249 |
| - } |
250 |
| - |
251 |
| - pragma[nomagic] |
252 |
| - private predicate sameInternal(ControlFlowElement x, ControlFlowElement y) { |
253 |
| - sameByValue(x, y) |
254 |
| - or |
255 |
| - sameByStructure(x, y, getNumberOfActualChildren(x)) |
256 |
| - } |
257 |
| - |
258 |
| - /** |
259 |
| - * Holds if elements `x` and `y` structurally equal. `x` and `y` must be |
260 |
| - * flagged as candidates for structural equality, that is, |
261 |
| - * `candidate(x, y)` must hold. |
262 |
| - */ |
263 |
| - predicate same(ControlFlowElement x, ControlFlowElement y) { |
264 |
| - candidate(x, y) and |
265 |
| - sameInternal(x, y) |
266 |
| - } |
267 |
| - } |
268 |
| -} |
0 commit comments