Skip to content

Commit 86ebb0b

Browse files
committed
Swift: fix qltest skipping and skip isUnknown
Also remove obsolete accessor and function hand-written tests.
1 parent 234e05c commit 86ebb0b

35 files changed

+143
-322
lines changed

swift/codegen/generators/qlgen.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def get_ql_property(cls: schema.Class, prop: schema.Property):
2929
**common_args,
3030
singular=inflection.camelize(prop.name),
3131
tablename=inflection.tableize(cls.name),
32-
tableparams=["this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single],
32+
tableparams=[
33+
"this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single],
3334
)
3435
elif prop.is_repeated:
3536
return ql.Property(
@@ -49,7 +50,8 @@ def get_ql_property(cls: schema.Class, prop: schema.Property):
4950
elif prop.is_predicate:
5051
return ql.Property(
5152
**common_args,
52-
singular=inflection.camelize(prop.name, uppercase_first_letter=False),
53+
singular=inflection.camelize(
54+
prop.name, uppercase_first_letter=False),
5355
tablename=inflection.underscore(f"{cls.name}_{prop.name}"),
5456
tableparams=["this"],
5557
)
@@ -62,6 +64,7 @@ def get_ql_class(cls: schema.Class):
6264
final=not cls.derived,
6365
properties=[get_ql_property(cls, p) for p in cls.properties],
6466
dir=cls.dir,
67+
skip_qltest="no_qltest" in cls.tags,
6568
)
6669

6770

@@ -100,20 +103,22 @@ def format(codeql, files):
100103
log.debug(line.strip())
101104

102105

103-
def _get_all_properties(cls: ql.Class, lookup: typing.Dict[str, ql.Class]) -> typing.Iterable[ql.Property]:
106+
def _get_all_properties(cls: ql.Class, lookup: typing.Dict[str, ql.Class]) -> typing.Iterable[
107+
typing.Tuple[ql.Class, ql.Property]]:
104108
for b in cls.bases:
105-
for p in _get_all_properties(lookup[b], lookup):
106-
yield p
109+
base = lookup[b]
110+
for item in _get_all_properties(base, lookup):
111+
yield item
107112
for p in cls.properties:
108-
yield p
113+
yield cls, p
109114

110115

111116
def _get_all_properties_to_be_tested(cls: ql.Class, lookup: typing.Dict[str, ql.Class]) -> typing.Iterable[
112117
ql.PropertyForTest]:
113118
# deduplicate using id
114119
already_seen = set()
115-
for p in _get_all_properties(cls, lookup):
116-
if not p.skip_qltest and id(p) not in already_seen:
120+
for c, p in _get_all_properties(cls, lookup):
121+
if not (c.skip_qltest or p.skip_qltest or id(p) in already_seen):
117122
already_seen.add(id(p))
118123
yield ql.PropertyForTest(p.getter, p.type, p.is_single, p.is_predicate, p.is_repeated)
119124

@@ -153,30 +158,35 @@ def generate(opts, renderer):
153158
renderer.render(c, qll)
154159
stub_file = stub_out / c.path.with_suffix(".qll")
155160
if not stub_file.is_file() or is_generated(stub_file):
156-
stub = ql.Stub(name=c.name, base_import=get_import(qll, opts.swift_dir))
161+
stub = ql.Stub(
162+
name=c.name, base_import=get_import(qll, opts.swift_dir))
157163
renderer.render(stub, stub_file)
158164

159165
# for example path/to/elements -> path/to/elements.qll
160166
include_file = stub_out.with_suffix(".qll")
161167
all_imports = ql.ImportList(list(sorted(imports.values())))
162168
renderer.render(all_imports, include_file)
163169

164-
renderer.render(ql.GetParentImplementation(classes), out / 'GetImmediateParent.qll')
170+
renderer.render(ql.GetParentImplementation(
171+
classes), out / 'GetImmediateParent.qll')
165172

166173
for c in classes:
167-
if not c.final:
174+
if not c.final or c.skip_qltest:
168175
continue
169176
test_dir = test_out / c.path
170177
test_dir.mkdir(parents=True, exist_ok=True)
171178
if not any(test_dir.glob("*.swift")):
172179
log.warning(f"no test source in {c.path}")
173-
renderer.render(ql.MissingTestInstructions(), test_dir / missing_test_source_filename)
180+
renderer.render(ql.MissingTestInstructions(),
181+
test_dir / missing_test_source_filename)
174182
continue
175183
total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, lookup),
176184
lambda p: p.is_single or p.is_predicate)
177-
renderer.render(ql.ClassTester(class_name=c.name, properties=total_props), test_dir / f"{c.name}.ql")
185+
renderer.render(ql.ClassTester(class_name=c.name,
186+
properties=total_props), test_dir / f"{c.name}.ql")
178187
for p in partial_props:
179-
renderer.render(ql.PropertyTester(class_name=c.name, property=p), test_dir / f"{c.name}_{p.getter}.ql")
188+
renderer.render(ql.PropertyTester(class_name=c.name,
189+
property=p), test_dir / f"{c.name}_{p.getter}.ql")
180190

181191
renderer.cleanup(existing)
182192
if opts.ql_format:

swift/codegen/lib/ql.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class Class:
7979
properties: List[Property] = field(default_factory=list)
8080
dir: pathlib.Path = pathlib.Path()
8181
imports: List[str] = field(default_factory=list)
82+
skip_qltest: bool = False
8283

8384
def __post_init__(self):
8485
self.bases = sorted(self.bases)

swift/codegen/schema.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ _directories:
1313
stmt: Stmt$
1414

1515
Element:
16-
is_unknown: predicate
16+
is_unknown:
17+
type: predicate
18+
_tags: [ no_qltest ]
1719

1820
File:
1921
name: string

swift/codegen/templates/ql_test_class.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import codeql.swift.elements
44
import TestUtils
55

66
from {{class_name}} x{{#properties}}, {{#is_single}}{{type}}{{/is_single}}{{#is_predicate}}string{{/is_predicate}} {{getter}}{{/properties}}
7-
where toBeTested(x)
7+
where toBeTested(x) and not x.isUnknown()
88
{{#properties}}
99
{{#is_single}}
1010
and {{getter}} = x.{{getter}}()

swift/codegen/templates/ql_test_property.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ import TestUtils
55

66
{{#property}}
77
from {{class_name}} x{{#is_repeated}}, int index{{/is_repeated}}
8-
where toBeTested(x)
8+
where toBeTested(x) and not x.isUnknown()
99
select x, {{#is_repeated}}index, {{/is_repeated}}x.{{getter}}({{#is_repeated}}index{{/is_repeated}})
1010
{{/property}}

swift/codegen/test/test_qlgen.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,10 @@ def test_test_total_properties(opts, generate_tests):
406406
]),
407407
]) == {
408408
"B/B.ql": ql.ClassTester(class_name="B", properties=[
409-
ql.PropertyForTest(getter="getX", is_single=True, type="string"),
410-
ql.PropertyForTest(getter="y", is_predicate=True, type="predicate"),
409+
ql.PropertyForTest(
410+
getter="getX", is_single=True, type="string"),
411+
ql.PropertyForTest(
412+
getter="y", is_predicate=True, type="predicate"),
411413
])
412414
}
413415

@@ -443,13 +445,55 @@ def test_test_properties_deduplicated(opts, generate_tests):
443445
schema.Class("Final", bases={"A", "B"}),
444446
]) == {
445447
"Final/Final.ql": ql.ClassTester(class_name="Final", properties=[
446-
ql.PropertyForTest(getter="getX", is_single=True, type="string"),
448+
ql.PropertyForTest(
449+
getter="getX", is_single=True, type="string"),
447450
]),
448451
"Final/Final_getY.ql": ql.PropertyTester(class_name="Final",
449452
property=ql.PropertyForTest(getter="getY", is_repeated=True,
450453
type="int")),
451454
}
452455

453456

457+
def test_test_properties_skipped(opts, generate_tests):
458+
write(opts.ql_test_output / "Derived" / "test.swift")
459+
assert generate_tests([
460+
schema.Class("Base", derived={"Derived"}, properties=[
461+
schema.SingleProperty("x", "string", tags=["no_qltest", "foo"]),
462+
schema.RepeatedProperty("y", "int", tags=["bar", "no_qltest"]),
463+
]),
464+
schema.Class("Derived", bases={"Base"}, properties=[
465+
schema.PredicateProperty("a", tags=["no_qltest"]),
466+
schema.OptionalProperty(
467+
"b", "int", tags=["bar", "no_qltest", "baz"]),
468+
]),
469+
]) == {
470+
"Derived/Derived.ql": ql.ClassTester(class_name="Derived"),
471+
}
472+
473+
474+
def test_test_base_class_skipped(opts, generate_tests):
475+
write(opts.ql_test_output / "Derived" / "test.swift")
476+
assert generate_tests([
477+
schema.Class("Base", derived={"Derived"}, tags=["no_qltest", "foo"], properties=[
478+
schema.SingleProperty("x", "string"),
479+
schema.RepeatedProperty("y", "int"),
480+
]),
481+
schema.Class("Derived", bases={"Base"}),
482+
]) == {
483+
"Derived/Derived.ql": ql.ClassTester(class_name="Derived"),
484+
}
485+
486+
487+
def test_test_final_class_skipped(opts, generate_tests):
488+
write(opts.ql_test_output / "Derived" / "test.swift")
489+
assert generate_tests([
490+
schema.Class("Base", derived={"Derived"}),
491+
schema.Class("Derived", bases={"Base"}, tags=["no_qltest", "foo"], properties=[
492+
schema.SingleProperty("x", "string"),
493+
schema.RepeatedProperty("y", "int"),
494+
]),
495+
]) == {}
496+
497+
454498
if __name__ == '__main__':
455499
sys.exit(pytest.main([__file__] + sys.argv[1:]))

swift/ql/test/extractor-tests/declarations/accessor.expected

Lines changed: 0 additions & 53 deletions
This file was deleted.

swift/ql/test/extractor-tests/declarations/accessor.ql

Lines changed: 0 additions & 21 deletions
This file was deleted.

swift/ql/test/extractor-tests/declarations/func.expected

Lines changed: 0 additions & 58 deletions
This file was deleted.

swift/ql/test/extractor-tests/declarations/func.ql

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)