Skip to content

Commit 135c820

Browse files
authored
Merge pull request github#11592 from github/redsun82/swift-fix-get-number-of
Swift: fix generated `getNumberOf`
2 parents 5e694b5 + ef34845 commit 135c820

File tree

107 files changed

+705
-444
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+705
-444
lines changed

swift/codegen/generators/qlgen.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,12 @@ def _get_all_properties_to_be_tested(cls: schema.Class, lookup: typing.Dict[str,
248248
if not ("qltest_skip" in c.pragmas or "qltest_skip" in p.pragmas):
249249
# TODO here operations are duplicated, but should be better if we split ql and qltest generation
250250
p = get_ql_property(c, p)
251-
yield ql.PropertyForTest(p.getter, p.type, p.is_single, p.is_predicate, p.is_repeated)
251+
yield ql.PropertyForTest(p.getter, is_total=p.is_single or p.is_predicate,
252+
type=p.type if not p.is_predicate else None, is_repeated=p.is_repeated)
253+
if p.is_repeated and not p.is_optional:
254+
yield ql.PropertyForTest(f"getNumberOf{p.plural}", type="int")
255+
elif p.is_optional and not p.is_repeated:
256+
yield ql.PropertyForTest(f"has{p.singular}")
252257

253258

254259
def _partition_iter(x, pred):
@@ -337,7 +342,7 @@ def generate(opts, renderer):
337342
test_dir / missing_test_source_filename)
338343
continue
339344
total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, data.classes),
340-
lambda p: p.is_single or p.is_predicate)
345+
lambda p: p.is_total)
341346
renderer.render(ql.ClassTester(class_name=c.name,
342347
properties=total_props,
343348
# in case of collapsed hierarchies we want to see the actual QL class in results

swift/codegen/lib/ql.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,8 @@ class GetParentImplementation:
165165
@dataclass
166166
class PropertyForTest:
167167
getter: str
168+
is_total: bool = True
168169
type: Optional[str] = None
169-
is_single: bool = False
170-
is_predicate: bool = False
171170
is_repeated: bool = False
172171

173172

swift/codegen/templates/ql_class.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ module Generated {
126126
* Gets the number of {{doc_plural}}.
127127
*/
128128
final int getNumberOf{{plural}}() {
129-
result = count({{indefinite_getter}}())
129+
result = count(int i | exists({{getter}}(i)))
130130
}
131131
{{/is_optional}}
132132
{{/is_repeated}}

swift/codegen/templates/ql_test_class.mustache

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import codeql.swift.elements
44
import TestUtils
55

6-
from {{class_name}} x{{#properties}}, {{#is_single}}{{type}}{{/is_single}}{{#is_predicate}}string{{/is_predicate}} {{getter}}{{/properties}}
6+
from {{class_name}} x{{#properties}}, {{#type}}{{.}}{{/type}}{{^type}}string{{/type}} {{getter}}{{/properties}}
77
where toBeTested(x) and not x.isUnknown()
88
{{#properties}}
9-
{{#is_single}}
9+
{{#type}}
1010
and {{getter}} = x.{{getter}}()
11-
{{/is_single}}
12-
{{#is_predicate}}
11+
{{/type}}
12+
{{^type}}
1313
and if x.{{getter}}() then {{getter}} = "yes" else {{getter}} = "no"
14-
{{/is_predicate}}
14+
{{/type}}
1515
{{/properties}}
1616
select x{{#show_ql_class}}, x.getPrimaryQlClasses(){{/show_ql_class}}{{#properties}}, "{{getter}}:", {{getter}}{{/properties}}

swift/codegen/test/test_qlgen.py

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ def test_children(generate_classes):
222222
ql.Class(name="MyObject", final=True,
223223
properties=[
224224
ql.Property(singular="A", type="int", tablename="my_objects",
225-
tableparams=["this", "result", "_"], doc="a of this my object"),
225+
tableparams=["this", "result", "_"],
226+
doc="a of this my object"),
226227
ql.Property(singular="Child1", type="int", tablename="my_objects",
227228
tableparams=["this", "_", "result"], prev_child="",
228229
doc="child 1 of this my object"),
@@ -233,9 +234,11 @@ def test_children(generate_classes):
233234
ql.Property(singular="Child", plural="Children", type="int",
234235
tablename="my_object_children",
235236
tableparams=["this", "index", "result"], prev_child="Child1",
236-
doc="child of this my object", doc_plural="children of this my object"),
237+
doc="child of this my object",
238+
doc_plural="children of this my object"),
237239
ql.Property(singular="C", type="int", tablename="my_object_cs",
238-
tableparams=["this", "result"], is_optional=True, doc="c of this my object"),
240+
tableparams=["this", "result"], is_optional=True,
241+
doc="c of this my object"),
239242
ql.Property(singular="Child3", type="int", tablename="my_object_child_3s",
240243
tableparams=["this", "result"], is_optional=True,
241244
prev_child="Child", doc="child 3 of this my object"),
@@ -246,7 +249,8 @@ def test_children(generate_classes):
246249
ql.Property(singular="Child4", plural="Child4s", type="int",
247250
tablename="my_object_child_4s",
248251
tableparams=["this", "index", "result"], is_optional=True,
249-
prev_child="Child3", doc="child 4 of this my object", doc_plural="child 4s of this my object"),
252+
prev_child="Child3", doc="child 4 of this my object",
253+
doc_plural="child 4s of this my object"),
250254
])),
251255
}
252256

@@ -263,11 +267,14 @@ def test_single_properties(generate_classes):
263267
ql.Class(name="MyObject", final=True,
264268
properties=[
265269
ql.Property(singular="One", type="x", tablename="my_objects",
266-
tableparams=["this", "result", "_", "_"], doc="one of this my object"),
270+
tableparams=["this", "result", "_", "_"],
271+
doc="one of this my object"),
267272
ql.Property(singular="Two", type="y", tablename="my_objects",
268-
tableparams=["this", "_", "result", "_"], doc="two of this my object"),
273+
tableparams=["this", "_", "result", "_"],
274+
doc="two of this my object"),
269275
ql.Property(singular="Three", type="z", tablename="my_objects",
270-
tableparams=["this", "_", "_", "result"], doc="three of this my object"),
276+
tableparams=["this", "_", "_", "result"],
277+
doc="three of this my object"),
271278
])),
272279
}
273280

@@ -322,7 +329,8 @@ def test_repeated_optional_property(generate_classes, is_child, prev_child):
322329
ql.Class(name="MyObject", final=True, properties=[
323330
ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos",
324331
tableparams=["this", "index", "result"], is_optional=True,
325-
prev_child=prev_child, doc="foo of this my object", doc_plural="foos of this my object"),
332+
prev_child=prev_child, doc="foo of this my object",
333+
doc_plural="foos of this my object"),
326334
])),
327335
}
328336

@@ -498,30 +506,38 @@ def test_test_total_properties(opts, generate_tests):
498506
]),
499507
]) == {
500508
"B/B.ql": ql.ClassTester(class_name="B", properties=[
501-
ql.PropertyForTest(
502-
getter="getX", is_single=True, type="string"),
503-
ql.PropertyForTest(
504-
getter="y", is_predicate=True, type="predicate"),
509+
ql.PropertyForTest(getter="getX", type="string"),
510+
ql.PropertyForTest(getter="y"),
505511
])
506512
}
507513

508514

509515
def test_test_partial_properties(opts, generate_tests):
510516
write(opts.ql_test_output / "B" / "test.swift")
511517
assert generate_tests([
512-
schema.Class("A", derived={"B"}, properties=[
518+
schema.Class("A", derived={"B", "C"}, properties=[
513519
schema.OptionalProperty("x", "string"),
514520
]),
515521
schema.Class("B", bases=["A"], properties=[
516-
schema.RepeatedProperty("y", "int"),
522+
schema.RepeatedProperty("y", "bool"),
523+
schema.RepeatedOptionalProperty("z", "int"),
517524
]),
518525
]) == {
519-
"B/B.ql": ql.ClassTester(class_name="B"),
526+
"B/B.ql": ql.ClassTester(class_name="B", properties=[
527+
ql.PropertyForTest(getter="hasX"),
528+
ql.PropertyForTest(getter="getNumberOfYs", type="int"),
529+
]),
520530
"B/B_getX.ql": ql.PropertyTester(class_name="B",
521-
property=ql.PropertyForTest(getter="getX", type="string")),
531+
property=ql.PropertyForTest(getter="getX", is_total=False,
532+
type="string")),
522533
"B/B_getY.ql": ql.PropertyTester(class_name="B",
523-
property=ql.PropertyForTest(getter="getY", is_repeated=True,
524-
type="int")),
534+
property=ql.PropertyForTest(getter="getY", is_total=False,
535+
is_repeated=True,
536+
type="bool")),
537+
"B/B_getZ.ql": ql.PropertyTester(class_name="B",
538+
property=ql.PropertyForTest(getter="getZ", is_total=False,
539+
is_repeated=True,
540+
type="int")),
525541
}
526542

527543

@@ -530,19 +546,20 @@ def test_test_properties_deduplicated(opts, generate_tests):
530546
assert generate_tests([
531547
schema.Class("Base", derived={"A", "B"}, properties=[
532548
schema.SingleProperty("x", "string"),
533-
schema.RepeatedProperty("y", "int"),
549+
schema.RepeatedProperty("y", "bool"),
534550
]),
535551
schema.Class("A", bases=["Base"], derived={"Final"}),
536552
schema.Class("B", bases=["Base"], derived={"Final"}),
537553
schema.Class("Final", bases=["A", "B"]),
538554
]) == {
539555
"Final/Final.ql": ql.ClassTester(class_name="Final", properties=[
540-
ql.PropertyForTest(
541-
getter="getX", is_single=True, type="string"),
556+
ql.PropertyForTest(getter="getX", type="string"),
557+
ql.PropertyForTest(getter="getNumberOfYs", type="int"),
542558
]),
543559
"Final/Final_getY.ql": ql.PropertyTester(class_name="Final",
544-
property=ql.PropertyForTest(getter="getY", is_repeated=True,
545-
type="int")),
560+
property=ql.PropertyForTest(getter="getY", is_total=False,
561+
is_repeated=True,
562+
type="bool")),
546563
}
547564

548565

@@ -692,7 +709,8 @@ def test_property_doc_abbreviations(generate_classes, abbr, expected):
692709
"Object.qll": (ql.Stub(name="Object", base_import=gen_import_prefix + "Object"),
693710
ql.Class(name="Object", final=True,
694711
properties=[
695-
ql.Property(singular=f"Foo{abbr.capitalize()}Bar", type="baz", tablename="objects",
712+
ql.Property(singular=f"Foo{abbr.capitalize()}Bar", type="baz",
713+
tablename="objects",
696714
tableparams=["this", "result"], doc=expected_doc),
697715
])),
698716
}
@@ -708,7 +726,8 @@ def test_property_doc_abbreviations_ignored_if_within_word(generate_classes, abb
708726
"Object.qll": (ql.Stub(name="Object", base_import=gen_import_prefix + "Object"),
709727
ql.Class(name="Object", final=True,
710728
properties=[
711-
ql.Property(singular=f"Foo{abbr.capitalize()}acadabraBar", type="baz", tablename="objects",
729+
ql.Property(singular=f"Foo{abbr.capitalize()}acadabraBar", type="baz",
730+
tablename="objects",
712731
tableparams=["this", "result"], doc=expected_doc),
713732
])),
714733
}
@@ -726,11 +745,13 @@ def test_repeated_property_doc_override_with_format(generate_classes):
726745
ql.Property(singular="X", plural="Xes", type="int",
727746
tablename="my_object_xes",
728747
tableparams=["this", "index", "result"],
729-
doc="special child of this", doc_plural="special children of this"),
748+
doc="special child of this",
749+
doc_plural="special children of this"),
730750
ql.Property(singular="Y", plural="Ys", type="int",
731751
tablename="my_object_ies", is_optional=True,
732752
tableparams=["this", "index", "result"],
733-
doc="special child of this", doc_plural="special children of this"),
753+
doc="special child of this",
754+
doc_plural="special children of this"),
734755
])),
735756
}
736757

0 commit comments

Comments
 (0)