Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 36b27ad

Browse files
author
Dave Bartolomeo
committed
Simplify ordering of children with conversions using rank
In `getChild(int childIndex)`, the actual values of `childIndex` don't matter, as long as they are in the correct order. Rather than doing complicated math to compute the indices for the synthesized `.getFullyConverted()` children, just use the `rank` aggregate to order all children first by whether or not the child is a conversion, then by the original child index.
1 parent cf8f802 commit 36b27ad

1 file changed

Lines changed: 57 additions & 54 deletions

File tree

cpp/ql/src/semmle/code/cpp/PrintAST.qll

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,38 @@ class PrintASTNode extends TPrintASTNode {
124124
* regular parent/child relation traversal.
125125
*/
126126
final PrintASTNode getChild(int childIndex) {
127-
exists(int nonConvertedIndex, boolean isConverted |
128-
mapIndex(childIndex, nonConvertedIndex, isConverted)
129-
|
130-
if isConverted = false
131-
then result = getChildInternal(childIndex)
132-
else
133-
exists(Expr expr |
134-
expr = getChildInternal(nonConvertedIndex).(ASTNode).getAST() and
135-
expr.getFullyConverted() instanceof Conversion and
136-
result.(ASTNode).getAST() = expr.getFullyConverted() and
137-
not expr instanceof Conversion
138-
)
127+
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
128+
result =
129+
rank[childIndex](PrintASTNode child, int nonConvertedIndex, boolean isConverted |
130+
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
131+
|
132+
// Unconverted children come first, then sort by original child index within each group.
133+
child order by isConverted, nonConvertedIndex
134+
)
135+
}
136+
137+
/**
138+
* Gets the node for the `.getFullyConverted()` version of the child originally at index
139+
* `childIndex`, if that node has any conversions.
140+
*/
141+
private PrintASTNode getConvertedChild(int childIndex) {
142+
exists(Expr expr |
143+
expr = getChildInternal(childIndex).(ASTNode).getAST() and
144+
expr.getFullyConverted() instanceof Conversion and
145+
result.(ASTNode).getAST() = expr.getFullyConverted() and
146+
not expr instanceof Conversion
139147
)
140148
}
141149

150+
/**
151+
* Gets the child access predicate for the `.getFullyConverted()` version of the child originally
152+
* at index `childIndex`, if that node has any conversions.
153+
*/
154+
private string getConvertedChildAccessorPredicate(int childIndex) {
155+
exists(getConvertedChild(childIndex)) and
156+
result = getChildAccessorPredicateInternal(childIndex) + ".getFullyConverted()"
157+
}
158+
142159
/**
143160
* Holds if this node should be printed in the output. By default, all nodes
144161
* within a function are printed, but the query can override
@@ -170,19 +187,39 @@ class PrintASTNode extends TPrintASTNode {
170187
result = toString()
171188
}
172189

190+
/**
191+
* Holds if there is a child node `child` for original child index `nonConvertedIndex` with
192+
* predicate name `childPredicate`. If the original child at that index has any conversions, there
193+
* will be two result tuples for this predicate: one with the original child and predicate, with
194+
* `isConverted = false`, and the other with the `.getFullyConverted()` version of the child and
195+
* predicate, with `isConverted = true`. For a child without any conversions, there will be only
196+
* one result tuple, with `isConverted = false`.
197+
*/
198+
private predicate childAndAccessorPredicate(
199+
PrintASTNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
200+
) {
201+
child = getChildInternal(nonConvertedIndex) and
202+
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
203+
isConverted = false
204+
or
205+
child = getConvertedChild(nonConvertedIndex) and
206+
childPredicate = getConvertedChildAccessorPredicate(nonConvertedIndex) and
207+
isConverted = true
208+
}
209+
173210
/**
174211
* Gets the QL predicate that can be used to access the child at `childIndex`.
175212
* May not always return a QL predicate, see for example `FunctionNode`.
176213
*/
177214
final string getChildAccessorPredicate(int childIndex) {
178-
exists(getChild(childIndex)) and
179-
exists(int nonConvertedIndex, boolean isConverted |
180-
mapIndex(childIndex, nonConvertedIndex, isConverted)
181-
|
182-
if isConverted = false
183-
then result = getChildAccessorPredicateInternal(childIndex)
184-
else result = getChildAccessorPredicateInternal(nonConvertedIndex) + ".getFullyConverted()"
185-
)
215+
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
216+
result =
217+
rank[childIndex](string childPredicate, int nonConvertedIndex, boolean isConverted |
218+
childAndAccessorPredicate(_, childPredicate, nonConvertedIndex, isConverted)
219+
|
220+
// Unconverted children come first, then sort by original child index within each group.
221+
childPredicate order by isConverted, nonConvertedIndex
222+
)
186223
}
187224

188225
/**
@@ -191,40 +228,6 @@ class PrintASTNode extends TPrintASTNode {
191228
*/
192229
abstract string getChildAccessorPredicateInternal(int childIndex);
193230

194-
/**
195-
* Holds either if a `childIndex` is a synthesized child coming from a conversion (`isConverted = true`)
196-
* or if the child is a regular child node.
197-
* In the former case, `nonConvertedIndex` is the index of the regular, unconverted child node.
198-
* Note: This predicate contains the mapping between the converted and nonconverted indexes, but
199-
* if `nonConvertedIndex` does not have conversions attached, there will be no node at `childIndex`.
200-
*/
201-
final predicate mapIndex(int childIndex, int nonConvertedIndex, boolean isConverted) {
202-
exists(getChildInternal(childIndex)) and
203-
nonConvertedIndex = childIndex and
204-
isConverted = false
205-
or
206-
not exists(getChildInternal(childIndex)) and
207-
exists(getChildInternal(nonConvertedIndex)) and
208-
isConverted = true and
209-
// to get the desired order of the extended `childIndex`es (including the synthesized children for conversions)
210-
// we keep the indexes in the following three disjoint intervals:
211-
// [minIndex, maxIndex: original children, without conversion
212-
// [|-1| + |maxIndex|, |minIndex| + |maxIndex|]: conversion children with negative `nonConvertedIndex`
213-
// [0 + |maxIndex| + |minIndex| + 1, maxIndex + |maxIndex| + |minIndex| + 1]: for conversion children
214-
// with positive `nonConvertedIndex`
215-
exists(int minIndex, int maxIndex |
216-
minIndex = min(int n | exists(getChildInternal(n))) and
217-
maxIndex = max(int n | exists(getChildInternal(n)))
218-
|
219-
if nonConvertedIndex < 0
220-
then
221-
// note that we swap the order of the negative indexes here, so that the conversion child for `-2`
222-
// comes before the conversion child for `-1`
223-
childIndex = (minIndex - 1 - nonConvertedIndex).abs() + maxIndex.abs()
224-
else childIndex = nonConvertedIndex + maxIndex.abs() + minIndex.abs() + 1
225-
)
226-
}
227-
228231
/**
229232
* Gets the `Function` that contains this node.
230233
*/

0 commit comments

Comments
 (0)