|
2 | 2 |
|
3 | 3 | import codeql.swift.elements
|
4 | 4 |
|
5 |
| -/** |
6 |
| - * Gets any of the "immediate" children of `e`. "Immediate" means not taking into account node resolution: for example |
7 |
| - * if the AST child is the first of a series of conversions that would normally be hidden away, this will select the |
8 |
| - * next conversion down the hidden AST tree instead of the corresponding fully uncoverted node at the bottom. |
9 |
| - * Outside this module this file is mainly intended to be used to test uniqueness of parents. |
10 |
| - */ |
| 5 | +private module Impl { |
| 6 | +{{#classes}} |
| 7 | + private Element getImmediateChildOf{{name}}({{name}} e, int index, string partialPredicateCall) { |
| 8 | + {{! avoid unused argument warnings on root element, assuming the root element has no children }} |
| 9 | + {{#root}}none(){{/root}} |
| 10 | + {{^root}} |
| 11 | + {{! b is the base offset 0, for ease of generation }} |
| 12 | + {{! b<base> is constructed to be strictly greater than the indexes required for children coming from <base> }} |
| 13 | + {{! n is the base offset for direct children, equal to the last base offset from above }} |
| 14 | + {{! n<child> is constructed to be strictly greater than the indexes for <child> children }} |
| 15 | + exists(int b{{#bases}}, int b{{.}}{{/bases}}, int n{{#properties}}{{#is_child}}, int n{{singular}}{{/is_child}}{{/properties}} | |
| 16 | + b = 0 |
| 17 | + {{#bases}} |
| 18 | + and |
| 19 | + b{{.}} = b{{prev}} + 1 + max(int i | i = -1 or exists(getImmediateChildOf{{.}}(e, i, _)) | i) |
| 20 | + {{/bases}} |
| 21 | + and |
| 22 | + n = b{{last_base}} |
| 23 | + {{#properties}} |
| 24 | + {{#is_child}} |
| 25 | + {{! n<child> is defined on top of the previous definition }} |
| 26 | + {{! for single and optional properties it adds 1 (regardless of whether the optional property exists) }} |
| 27 | + {{! for repeated it adds 1 + the maximum index (which works for repeated optional as well) }} |
| 28 | + and |
| 29 | + n{{singular}} = n{{prev_child}} + 1{{#is_repeated}}+ max(int i | i = -1 or exists(e.getImmediate{{singular}}(i)) | i){{/is_repeated}} |
| 30 | + {{/is_child}} |
| 31 | + {{/properties}} and ( |
| 32 | + none() |
| 33 | + {{#bases}} |
| 34 | + or |
| 35 | + result = getImmediateChildOf{{.}}(e, index - b{{prev}}, partialPredicateCall) |
| 36 | + {{/bases}} |
| 37 | + {{#properties}} |
| 38 | + {{#is_child}} |
| 39 | + or |
| 40 | + {{#is_repeated}} |
| 41 | + result = e.getImmediate{{singular}}(index - n{{prev_child}}) and partialPredicateCall = "{{singular}}(" + (index - n{{prev_child}}).toString() + ")" |
| 42 | + {{/is_repeated}} |
| 43 | + {{^is_repeated}} |
| 44 | + index = n{{prev_child}} and result = e.getImmediate{{singular}}() and partialPredicateCall = "{{singular}}()" |
| 45 | + {{/is_repeated}} |
| 46 | + {{/is_child}} |
| 47 | + {{/properties}} |
| 48 | + )) |
| 49 | + {{/root}} |
| 50 | + } |
| 51 | + |
| 52 | +{{/classes}} |
11 | 53 | cached
|
12 |
| -Element getAnImmediateChild(Element e) { |
13 |
| - // why does this look more complicated than it should? |
14 |
| - // * none() simplifies generation, as we can append `or ...` without a special case for the first item |
15 |
| - none() |
16 |
| - {{#classes}} |
17 |
| - {{#properties}} |
18 |
| - {{#is_child}} |
19 |
| - or |
20 |
| - result = e.({{name}}).getImmediate{{singular}}({{#is_repeated}}_{{/is_repeated}}) |
21 |
| - {{/is_child}} |
22 |
| - {{/properties}} |
23 |
| - {{/classes}} |
| 54 | +Element getImmediateChild(Element e, int index, string partialAccessor) { |
| 55 | +// why does this look more complicated than it should? |
| 56 | +// * none() simplifies generation, as we can append `or ...` without a special case for the first item |
| 57 | +none() |
| 58 | +{{#classes}} |
| 59 | + {{#final}} |
| 60 | + or |
| 61 | + result = getImmediateChildOf{{name}}(e, index, partialAccessor) |
| 62 | + {{/final}} |
| 63 | +{{/classes}} |
| 64 | +} |
| 65 | +} |
| 66 | + |
| 67 | +/** |
| 68 | +* Gets the "immediate" parent of `e`. "Immediate" means not taking into account node resolution: for example |
| 69 | +* if `e` has conversions, `getImmediateParent(e)` will give the innermost conversion in the hidden AST. |
| 70 | +*/ |
| 71 | +Element getImmediateParent(Element e) { |
| 72 | +// `unique` is used here to tell the optimizer that there is in fact only one result |
| 73 | +// this is tested by the `library-tests/parent/no_double_parents.ql` test |
| 74 | +result = unique(Element x | e = Impl::getImmediateChild(x, _, _) | x) |
| 75 | +} |
| 76 | + |
| 77 | +/** |
| 78 | +* Gets the immediate child indexed at `index`. Indexes are not guaranteed to be contiguous, but are guaranteed to be distinct. `accessor` is bound the member predicate call resulting in the given child. |
| 79 | +*/ |
| 80 | +Element getImmediateChildAndAccessor(Element e, int index, string accessor) { |
| 81 | +exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor) and accessor = "getImmediate" + partialAccessor) |
24 | 82 | }
|
25 | 83 |
|
26 | 84 | /**
|
27 |
| - * Gets the "immediate" parent of `e`. "Immediate" means not taking into account node resolution: for example |
28 |
| - * if `e` has conversions, `getImmediateParent(e)` will give the bottom conversion in the hidden AST. |
29 |
| - */ |
30 |
| - Element getImmediateParent(Element e) { |
31 |
| - // `unique` is used here to tell the optimizer that there is in fact only one result |
32 |
| - // this is tested by the `library-tests/parent/no_double_parents.ql` test |
33 |
| - result = unique(Element x | e = getAnImmediateChild(x) | x) |
| 85 | +* Gets the child indexed at `index`. Indexes are not guaranteed to be contiguous, but are guaranteed to be distinct. `accessor` is bound the member predicate call resulting in the given child. |
| 86 | +*/ |
| 87 | +Element getChildAndAccessor(Element e, int index, string accessor) { |
| 88 | +exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor).resolve() and accessor = "get" + partialAccessor) |
34 | 89 | }
|
0 commit comments