You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There was an issue in case multiple inheritance from classes with
children was involved, where indexes would overlap.
The generated code structure has been reshuffled a bit, with
`Impl::getImmediateChildOf<Class>` predicates giving 0-based children
for a given class, including those coming from bases, and the final
`Impl::getImmediateChild` disjuncting the above on final classes only.
This removes the need of `getMaximumChildrenIndex<Class>`, and also
removes the code scanning alerts.
Also, comments were fixed addressing the review.
Copy file name to clipboardExpand all lines: swift/codegen/templates/ql_parent.mustache
+64-58Lines changed: 64 additions & 58 deletions
Original file line number
Diff line number
Diff line change
@@ -4,80 +4,86 @@ import codeql.swift.elements
4
4
5
5
private module Impl {
6
6
{{#classes}}
7
-
int getMaximumChildrenIndex{{name}}({{name}} e) {
8
-
{{#root}}e = e and{{/root}}
9
-
result = 0
10
-
{{#bases}}
11
-
+ getMaximumChildrenIndex{{.}}(e)
12
-
{{/bases}}
13
-
{{#properties}}
14
-
{{#is_child}}
15
-
+ 1{{#is_repeated}}+ max(int i | exists(e.getImmediate{{singular}}(i)) | i){{/is_repeated}}
16
-
{{/is_child}}
17
-
{{/properties}}
18
-
}
19
-
20
-
{{/classes}}
21
-
/**
22
-
* Gets any of the "immediate" children of `e`. "Immediate" means not taking into account node resolution: for example
23
-
* if the AST child is the first of a series of conversions that would normally be hidden away, this will select the
24
-
* next conversion down the hidden AST tree instead of the corresponding fully uncoverted node at the bottom.
25
-
* Outside this module this file is mainly intended to be used to test uniqueness of parents.
26
-
*/
27
-
cached
28
-
Element getImmediateChild(Element e, int index, string partialAccessor) {
29
-
// why does this look more complicated than it should?
30
-
// * none() simplifies generation, as we can append `or ...` without a special case for the first item
31
-
none()
32
-
{{#classes}}
33
-
{{#has_children}}
34
-
or
35
-
exists(int n{{#properties}}{{#is_child}}, int n{{singular}}{{/is_child}}{{/properties}} |
36
-
n = 0{{#bases}} + getMaximumChildrenIndex{{.}}(e){{/bases}}
7
+
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 offsets 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}}
37
23
{{#properties}}
38
-
{{#is_child}}
39
-
and n{{singular}} = n{{prev_child}} + 1{{#is_repeated}} + max(int i | i = 0 or exists(e.({{name}}).getImmediate{{singular}}(i)) | i){{/is_repeated}}
40
-
{{/is_child}}
41
-
{{/properties}}
42
-
and (
43
-
none()
44
-
{{#properties}}
45
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}}
46
34
or
47
-
{{#is_repeated}}
48
-
result = e.({{name}}).getImmediate{{singular}}(index - n{{prev_child}}) and partialAccessor = "{{singular}}(" + (index - n{{prev_child}}).toString() + ")"
49
-
{{/is_repeated}}
50
-
{{^is_repeated}}
51
-
index = n{{prev_child}} and result = e.({{name}}).getImmediate{{singular}}() and partialAccessor = "{{singular}}()"
52
-
{{/is_repeated}}
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}}
53
46
{{/is_child}}
54
-
{{/properties}}
55
-
))
56
-
{{/has_children}}
57
-
{{/classes}}
47
+
{{/properties}}
48
+
))
49
+
{{/root}}
50
+
}
51
+
52
+
{{/classes}}
53
+
cached
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}}
58
64
}
59
65
}
60
66
61
67
/**
62
-
* Gets the "immediate" parent of `e`. "Immediate" means not taking into account node resolution: for example
63
-
* if `e` has conversions, `getImmediateParent(e)` will give the bottom conversion in the hidden AST.
64
-
*/
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
+
*/
65
71
Element getImmediateParent(Element e) {
66
-
// `unique` is used here to tell the optimizer that there is in fact only one result
67
-
// this is tested by the `library-tests/parent/no_double_parents.ql` test
68
-
result = unique(Element x | e = Impl::getImmediateChild(x, _, _) | x)
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)
69
75
}
70
76
71
77
/**
72
-
* Gets the immediate child indexed at `index`. Indexes are not guaranteed to be contiguous, but are guaranteed to be distinct. `accessor` is bound the the method giving the given child.
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.
73
79
*/
74
80
Element getImmediateChildAndAccessor(Element e, int index, string accessor) {
75
-
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor) and accessor = "getImmediate" + partialAccessor)
81
+
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor) and accessor = "getImmediate" + partialAccessor)
76
82
}
77
83
78
84
/**
79
-
* Gets the child indexed at `index`. Indexes are not guaranteed to be contiguous, but are guaranteed to be distinct. `accessor` is bound the the method giving the given child. Node resolution is carried out.
80
-
*/
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
+
*/
81
87
Element getChildAndAccessor(Element e, int index, string accessor) {
82
-
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor).resolve() and accessor = "get" + partialAccessor)
88
+
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor).resolve() and accessor = "get" + partialAccessor)
0 commit comments