Skip to content

Commit b4edc92

Browse files
committed
Swift: make hideability spread upward in the hierarchy
1 parent b19194b commit b4edc92

29 files changed

+174
-213
lines changed

misc/codegen/generators/qlgen.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> q
166166
ipa=bool(cls.ipa),
167167
doc=cls.doc,
168168
hideable=cls.hideable,
169-
hideable_root=cls.hideable_root,
170169
**pragmas,
171170
)
172171

misc/codegen/lib/ql.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ class Class:
114114
ql_internal: bool = False
115115
ipa: bool = False
116116
doc: List[str] = field(default_factory=list)
117-
hideable_root: bool = False
118117
hideable: bool = False
119118

120119
def __post_init__(self):

misc/codegen/lib/schema.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ class Class:
9191
"""^^^ filled with `True` for non-final classes with only synthesized final descendants """
9292
doc: List[str] = field(default_factory=list)
9393
default_doc_name: Optional[str] = None
94-
hideable_root: bool = False
9594
hideable: bool = False
9695

9796
@property

misc/codegen/loaders/schemaloader.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def _get_class(cls: type) -> schema.Class:
3939
group=getattr(cls, "_group", ""),
4040
hideable=getattr(cls, "_hideable", False),
4141
# in the following we don't use `getattr` to avoid inheriting
42-
hideable_root=cls.__dict__.get("_hideable", False),
4342
pragmas=cls.__dict__.get("_pragmas", []),
4443
ipa=cls.__dict__.get("_ipa", None),
4544
properties=[
@@ -96,6 +95,18 @@ def fill_is_ipa(name: str):
9695
cls.ipa = True
9796

9897

98+
def _fill_hideable_information(classes: typing.Dict[str, schema.Class]):
99+
""" Update the class map propagating the `hideable` attribute upwards in the hierarchy """
100+
todo = [cls for cls in classes.values() if cls.hideable]
101+
while todo:
102+
cls = todo.pop()
103+
for base in cls.bases:
104+
supercls = classes[base]
105+
if not supercls.hideable:
106+
supercls.hideable = True
107+
todo.append(supercls)
108+
109+
99110
def load(m: types.ModuleType) -> schema.Schema:
100111
includes = set()
101112
classes = {}
@@ -124,6 +135,7 @@ def load(m: types.ModuleType) -> schema.Schema:
124135
cls.is_null_class = True
125136

126137
_fill_ipa_information(classes)
138+
_fill_hideable_information(classes)
127139

128140
return schema.Schema(includes=includes, classes=_toposort_classes_by_group(classes), null=null)
129141

misc/codegen/templates/ql_class.mustache

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ module Generated {
3737
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
3838
*/
3939
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
40-
{{/root}}
41-
{{#hideable_root}}
40+
4241
/**
4342
* Gets the most immediate element that should substitute this element in the explicit AST, if any.
4443
* Classes can override this to indicate this node should be in the "hidden" AST, mostly reserved
@@ -55,7 +54,7 @@ module Generated {
5554
or
5655
result = this.getResolveStep().resolve()
5756
}
58-
{{/hideable_root}}
57+
{{/root}}
5958
{{#final}}
6059
override string getAPrimaryQlClass() { result = "{{name}}" }
6160
{{/final}}

misc/codegen/templates/ql_parent.mustache

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,28 @@ none()
6464
{{/final}}
6565
{{/classes}}
6666
}
67-
68-
Element resolve(Element e) {
69-
{{#classes}}{{#hideable_root}}if e instanceof {{name}} then result = e.({{name}}).resolve() else {{/hideable_root}}{{/classes}}result = e
70-
}
7167
}
7268

7369
/**
7470
* Gets the "immediate" parent of `e`. "Immediate" means not taking into account node resolution: for example
7571
* if `e` has conversions, `getImmediateParent(e)` will give the innermost conversion in the hidden AST.
7672
*/
7773
Element getImmediateParent(Element e) {
78-
// `unique` is used here to tell the optimizer that there is in fact only one result
79-
// this is tested by the `library-tests/parent/no_double_parents.ql` test
80-
result = unique(Element x | e = Impl::getImmediateChild(x, _, _) | x)
74+
// `unique` is used here to tell the optimizer that there is in fact only one result
75+
// this is tested by the `library-tests/parent/no_double_parents.ql` test
76+
result = unique(Element x | e = Impl::getImmediateChild(x, _, _) | x)
8177
}
8278

8379
/**
8480
* 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.
8581
*/
8682
Element getImmediateChildAndAccessor(Element e, int index, string accessor) {
87-
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor) and accessor = "get" + partialAccessor)
83+
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor) and accessor = "get" + partialAccessor)
8884
}
8985

9086
/**
9187
* 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.
9288
*/
9389
Element getChildAndAccessor(Element e, int index, string accessor) {
94-
exists(string partialAccessor | result = Impl::resolve(Impl::getImmediateChild(e, index, partialAccessor)) and accessor = "get" + partialAccessor)
90+
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor).resolve() and accessor = "get" + partialAccessor)
9591
}

misc/codegen/test/test_qlgen.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -880,14 +880,6 @@ def test_hideable_class(generate_classes):
880880
}
881881

882882

883-
def test_hideable_root_class(generate_classes):
884-
assert generate_classes([
885-
schema.Class("MyObject", hideable_root=True),
886-
]) == {
887-
"MyObject.qll": (a_ql_stub(name="MyObject"), a_ql_class(name="MyObject", final=True, hideable_root=True)),
888-
}
889-
890-
891883
def test_hideable_property(generate_classes):
892884
assert generate_classes([
893885
schema.Class("MyObject", hideable=True),

misc/codegen/test/test_schemaloader.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -698,11 +698,22 @@ class Root:
698698
class A(Root):
699699
pass
700700

701-
class B(A):
701+
class IndirectlyHideable(Root):
702+
pass
703+
704+
class B(A, IndirectlyHideable):
702705
pass
703706

704-
assert data.classes["A"] == schema.Class("A", bases=["Root"], derived={"B"}, hideable_root=True, hideable=True)
705-
assert data.classes["B"] == schema.Class("B", bases=["A"], hideable=True)
707+
class NonHideable(Root):
708+
pass
709+
710+
assert data.classes == {
711+
"Root": schema.Class("Root", derived={"A", "IndirectlyHideable", "NonHideable"}, hideable=True),
712+
"A": schema.Class("A", bases=["Root"], derived={"B"}, hideable=True),
713+
"IndirectlyHideable": schema.Class("IndirectlyHideable", bases=["Root"], derived={"B"}, hideable=True),
714+
"B": schema.Class("B", bases=["A", "IndirectlyHideable"], hideable=True),
715+
"NonHideable": schema.Class("NonHideable", bases=["Root"], hideable=False),
716+
}
706717

707718

708719
if __name__ == '__main__':

swift/ql/.generated.list

Lines changed: 11 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)