Merge pull request #9891 from github/redsun82/swift-first-prototype-of-generated-ipa-layer

Swift: first prototype of a generated IPA layer
This commit is contained in:
Paolo Tranquilli
2022-08-16 18:08:03 +02:00
committed by GitHub
568 changed files with 9867 additions and 2100 deletions

View File

@@ -83,7 +83,7 @@ class Processor:
def generate(opts, renderer):
assert opts.cpp_output
processor = Processor({cls.name: cls for cls in schema.load(opts.schema).classes})
processor = Processor(schema.load(opts.schema).classes)
out = opts.cpp_output
for dir, classes in processor.get_classes().items():
include_parent = (dir != pathlib.Path())

View File

@@ -88,7 +88,7 @@ def cls_to_dbscheme(cls: schema.Class):
def get_declarations(data: schema.Schema):
return [d for cls in data.classes for d in cls_to_dbscheme(cls)]
return [d for cls in data.classes.values() for d in cls_to_dbscheme(cls)]
def get_includes(data: schema.Schema, include_dir: pathlib.Path, swift_dir: pathlib.Path):

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# TODO this should probably be split in different generators now: ql, qltest, maybe qlipa
import logging
import pathlib
@@ -8,6 +9,7 @@ import typing
import itertools
import inflection
from toposort import toposort_flatten
from swift.codegen.lib import schema, ql
@@ -27,8 +29,8 @@ class ModifiedStubMarkedAsGeneratedError(Error):
pass
def get_ql_property(cls: schema.Class, prop: schema.Property):
common_args = dict(
def get_ql_property(cls: schema.Class, prop: schema.Property) -> ql.Property:
args = dict(
type=prop.type if not prop.is_predicate else "predicate",
qltest_skip="qltest_skip" in prop.pragmas,
is_child=prop.is_child,
@@ -36,39 +38,36 @@ def get_ql_property(cls: schema.Class, prop: schema.Property):
is_predicate=prop.is_predicate,
)
if prop.is_single:
return ql.Property(
**common_args,
args.update(
singular=inflection.camelize(prop.name),
tablename=inflection.tableize(cls.name),
tableparams=[
"this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single],
tableparams=["this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single],
)
elif prop.is_repeated:
return ql.Property(
**common_args,
args.update(
singular=inflection.singularize(inflection.camelize(prop.name)),
plural=inflection.pluralize(inflection.camelize(prop.name)),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "index", "result"],
)
elif prop.is_optional:
return ql.Property(
**common_args,
args.update(
singular=inflection.camelize(prop.name),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "result"],
)
elif prop.is_predicate:
return ql.Property(
**common_args,
singular=inflection.camelize(
prop.name, uppercase_first_letter=False),
args.update(
singular=inflection.camelize(prop.name, uppercase_first_letter=False),
tablename=inflection.underscore(f"{cls.name}_{prop.name}"),
tableparams=["this"],
)
else:
raise ValueError(f"unknown property kind for {prop.name} from {cls.name}")
return ql.Property(**args)
def get_ql_class(cls: schema.Class):
def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]):
pragmas = {k: True for k in cls.pragmas if k.startswith("ql")}
return ql.Class(
name=cls.name,
@@ -76,10 +75,42 @@ def get_ql_class(cls: schema.Class):
final=not cls.derived,
properties=[get_ql_property(cls, p) for p in cls.properties],
dir=cls.dir,
ipa=bool(cls.ipa),
**pragmas,
)
def _to_db_type(x: str) -> str:
if x[0].isupper():
return "Raw::" + x
return x
_final_db_class_lookup = {}
def get_ql_ipa_class_db(name: str) -> ql.Synth.FinalClassDb:
return _final_db_class_lookup.setdefault(name, ql.Synth.FinalClassDb(name=name,
params=[
ql.Synth.Param("id", _to_db_type(name))]))
def get_ql_ipa_class(cls: schema.Class):
if cls.derived:
return ql.Synth.NonFinalClass(name=cls.name, derived=sorted(cls.derived),
root=(cls.name == schema.root_class_name))
if cls.ipa and cls.ipa.from_class is not None:
source = cls.ipa.from_class
get_ql_ipa_class_db(source).subtract_type(cls.name)
return ql.Synth.FinalClassDerivedIpa(name=cls.name,
params=[ql.Synth.Param("id", _to_db_type(source))])
if cls.ipa and cls.ipa.on_arguments is not None:
return ql.Synth.FinalClassFreshIpa(name=cls.name,
params=[ql.Synth.Param(k, _to_db_type(v))
for k, v in cls.ipa.on_arguments.items()])
return get_ql_ipa_class_db(cls.name)
def get_import(file: pathlib.Path, swift_dir: pathlib.Path):
stem = file.relative_to(swift_dir / "ql/lib").with_suffix("")
return str(stem).replace("/", ".")
@@ -96,10 +127,10 @@ def get_classes_used_by(cls: ql.Class):
return sorted(set(t for t in get_types_used_by(cls) if t[0].isupper()))
_generated_stub_re = re.compile(r"private import .*\n\nclass \w+ extends \w+ \{[ \n]\}", re.MULTILINE)
_generated_stub_re = re.compile(r"\n*private import .*\n+class \w+ extends \w+ \{[ \n]?\}", re.MULTILINE)
def _is_generated_stub(file):
def _is_generated_stub(file: pathlib.Path) -> bool:
with open(file) as contents:
for line in contents:
if not line.startswith("// generated"):
@@ -108,12 +139,14 @@ def _is_generated_stub(file):
else:
# no lines
return False
# one line already read, if we can read 5 other we are past the normal stub generation
line_threshold = 5
first_lines = list(itertools.islice(contents, line_threshold))
if len(first_lines) == line_threshold or not _generated_stub_re.match("".join(first_lines)):
raise ModifiedStubMarkedAsGeneratedError(
f"{file.name} stub was modified but is still marked as generated")
# we still do not detect modified synth constructors
if not file.name.endswith("Constructor.qll"):
# one line already read, if we can read 5 other we are past the normal stub generation
line_threshold = 5
first_lines = list(itertools.islice(contents, line_threshold))
if len(first_lines) == line_threshold or not _generated_stub_re.match("".join(first_lines)):
raise ModifiedStubMarkedAsGeneratedError(
f"{file.name} stub was modified but is still marked as generated")
return True
@@ -129,45 +162,53 @@ def format(codeql, files):
log.debug(line.strip())
def _get_all_properties(cls: ql.Class, lookup: typing.Dict[str, ql.Class]) -> typing.Iterable[
typing.Tuple[ql.Class, ql.Property]]:
for b in cls.bases:
def _get_all_properties(cls: schema.Class, lookup: typing.Dict[str, schema.Class],
already_seen: typing.Optional[typing.Set[int]] = None) -> \
typing.Iterable[typing.Tuple[schema.Class, schema.Property]]:
# deduplicate using ids
if already_seen is None:
already_seen = set()
for b in sorted(cls.bases):
base = lookup[b]
for item in _get_all_properties(base, lookup):
for item in _get_all_properties(base, lookup, already_seen):
yield item
for p in cls.properties:
yield cls, p
def _get_all_properties_to_be_tested(cls: ql.Class, lookup: typing.Dict[str, ql.Class]) -> typing.Iterable[
ql.PropertyForTest]:
# deduplicate using id
already_seen = set()
for c, p in _get_all_properties(cls, lookup):
if not (c.qltest_skip or p.qltest_skip or id(p) in already_seen):
if id(p) not in already_seen:
already_seen.add(id(p))
yield cls, p
def _get_all_properties_to_be_tested(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> \
typing.Iterable[ql.PropertyForTest]:
for c, p in _get_all_properties(cls, lookup):
if not ("qltest_skip" in c.pragmas or "qltest_skip" in p.pragmas):
# TODO here operations are duplicated, but should be better if we split ql and qltest generation
p = get_ql_property(c, p)
yield ql.PropertyForTest(p.getter, p.type, p.is_single, p.is_predicate, p.is_repeated)
def _partition_iter(x, pred):
x1, x2 = itertools.tee(x)
return filter(pred, x1), itertools.filterfalse(pred, x2)
def _partition(l, pred):
""" partitions a list according to boolean predicate """
res = ([], [])
for x in l:
res[not pred(x)].append(x)
return res
return map(list, _partition_iter(l, pred))
def _is_in_qltest_collapsed_hierachy(cls: ql.Class, lookup: typing.Dict[str, ql.Class]):
return cls.qltest_collapse_hierarchy or _is_under_qltest_collapsed_hierachy(cls, lookup)
def _is_in_qltest_collapsed_hierachy(cls: schema.Class, lookup: typing.Dict[str, schema.Class]):
return "qltest_collapse_hierarchy" in cls.pragmas or _is_under_qltest_collapsed_hierachy(cls, lookup)
def _is_under_qltest_collapsed_hierachy(cls: ql.Class, lookup: typing.Dict[str, ql.Class]):
return not cls.qltest_uncollapse_hierarchy and any(
def _is_under_qltest_collapsed_hierachy(cls: schema.Class, lookup: typing.Dict[str, schema.Class]):
return "qltest_uncollapse_hierarchy" not in cls.pragmas and any(
_is_in_qltest_collapsed_hierachy(lookup[b], lookup) for b in cls.bases)
def _should_skip_qltest(cls: ql.Class, lookup: typing.Dict[str, ql.Class]):
return cls.qltest_skip or not (cls.final or cls.qltest_collapse_hierarchy) or _is_under_qltest_collapsed_hierachy(
def _should_skip_qltest(cls: schema.Class, lookup: typing.Dict[str, schema.Class]):
return "qltest_skip" in cls.pragmas or not (
cls.final or "qltest_collapse_hierarchy" in cls.pragmas) or _is_under_qltest_collapsed_hierachy(
cls, lookup)
@@ -185,15 +226,18 @@ def generate(opts, renderer):
data = schema.load(input)
classes = [get_ql_class(cls) for cls in data.classes]
lookup = {cls.name: cls for cls in classes}
classes.sort(key=lambda cls: (cls.dir, cls.name))
classes = {name: get_ql_class(cls, data.classes) for name, cls in data.classes.items()}
imports = {}
for c in classes:
inheritance_graph = {name: cls.bases for name, cls in data.classes.items()}
db_classes = [classes[name] for name in toposort_flatten(inheritance_graph) if not classes[name].ipa]
renderer.render(ql.DbClasses(db_classes), out / "Raw.qll")
classes_by_dir_and_name = sorted(classes.values(), key=lambda cls: (cls.dir, cls.name))
for c in classes_by_dir_and_name:
imports[c.name] = get_import(stub_out / c.path, opts.swift_dir)
for c in classes:
for c in classes.values():
qll = out / c.path.with_suffix(".qll")
c.imports = [imports[t] for t in get_classes_used_by(c)]
renderer.render(c, qll)
@@ -207,20 +251,19 @@ def generate(opts, renderer):
include_file = stub_out.with_suffix(".qll")
renderer.render(ql.ImportList(list(imports.values())), include_file)
renderer.render(ql.GetParentImplementation(
classes), out / 'GetImmediateParent.qll')
renderer.render(ql.GetParentImplementation(classes_by_dir_and_name), out / 'GetImmediateParent.qll')
for c in classes:
if _should_skip_qltest(c, lookup):
for c in data.classes.values():
if _should_skip_qltest(c, data.classes):
continue
test_dir = test_out / c.path
test_dir = test_out / c.dir / c.name
test_dir.mkdir(parents=True, exist_ok=True)
if not any(test_dir.glob("*.swift")):
log.warning(f"no test source in {c.path}")
log.warning(f"no test source in {c.dir / c.name}")
renderer.render(ql.MissingTestInstructions(),
test_dir / missing_test_source_filename)
continue
total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, lookup),
total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, data.classes),
lambda p: p.is_single or p.is_predicate)
renderer.render(ql.ClassTester(class_name=c.name,
properties=total_props), test_dir / f"{c.name}.ql")
@@ -228,6 +271,29 @@ def generate(opts, renderer):
renderer.render(ql.PropertyTester(class_name=c.name,
property=p), test_dir / f"{c.name}_{p.getter}.ql")
final_ipa_types = []
non_final_ipa_types = []
constructor_imports = []
ipa_constructor_imports = []
for cls in sorted(data.classes.values(), key=lambda cls: (cls.dir, cls.name)):
ipa_type = get_ql_ipa_class(cls)
if ipa_type.is_final:
final_ipa_types.append(ipa_type)
if ipa_type.has_params:
stub_file = stub_out / cls.dir / f"{cls.name}Constructor.qll"
if not stub_file.is_file() or _is_generated_stub(stub_file):
renderer.render(ql.Synth.ConstructorStub(ipa_type), stub_file)
constructor_import = get_import(stub_file, opts.swift_dir)
constructor_imports.append(constructor_import)
if ipa_type.is_ipa:
ipa_constructor_imports.append(constructor_import)
else:
non_final_ipa_types.append(ipa_type)
renderer.render(ql.Synth.Types(schema.root_class_name, final_ipa_types, non_final_ipa_types), out / "Synth.qll")
renderer.render(ql.ImportList(constructor_imports), out / "SynthConstructors.qll")
renderer.render(ql.ImportList(ipa_constructor_imports), out / "PureSynthConstructors.qll")
renderer.cleanup(existing)
if opts.ql_format:
format(opts.codeql_binary, renderer.written)

View File

@@ -14,7 +14,7 @@ left behind and must be dealt with by hand.
import pathlib
from dataclasses import dataclass, field
from typing import List, ClassVar
from typing import List, ClassVar, Union, Optional
import inflection
@@ -28,12 +28,11 @@ class Param:
@dataclass
class Property:
singular: str
type: str = None
tablename: str = None
type: Optional[str] = None
tablename: Optional[str] = None
tableparams: List[Param] = field(default_factory=list)
plural: str = None
plural: Optional[str] = None
first: bool = False
local_var: str = "x"
is_optional: bool = False
is_predicate: bool = False
is_child: bool = False
@@ -41,8 +40,6 @@ class Property:
def __post_init__(self):
if self.tableparams:
if self.type_is_class:
self.tableparams = [x if x != "result" else self.local_var for x in self.tableparams]
self.tableparams = [Param(x) for x in self.tableparams]
self.tableparams[0].first = True
@@ -82,6 +79,7 @@ class Class:
qltest_skip: bool = False
qltest_collapse_hierarchy: bool = False
qltest_uncollapse_hierarchy: bool = False
ipa: bool = False
def __post_init__(self):
self.bases = sorted(self.bases)
@@ -89,17 +87,17 @@ class Class:
self.properties[0].first = True
@property
def db_id(self):
return "@" + inflection.underscore(self.name)
@property
def root(self):
def root(self) -> bool:
return not self.bases
@property
def path(self):
def path(self) -> pathlib.Path:
return self.dir / self.name
@property
def db_id(self):
return "@" + inflection.underscore(self.name)
@dataclass
class Stub:
@@ -109,6 +107,13 @@ class Stub:
base_import: str
@dataclass
class DbClasses:
template: ClassVar = 'ql_db'
classes: List[Class] = field(default_factory=list)
@dataclass
class ImportList:
template: ClassVar = 'ql_imports'
@@ -126,7 +131,7 @@ class GetParentImplementation:
@dataclass
class PropertyForTest:
getter: str
type: str = None
type: Optional[str] = None
is_single: bool = False
is_predicate: bool = False
is_repeated: bool = False
@@ -151,3 +156,96 @@ class PropertyTester:
@dataclass
class MissingTestInstructions:
template: ClassVar = 'ql_test_missing'
class Synth:
@dataclass
class Class:
is_final: ClassVar = False
name: str
first: bool = False
@dataclass
class Param:
param: str
type: str
first: bool = False
@dataclass
class FinalClass(Class):
is_final: ClassVar = True
is_derived_ipa: ClassVar = False
is_fresh_ipa: ClassVar = False
is_db: ClassVar = False
params: List["Synth.Param"] = field(default_factory=list)
def __post_init__(self):
if self.params:
self.params[0].first = True
@property
def is_ipa(self):
return self.is_fresh_ipa or self.is_derived_ipa
@property
def has_params(self) -> bool:
return bool(self.params)
@dataclass
class FinalClassIpa(FinalClass):
pass
@dataclass
class FinalClassDerivedIpa(FinalClassIpa):
is_derived_ipa: ClassVar = True
@dataclass
class FinalClassFreshIpa(FinalClassIpa):
is_fresh_ipa: ClassVar = True
@dataclass
class FinalClassDb(FinalClass):
is_db: ClassVar = True
subtracted_ipa_types: List["Synth.Class"] = field(default_factory=list)
def subtract_type(self, type: str):
self.subtracted_ipa_types.append(Synth.Class(type, first=not self.subtracted_ipa_types))
@property
def has_subtracted_ipa_types(self) -> bool:
return bool(self.subtracted_ipa_types)
@property
def db_id(self) -> str:
return "@" + inflection.underscore(self.name)
@dataclass
class NonFinalClass(Class):
derived: List["Synth.Class"] = field(default_factory=list)
root: bool = False
def __post_init__(self):
self.derived = [Synth.Class(c) for c in self.derived]
if self.derived:
self.derived[0].first = True
@dataclass
class Types:
template: ClassVar = "ql_ipa_types"
root: str
final_classes: List["Synth.FinalClass"] = field(default_factory=list)
non_final_classes: List["Synth.NonFinalClass"] = field(default_factory=list)
def __post_init__(self):
if self.final_classes:
self.final_classes[0].first = True
@dataclass
class ConstructorStub:
template: ClassVar = "ql_ipa_constructor_stub"
cls: "Synth.FinalClass"

View File

@@ -2,9 +2,8 @@
import pathlib
import re
import typing
from dataclasses import dataclass, field
from typing import List, Set, Union, Dict, ClassVar
from typing import List, Set, Union, Dict, ClassVar, Optional
import yaml
@@ -57,6 +56,12 @@ class PredicateProperty(Property):
is_predicate: ClassVar = True
@dataclass
class IpaInfo:
from_class: Optional[str] = None
on_arguments: Optional[Dict[str, str]] = None
@dataclass
class Class:
name: str
@@ -65,11 +70,16 @@ class Class:
properties: List[Property] = field(default_factory=list)
dir: pathlib.Path = pathlib.Path()
pragmas: List[str] = field(default_factory=list)
ipa: Optional[IpaInfo] = None
@property
def final(self):
return not self.derived
@dataclass
class Schema:
classes: List[Class]
classes: Dict[str, Class]
includes: Set[str] = field(default_factory=set)
@@ -107,6 +117,11 @@ def _parse_property(name: str, data: Union[str, Dict[str, _StrOrList]], is_child
return SingleProperty(name, type, is_child=is_child, pragmas=pragmas)
def _parse_ipa(data: Dict[str, Union[str, Dict[str, str]]]):
return IpaInfo(from_class=data.get("from"),
on_arguments=data.get(True)) # 'on' is parsed as boolean True in yaml
class _DirSelector:
""" Default output subdirectory selector for generated QL files, based on the `_directories` global field"""
@@ -145,10 +160,12 @@ def load(path):
cls.properties.extend(_parse_property(kk, vv, is_child=True) for kk, vv in v.items())
elif k == "_pragma":
cls.pragmas = _auto_list(v)
elif k == "_synth":
cls.ipa = _parse_ipa(v)
else:
raise Error(f"unknown metadata {k} for class {name}")
if not cls.bases and cls.name != root_class_name:
cls.bases.add(root_class_name)
classes[root_class_name].derived.add(name)
return Schema(classes=list(classes.values()), includes=set(data.get("_includes", [])))
return Schema(classes=classes, includes=set(data.get("_includes", [])))

View File

@@ -19,6 +19,15 @@ Element:
File:
name: string
_pragma: qltest_collapse_hierarchy
DbFile:
_extends: File
UnknownFile:
_extends: File
_synth:
on: {}
Locatable:
location:
@@ -32,7 +41,15 @@ Location:
start_column: int
end_line: int
end_column: int
_pragma: qltest_skip
_pragma: [qltest_skip, qltest_collapse_hierarchy]
DbLocation:
_extends: Location
UnknownLocation:
_extends: Location
_synth:
on: {}
Comment:
_extends: Locatable
@@ -411,7 +428,7 @@ EnumIsCaseExpr:
_extends: Expr
_children:
sub_expr: Expr
element: EnumElementDecl
element: EnumElementDecl
ErrorExpr:
_extends: Expr
@@ -797,6 +814,12 @@ OptionalTryExpr:
TryExpr:
_extends: AnyTryExpr
#MethodCallExpr:
# _extends: ApplyExpr
# _synth:
# from: CallExpr
# qualifier: Expr
BinaryExpr:
_extends: ApplyExpr

View File

@@ -1,10 +1,11 @@
// generated by {{generator}}
private import codeql.swift.generated.Synth
private import codeql.swift.generated.Raw
{{#imports}}
import {{.}}
{{/imports}}
class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} {
class {{name}}Base extends Synth::T{{name}}{{#bases}}, {{.}}{{/bases}} {
{{#root}}
string toString() { none() } // overridden by subclasses
@@ -25,31 +26,45 @@ class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} {
{{/final}}
{{#properties}}
{{type}} {{getter}}({{#is_repeated}}int index{{/is_repeated}}) {
{{#type_is_class}}
exists({{type}} {{local_var}} |
{{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}})
and
result = {{local_var}}.resolve())
{{/type_is_class}}
{{^type_is_class}}
{{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}})
{{/type_is_class}}
{{#type_is_class}}
{{type}} getImmediate{{singular}}({{#is_repeated}}int index{{/is_repeated}}) {
{{^ipa}}
result = Synth::convert{{type}}FromRaw(Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_repeated}}index{{/is_repeated}}))
{{/ipa}}
{{#ipa}}
none()
{{/ipa}}
}
{{#is_optional}}
predicate has{{singular}}({{#is_repeated}}int index{{/is_repeated}}) {
final {{type}} {{getter}}({{#is_repeated}}int index{{/is_repeated}}) {
result = getImmediate{{singular}}({{#is_repeated}}index{{/is_repeated}}).resolve()
}
{{/type_is_class}}
{{^type_is_class}}
{{type}} {{getter}}({{#is_repeated}}int index{{/is_repeated}}) {
{{^ipa}}
{{^is_predicate}}result = {{/is_predicate}}Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_repeated}}index{{/is_repeated}})
{{/ipa}}
{{#ipa}}
none()
{{/ipa}}
}
{{/type_is_class}}
{{#is_optional}}
final predicate has{{singular}}({{#is_repeated}}int index{{/is_repeated}}) {
exists({{getter}}({{#is_repeated}}index{{/is_repeated}}))
}
{{/is_optional}}
{{#is_repeated}}
{{type}} {{indefinite_getter}}() {
final {{type}} {{indefinite_getter}}() {
result = {{getter}}(_)
}
{{^is_optional}}
int getNumberOf{{plural}}() {
final int getNumberOf{{plural}}() {
result = count({{indefinite_getter}}())
}
{{/is_optional}}

View File

@@ -0,0 +1,15 @@
module Raw {
{{#classes}}
class {{name}} extends {{db_id}}{{#bases}}, {{.}}{{/bases}} {
{{#root}}string toString() { none() }{{/root}}
{{#final}}override string toString() { result = "{{name}}" }{{/final}}
{{#properties}}
{{type}} {{getter}}({{#is_repeated}}int index{{/is_repeated}}) {
{{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}})
}
{{/properties}}
}
{{/classes}}
}

View File

@@ -0,0 +1,19 @@
// generated by {{generator}}, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
{{#cls}}
{{#is_db}}
{{#has_subtracted_ipa_types}}
private import codeql.swift.generated.PureSynthConstructors
{{/has_subtracted_ipa_types}}
{{/is_db}}
predicate construct{{name}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) {
{{#is_db}}
{{#subtracted_ipa_types}}{{^first}} and {{/first}}not construct{{name}}(id){{/subtracted_ipa_types}}
{{^subtracted_ipa_types}}any(){{/subtracted_ipa_types}}
{{/is_db}}
{{^is_db}}
none()
{{/is_db}}
}
{{/cls}}

View File

@@ -0,0 +1,62 @@
private import codeql.swift.generated.SynthConstructors
private import codeql.swift.generated.Raw
cached module Synth {
cached newtype T{{root}} =
{{#final_classes}}
{{^first}}
or
{{/first}}
T{{name}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}){{#has_params}} { construct{{name}}({{#params}}{{^first}}, {{/first}}{{param}}{{/params}}) }{{/has_params}}
{{/final_classes}}
{{#non_final_classes}}
{{^root}}
class T{{name}} = {{#derived}}{{^first}} or {{/first}}T{{name}}{{/derived}};
{{/root}}
{{/non_final_classes}}
{{#final_classes}}
cached T{{name}} convert{{name}}FromRaw(Raw::Element e) {
{{^is_fresh_ipa}}
result = T{{name}}(e)
{{/is_fresh_ipa}}
{{#is_fresh_ipa}}
none()
{{/is_fresh_ipa}}
}
{{/final_classes}}
{{#non_final_classes}}
cached T{{name}} convert{{name}}FromRaw(Raw::Element e) {
{{#derived}}
{{^first}}
or
{{/first}}
result = convert{{name}}FromRaw(e)
{{/derived}}
}
{{/non_final_classes}}
{{#final_classes}}
cached Raw::Element convert{{name}}ToRaw(T{{name}} e) {
{{^is_fresh_ipa}}
e = T{{name}}(result)
{{/is_fresh_ipa}}
{{#is_fresh_ipa}}
none()
{{/is_fresh_ipa}}
}
{{/final_classes}}
{{#non_final_classes}}
cached Raw::Element convert{{name}}ToRaw(T{{name}} e) {
{{#derived}}
{{^first}}
or
{{/first}}
result = convert{{name}}ToRaw(e)
{{/derived}}
}
{{/non_final_classes}}
}

View File

@@ -1,6 +1,6 @@
// generated by {{generator}}
import codeql.swift.elements.Element
import codeql.swift.elements
/**
* Gets any of the "immediate" children of `e`. "Immediate" means not taking into account node resolution: for example
@@ -11,25 +11,16 @@ import codeql.swift.elements.Element
cached
Element getAnImmediateChild(Element e) {
// why does this look more complicated than it should?
// * `exists` and the `x` variable are there to reuse the same generation done in classes (where `x` is used to hide
// nodes via resolution)
// * none() simplifies generation, as we can append `or ...` without a special case for the first item
exists(Element x | result = x and (
none()
{{#classes}}
{{#properties}}
{{#is_child}}
or
{{#is_repeated}}
{{tablename}}(e, _, x)
{{/is_repeated}}
{{^is_repeated}}
{{tablename}}(e{{#tableparams}}{{^first}}, {{param}}{{/first}}{{/tableparams}})
{{/is_repeated}}
{{/is_child}}
{{/properties}}
{{/classes}}
))
none()
{{#classes}}
{{#properties}}
{{#is_child}}
or
result = e.({{name}}).getImmediate{{singular}}({{#is_repeated}}_{{/is_repeated}})
{{/is_child}}
{{/properties}}
{{/classes}}
}
/**

View File

@@ -1,5 +1,4 @@
// generated by {{generator}}, remove this comment if you wish to edit this file
private import {{base_import}}
class {{name}} extends {{name}}Base {}

View File

@@ -12,7 +12,7 @@ def generate_grouped(opts, renderer, input):
opts.cpp_output = output_dir
def ret(classes):
input.classes = classes
input.classes = {cls.name: cls for cls in classes}
generated = run_generation(cppgen.generate, opts, renderer)
for f, g in generated.items():
assert isinstance(g, cpp.ClassList), f

View File

@@ -8,7 +8,6 @@ from swift.codegen.generators import dbschemegen
from swift.codegen.lib import dbscheme
from swift.codegen.test.utils import *
InputExpectedPair = collections.namedtuple("InputExpectedPair", ("input", "expected"))
@@ -20,27 +19,32 @@ def dir_param(request):
return request.param
def generate(opts, renderer):
(out, data), = run_generation(dbschemegen.generate, opts, renderer).items()
assert out is opts.dbscheme
return data
@pytest.fixture
def generate(opts, input, renderer):
def func(classes):
input.classes = {cls.name: cls for cls in classes}
(out, data), = run_generation(dbschemegen.generate, opts, renderer).items()
assert out is opts.dbscheme
return data
return func
def test_empty(opts, input, renderer):
assert generate(opts, renderer) == dbscheme.Scheme(
def test_empty(generate):
assert generate([]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[],
)
def test_includes(opts, input, renderer):
def test_includes(input, opts, generate):
includes = ["foo", "bar"]
input.includes = includes
for i in includes:
write(opts.schema.parent / i, i + " data")
assert generate(opts, renderer) == dbscheme.Scheme(
assert generate([]) == dbscheme.Scheme(
src=schema_file,
includes=[
dbscheme.SchemeInclude(
@@ -52,11 +56,10 @@ def test_includes(opts, input, renderer):
)
def test_empty_final_class(opts, input, renderer, dir_param):
input.classes = [
def test_empty_final_class(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -71,14 +74,12 @@ def test_empty_final_class(opts, input, renderer, dir_param):
)
def test_final_class_with_single_scalar_field(opts, input, renderer, dir_param):
input.classes = [
def test_final_class_with_single_scalar_field(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
schema.SingleProperty("foo", "bar"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -93,13 +94,12 @@ def test_final_class_with_single_scalar_field(opts, input, renderer, dir_param):
)
def test_final_class_with_single_class_field(opts, input, renderer, dir_param):
input.classes = [
def test_final_class_with_single_class_field(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
schema.SingleProperty("foo", "Bar"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -114,13 +114,12 @@ def test_final_class_with_single_class_field(opts, input, renderer, dir_param):
)
def test_final_class_with_optional_field(opts, input, renderer, dir_param):
input.classes = [
def test_final_class_with_optional_field(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
schema.OptionalProperty("foo", "bar"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -143,13 +142,12 @@ def test_final_class_with_optional_field(opts, input, renderer, dir_param):
@pytest.mark.parametrize("property_cls", [schema.RepeatedProperty, schema.RepeatedOptionalProperty])
def test_final_class_with_repeated_field(opts, input, renderer, property_cls, dir_param):
input.classes = [
def test_final_class_with_repeated_field(generate, property_cls, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
property_cls("foo", "bar"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -172,13 +170,12 @@ def test_final_class_with_repeated_field(opts, input, renderer, property_cls, di
)
def test_final_class_with_predicate_field(opts, input, renderer, dir_param):
input.classes = [
def test_final_class_with_predicate_field(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
schema.PredicateProperty("foo"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -199,8 +196,8 @@ def test_final_class_with_predicate_field(opts, input, renderer, dir_param):
)
def test_final_class_with_more_fields(opts, input, renderer, dir_param):
input.classes = [
def test_final_class_with_more_fields(generate, dir_param):
assert generate([
schema.Class("Object", dir=dir_param.input, properties=[
schema.SingleProperty("one", "x"),
schema.SingleProperty("two", "y"),
@@ -209,8 +206,7 @@ def test_final_class_with_more_fields(opts, input, renderer, dir_param):
schema.RepeatedOptionalProperty("five", "v"),
schema.PredicateProperty("six"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -259,12 +255,11 @@ def test_final_class_with_more_fields(opts, input, renderer, dir_param):
)
def test_empty_class_with_derived(opts, input, renderer):
input.classes = [
def test_empty_class_with_derived(generate):
assert generate([
schema.Class(
name="Base", derived={"Left", "Right"}),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -276,8 +271,8 @@ def test_empty_class_with_derived(opts, input, renderer):
)
def test_class_with_derived_and_single_property(opts, input, renderer, dir_param):
input.classes = [
def test_class_with_derived_and_single_property(generate, dir_param):
assert generate([
schema.Class(
name="Base",
derived={"Left", "Right"},
@@ -285,8 +280,7 @@ def test_class_with_derived_and_single_property(opts, input, renderer, dir_param
properties=[
schema.SingleProperty("single", "Prop"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -307,8 +301,8 @@ def test_class_with_derived_and_single_property(opts, input, renderer, dir_param
)
def test_class_with_derived_and_optional_property(opts, input, renderer, dir_param):
input.classes = [
def test_class_with_derived_and_optional_property(generate, dir_param):
assert generate([
schema.Class(
name="Base",
derived={"Left", "Right"},
@@ -316,8 +310,7 @@ def test_class_with_derived_and_optional_property(opts, input, renderer, dir_par
properties=[
schema.OptionalProperty("opt", "Prop"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[
@@ -338,8 +331,8 @@ def test_class_with_derived_and_optional_property(opts, input, renderer, dir_par
)
def test_class_with_derived_and_repeated_property(opts, input, renderer, dir_param):
input.classes = [
def test_class_with_derived_and_repeated_property(generate, dir_param):
assert generate([
schema.Class(
name="Base",
dir=dir_param.input,
@@ -347,8 +340,7 @@ def test_class_with_derived_and_repeated_property(opts, input, renderer, dir_par
properties=[
schema.RepeatedProperty("rep", "Prop"),
]),
]
assert generate(opts, renderer) == dbscheme.Scheme(
]) == dbscheme.Scheme(
src=schema_file,
includes=[],
declarations=[

View File

@@ -21,7 +21,7 @@ def test_property_has_first_table_param_marked():
])
def test_property_is_a_class(type, expected):
tableparams = ["a", "result", "b"]
expected_tableparams = ["a", "x" if expected else "result", "b"]
expected_tableparams = ["a", "result" if expected else "result", "b"]
prop = ql.Property("Prop", type, tableparams=tableparams)
assert prop.type_is_class is expected
assert [p.param for p in prop.tableparams] == expected_tableparams
@@ -46,7 +46,7 @@ def test_property_indefinite_article(name, expected_getter):
("X", True),
])
def test_property_is_repeated(plural, expected):
prop = ql.Property("foo", "Foo", "props", ["x"], plural=plural)
prop = ql.Property("foo", "Foo", "props", ["result"], plural=plural)
assert prop.is_repeated is expected
@@ -58,12 +58,13 @@ def test_property_is_repeated(plural, expected):
(False, True, None, False),
])
def test_property_is_single(is_optional, is_predicate, plural, expected):
prop = ql.Property("foo", "Foo", "props", ["x"], plural=plural, is_predicate=is_predicate, is_optional=is_optional)
prop = ql.Property("foo", "Foo", "props", ["result"], plural=plural,
is_predicate=is_predicate, is_optional=is_optional)
assert prop.is_single is expected
def test_property_no_plural_no_indefinite_getter():
prop = ql.Property("Prop", "Foo", "props", ["x"])
prop = ql.Property("Prop", "Foo", "props", ["result"])
assert prop.indefinite_getter is None
@@ -94,11 +95,6 @@ def test_class_has_first_property_marked():
assert cls.properties == expected
def test_class_db_id():
cls = ql.Class("ThisIsMyClass")
assert cls.db_id == "@this_is_my_class"
def test_root_class():
cls = ql.Class("Class")
assert cls.root

View File

@@ -52,7 +52,7 @@ def generate(input, qlgen_opts, renderer):
renderer.written = []
def func(classes):
input.classes = classes
input.classes = {cls.name: cls for cls in classes}
return run_generation(qlgen.generate, qlgen_opts, renderer)
return func
@@ -101,7 +101,9 @@ def _filter_generated_classes(ret, output_test_files=False):
str(f): ret[ql_test_output_path() / f]
for f in test_files
}
assert stub_files == base_files
base_files -= {pathlib.Path(f"{name}.qll") for name in
("Raw", "Synth", "SynthConstructors", "PureSynthConstructors")}
assert base_files <= stub_files
return {
str(f): (ret[stub_path() / f], ret[ql_output_path() / f])
for f in base_files
@@ -128,6 +130,11 @@ def test_empty(generate):
assert generate([]) == {
import_file(): ql.ImportList(),
children_file(): ql.GetParentImplementation(),
ql_output_path() / "Synth.qll": ql.Synth.Types(schema.root_class_name),
ql_output_path() / "SynthConstructors.qll": ql.ImportList(),
ql_output_path() / "PureSynthConstructors.qll": ql.ImportList(),
ql_output_path() / "Raw.qll": ql.DbClasses(),
ql_output_path() / "Raw.qll": ql.DbClasses(),
}
@@ -192,10 +199,11 @@ def test_single_property(generate_classes):
schema.SingleProperty("foo", "bar")]),
]) == {
"MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
ql.Class(name="MyObject", final=True, properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
tableparams=["this", "result"]),
])),
ql.Class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
tableparams=["this", "result"]),
])),
}
@@ -208,14 +216,15 @@ def test_single_properties(generate_classes):
]),
]) == {
"MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
ql.Class(name="MyObject", final=True, properties=[
ql.Property(singular="One", type="x", tablename="my_objects",
tableparams=["this", "result", "_", "_"]),
ql.Property(singular="Two", type="y", tablename="my_objects",
tableparams=["this", "_", "result", "_"]),
ql.Property(singular="Three", type="z", tablename="my_objects",
tableparams=["this", "_", "_", "result"]),
])),
ql.Class(name="MyObject", final=True,
properties=[
ql.Property(singular="One", type="x", tablename="my_objects",
tableparams=["this", "result", "_", "_"]),
ql.Property(singular="Two", type="y", tablename="my_objects",
tableparams=["this", "_", "result", "_"]),
ql.Property(singular="Three", type="z", tablename="my_objects",
tableparams=["this", "_", "_", "result"]),
])),
}

View File

@@ -20,7 +20,7 @@ def load(tmp_path):
def test_empty_schema(load):
ret = load("{}")
assert ret.classes == [schema.Class(root_name)]
assert ret.classes == {root_name: schema.Class(root_name)}
assert ret.includes == set()
@@ -28,10 +28,10 @@ def test_one_empty_class(load):
ret = load("""
MyClass: {}
""")
assert ret.classes == [
schema.Class(root_name, derived={'MyClass'}),
schema.Class('MyClass', bases={root_name}),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'MyClass'}),
'MyClass': schema.Class('MyClass', bases={root_name}),
}
def test_two_empty_classes(load):
@@ -39,11 +39,11 @@ def test_two_empty_classes(load):
MyClass1: {}
MyClass2: {}
""")
assert ret.classes == [
schema.Class(root_name, derived={'MyClass1', 'MyClass2'}),
schema.Class('MyClass1', bases={root_name}),
schema.Class('MyClass2', bases={root_name}),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'MyClass1', 'MyClass2'}),
'MyClass1': schema.Class('MyClass1', bases={root_name}),
'MyClass2': schema.Class('MyClass2', bases={root_name}),
}
def test_two_empty_chained_classes(load):
@@ -52,11 +52,11 @@ MyClass1: {}
MyClass2:
_extends: MyClass1
""")
assert ret.classes == [
schema.Class(root_name, derived={'MyClass1'}),
schema.Class('MyClass1', bases={root_name}, derived={'MyClass2'}),
schema.Class('MyClass2', bases={'MyClass1'}),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'MyClass1'}),
'MyClass1': schema.Class('MyClass1', bases={root_name}, derived={'MyClass2'}),
'MyClass2': schema.Class('MyClass2', bases={'MyClass1'}),
}
def test_empty_classes_diamond(load):
@@ -68,12 +68,12 @@ C:
- A
- B
""")
assert ret.classes == [
schema.Class(root_name, derived={'A', 'B'}),
schema.Class('A', bases={root_name}, derived={'C'}),
schema.Class('B', bases={root_name}, derived={'C'}),
schema.Class('C', bases={'A', 'B'}),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A', 'B'}),
'A': schema.Class('A', bases={root_name}, derived={'C'}),
'B': schema.Class('B', bases={root_name}, derived={'C'}),
'C': schema.Class('C', bases={'A', 'B'}),
}
def test_dir(load):
@@ -81,10 +81,10 @@ def test_dir(load):
A:
_dir: other/dir
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, dir=pathlib.Path("other/dir")),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, dir=pathlib.Path("other/dir")),
}
def test_directory_filter(load):
@@ -101,16 +101,16 @@ Ax: {}
Ay: {}
A: {}
""")
assert ret.classes == [
schema.Class(root_name, derived={'Afoo', 'Bbar', 'Abar', 'Bfoo', 'Ax', 'Ay', 'A'}),
schema.Class('Afoo', bases={root_name}, dir=pathlib.Path("second/dir")),
schema.Class('Bbar', bases={root_name}, dir=pathlib.Path("third/dir")),
schema.Class('Abar', bases={root_name}, dir=pathlib.Path("third/dir")),
schema.Class('Bfoo', bases={root_name}, dir=pathlib.Path("second/dir")),
schema.Class('Ax', bases={root_name}, dir=pathlib.Path("first/dir")),
schema.Class('Ay', bases={root_name}, dir=pathlib.Path("first/dir")),
schema.Class('A', bases={root_name}, dir=pathlib.Path()),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'Afoo', 'Bbar', 'Abar', 'Bfoo', 'Ax', 'Ay', 'A'}),
'Afoo': schema.Class('Afoo', bases={root_name}, dir=pathlib.Path("second/dir")),
'Bbar': schema.Class('Bbar', bases={root_name}, dir=pathlib.Path("third/dir")),
'Abar': schema.Class('Abar', bases={root_name}, dir=pathlib.Path("third/dir")),
'Bfoo': schema.Class('Bfoo', bases={root_name}, dir=pathlib.Path("second/dir")),
'Ax': schema.Class('Ax', bases={root_name}, dir=pathlib.Path("first/dir")),
'Ay': schema.Class('Ay', bases={root_name}, dir=pathlib.Path("first/dir")),
'A': schema.Class('A', bases={root_name}, dir=pathlib.Path()),
}
def test_directory_filter_override(load):
@@ -120,10 +120,10 @@ _directories:
A:
_dir: other/dir
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, dir=pathlib.Path("other/dir")),
]
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, dir=pathlib.Path("other/dir")),
}
def test_lowercase_rejected(load):
@@ -145,16 +145,16 @@ A:
four: x?*
five: predicate
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.SingleProperty('one', 'string'),
schema.OptionalProperty('two', 'int'),
schema.RepeatedProperty('three', 'bool'),
schema.RepeatedOptionalProperty('four', 'x'),
schema.PredicateProperty('five'),
]),
]
}
def test_element_properties(load):
@@ -162,11 +162,11 @@ def test_element_properties(load):
Element:
x: string
""")
assert ret.classes == [
schema.Class(root_name, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, properties=[
schema.SingleProperty('x', 'string'),
]),
]
}
def test_children(load):
@@ -180,9 +180,9 @@ A:
e: E?
f: F?*
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.SingleProperty('a', 'string'),
schema.RepeatedProperty('b', 'B'),
schema.SingleProperty('c', 'C', is_child=True),
@@ -190,7 +190,7 @@ A:
schema.OptionalProperty('e', 'E', is_child=True),
schema.RepeatedOptionalProperty('f', 'F', is_child=True),
]),
]
}
@pytest.mark.parametrize("type", ["string", "int", "boolean", "predicate"])
@@ -209,12 +209,12 @@ A:
x:
type: string*
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.RepeatedProperty('x', 'string'),
]),
]
}
def test_property_with_explicit_type_and_pragmas(load):
@@ -224,12 +224,12 @@ A:
type: string*
_pragma: [foo, bar]
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.RepeatedProperty('x', 'string', pragmas=["foo", "bar"]),
]),
]
}
def test_property_with_explicit_type_and_one_pragma(load):
@@ -239,12 +239,12 @@ A:
type: string*
_pragma: foo
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.RepeatedProperty('x', 'string', pragmas=["foo"]),
]),
]
}
def test_property_with_explicit_type_and_unknown_metadata(load):
@@ -272,12 +272,12 @@ A:
x: string*
_pragma: [foo, bar]
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.RepeatedProperty('x', 'string'),
], pragmas=["foo", "bar"]),
]
}
def test_class_with_one_pragma(load):
@@ -286,12 +286,12 @@ A:
x: string*
_pragma: foo
""")
assert ret.classes == [
schema.Class(root_name, derived={'A'}),
schema.Class('A', bases={root_name}, properties=[
assert ret.classes == {
root_name: schema.Class(root_name, derived={'A'}),
'A': schema.Class('A', bases={root_name}, properties=[
schema.RepeatedProperty('x', 'string'),
], pragmas=["foo"]),
]
}
def test_class_with_unknown_metadata(load):
@@ -303,5 +303,34 @@ A:
""")
def test_ipa_class_from(load):
ret = load("""
MyClass:
_synth:
from: A
""")
assert ret.classes == {
root_name: schema.Class(root_name, derived={'MyClass'}),
'MyClass': schema.Class('MyClass', bases={root_name}, ipa=schema.IpaInfo(from_class="A")),
}
def test_ipa_class_on(load):
ret = load("""
MyClass:
_synth:
on:
x: A
y: int
""")
assert ret.classes == {
root_name: schema.Class(root_name, derived={'MyClass'}),
'MyClass': schema.Class('MyClass', bases={root_name}, ipa=schema.IpaInfo(on_arguments={"x": "A", "y": "int"})),
}
# TODO rejection tests and implementation for malformed `_synth` clauses
if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:]))

View File

@@ -96,14 +96,6 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
}
TrapDomain trap{*trapTarget};
// TODO: remove this and recreate it with IPA when we have that
// the following cannot conflict with actual files as those have an absolute path starting with /
File unknownFileEntry{trap.createLabel<FileTag>("unknown")};
Location unknownLocationEntry{trap.createLabel<LocationTag>("unknown")};
unknownLocationEntry.file = unknownFileEntry.id;
trap.emit(unknownFileEntry);
trap.emit(unknownLocationEntry);
std::vector<swift::Token> comments;
if (primaryFile && primaryFile->getBufferID().hasValue()) {
auto& sourceManager = compiler.getSourceMgr();

View File

@@ -258,13 +258,13 @@ class SwiftDispatcher {
return;
}
auto file = getFilePath(sourceManager.getDisplayNameForLoc(start));
Location entry{{}};
DbLocation entry{{}};
entry.file = fetchLabel(file);
std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
entry.id = trap.createLabel<LocationTag>('{', entry.file, "}:", entry.start_line, ':',
entry.start_column, ':', entry.end_line, ':',
entry.end_column);
entry.id = trap.createLabel<DbLocationTag>('{', entry.file, "}:", entry.start_line, ':',
entry.start_column, ':', entry.end_line, ':',
entry.end_column);
emit(entry);
emit(LocatableLocationsTrap{locatableLabel, entry.id});
}

View File

@@ -69,7 +69,7 @@ MAP_TYPE_TO_TAG(swift::TypeBase, TypeTag);
OVERRIDE_TAG(FuncDecl, ConcreteFuncDeclTag);
OVERRIDE_TAG(VarDecl, ConcreteVarDeclTag);
MAP_TYPE_TO_TAG(FilePath, FileTag);
MAP_TYPE_TO_TAG(FilePath, DbFileTag);
#undef MAP_TAG
#undef MAP_SUBTAG

View File

@@ -6,6 +6,8 @@ private import internal.ControlFlowGraphImpl
private import internal.ControlFlowElements
private import CfgNodes
private import SuccessorTypes
private import codeql.swift.generated.Raw
private import codeql.swift.generated.Synth
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
@@ -195,11 +197,14 @@ class ExitBasicBlock extends BasicBlock {
}
private module JoinBlockPredecessors {
private predicate id(AstNode x, AstNode y) { x = y }
private predicate id(Raw::AstNode x, Raw::AstNode y) { x = y }
private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
private predicate idOfDbAstNode(Raw::AstNode x, int y) = equivalenceRelation(id/2)(x, y)
private AstNode projctToAst(ControlFlowElement n) {
// TODO does not work if fresh ipa entities (`ipa: on:`) turn out to be first of the block
private predicate idOf(AstNode x, int y) { idOfDbAstNode(Synth::convertAstNodeToRaw(x), y) }
private AstNode projectToAst(ControlFlowElement n) {
result = n.asAstNode()
or
isPropertyGetterElement(n, _, result)
@@ -214,7 +219,7 @@ private module JoinBlockPredecessors {
}
int getId(JoinBlockPredecessor jbp) {
idOf(projctToAst(jbp.getFirstNode().(CfgNode).getNode()), result)
idOf(projectToAst(jbp.getFirstNode().(CfgNode).getNode()), result)
or
idOf(jbp.(EntryBasicBlock).getScope(), result)
}

View File

@@ -33,6 +33,7 @@
private import swift
private import codeql.swift.controlflow.ControlFlowGraph
private import codeql.swift.generated.Synth
private import Completion
private import Scope
import ControlFlowGraphImplShared
@@ -379,9 +380,9 @@ module Stmts {
* Control-flow for loops.
*/
module Loops {
class ConditionalLoop = @while_stmt or @repeat_while_stmt;
class ConditionalLoop = Synth::TWhileStmt or Synth::TRepeatWhileStmt;
class LoopStmt = @for_each_stmt or ConditionalLoop;
class LoopStmt = Synth::TForEachStmt or ConditionalLoop;
abstract class LoopTree extends AstPreOrderTree {
LoopTree() { ast instanceof ConditionalLoop }
@@ -1706,7 +1707,8 @@ module Exprs {
}
module Conversions {
class ConversionOrIdentity = @identity_expr or @explicit_cast_expr or @implicit_conversion_expr;
class ConversionOrIdentity =
Synth::TIdentityExpr or Synth::TExplicitCastExpr or Synth::TImplicitConversionExpr;
abstract class ConversionOrIdentityTree extends AstStandardPostOrderTree {
ConversionOrIdentityTree() { ast instanceof ConversionOrIdentity }

View File

@@ -1,8 +1,9 @@
private import swift
private import codeql.swift.generated.GetImmediateParent
private import codeql.swift.generated.Synth
module CallableBase {
class TypeRange = @abstract_function_decl or @key_path_expr or @closure_expr;
class TypeRange = Synth::TAbstractFunctionDecl or Synth::TKeyPathExpr or Synth::TClosureExpr;
class Range extends Scope::Range, TypeRange { }
}

View File

@@ -2,10 +2,14 @@
import codeql.swift.elements.AstNode
import codeql.swift.elements.Callable
import codeql.swift.elements.Comment
import codeql.swift.elements.DbFile
import codeql.swift.elements.DbLocation
import codeql.swift.elements.Element
import codeql.swift.elements.File
import codeql.swift.elements.Locatable
import codeql.swift.elements.Location
import codeql.swift.elements.UnknownFile
import codeql.swift.elements.UnknownLocation
import codeql.swift.elements.decl.AbstractFunctionDecl
import codeql.swift.elements.decl.AbstractStorageDecl
import codeql.swift.elements.decl.AbstractTypeParamDecl

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructComment(Raw::Comment id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.DbFile
class DbFile extends DbFileBase { }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDbFile(Raw::DbFile id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.DbLocation
class DbLocation extends DbLocationBase { }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDbLocation(Raw::DbLocation id) { any() }

View File

@@ -4,9 +4,6 @@ class File extends FileBase {
/** toString */
override string toString() { result = getAbsolutePath() }
/** Gets the name of this file. */
override string getName() { files(this, result) }
/** Gets the absolute path of this file. */
string getAbsolutePath() { result = getName() }

View File

@@ -1,12 +1,13 @@
private import codeql.swift.generated.Locatable
private import codeql.swift.elements.File
private import codeql.swift.elements.UnknownLocation
class Locatable extends LocatableBase {
pragma[nomagic]
override Location getLocation() {
result = LocatableBase.super.getLocation()
override Location getImmediateLocation() {
result = LocatableBase.super.getImmediateLocation()
or
not exists(LocatableBase.super.getLocation()) and result instanceof UnknownLocation
not exists(LocatableBase.super.getImmediateLocation()) and result instanceof UnknownLocation
}
/**

View File

@@ -9,7 +9,3 @@ class Location extends LocationBase {
ec = getEndColumn()
}
}
class UnknownLocation extends Location {
UnknownLocation() { hasLocationInfo("", 0, 0, 0, 0) }
}

View File

@@ -0,0 +1,5 @@
private import codeql.swift.generated.UnknownFile
class UnknownFile extends UnknownFileBase {
override string getName() { result = "" }
}

View File

@@ -0,0 +1,15 @@
private import codeql.swift.generated.UnknownLocation
private import codeql.swift.elements.UnknownFile
private import codeql.swift.elements.File
class UnknownLocation extends UnknownLocationBase {
override File getImmediateFile() { result instanceof UnknownFile }
override int getStartLine() { result = 0 }
override int getStartColumn() { result = 0 }
override int getEndLine() { result = 0 }
override int getEndColumn() { result = 0 }
}

View File

@@ -0,0 +1,3 @@
private import codeql.swift.generated.Raw
predicate constructUnknownLocation() { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAccessorDecl(Raw::AccessorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAssociatedTypeDecl(Raw::AssociatedTypeDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructClassDecl(Raw::ClassDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConcreteFuncDecl(Raw::ConcreteFuncDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConcreteVarDecl(Raw::ConcreteVarDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConstructorDecl(Raw::ConstructorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDestructorDecl(Raw::DestructorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructEnumCaseDecl(Raw::EnumCaseDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructEnumDecl(Raw::EnumDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructEnumElementDecl(Raw::EnumElementDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructExtensionDecl(Raw::ExtensionDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructGenericTypeParamDecl(Raw::GenericTypeParamDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructIfConfigClause(Raw::IfConfigClause id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructIfConfigDecl(Raw::IfConfigDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructImportDecl(Raw::ImportDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructInfixOperatorDecl(Raw::InfixOperatorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructMissingMemberDecl(Raw::MissingMemberDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructModuleDecl(Raw::ModuleDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructOpaqueTypeDecl(Raw::OpaqueTypeDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructParamDecl(Raw::ParamDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructPatternBindingDecl(Raw::PatternBindingDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructPostfixOperatorDecl(Raw::PostfixOperatorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructPoundDiagnosticDecl(Raw::PoundDiagnosticDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructPrecedenceGroupDecl(Raw::PrecedenceGroupDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructPrefixOperatorDecl(Raw::PrefixOperatorDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructProtocolDecl(Raw::ProtocolDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructStructDecl(Raw::StructDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructSubscriptDecl(Raw::SubscriptDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructTopLevelCodeDecl(Raw::TopLevelCodeDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructTypeAliasDecl(Raw::TypeAliasDecl id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAnyHashableErasureExpr(Raw::AnyHashableErasureExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAppliedPropertyWrapperExpr(Raw::AppliedPropertyWrapperExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructArchetypeToSuperExpr(Raw::ArchetypeToSuperExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructArgument(Raw::Argument id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructArrayExpr(Raw::ArrayExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructArrayToPointerExpr(Raw::ArrayToPointerExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructArrowExpr(Raw::ArrowExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAssignExpr(Raw::AssignExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAutoClosureExpr(Raw::AutoClosureExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructAwaitExpr(Raw::AwaitExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructBinaryExpr(Raw::BinaryExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructBindOptionalExpr(Raw::BindOptionalExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructBooleanLiteralExpr(Raw::BooleanLiteralExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructBridgeFromObjCExpr(Raw::BridgeFromObjCExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructBridgeToObjCExpr(Raw::BridgeToObjCExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCallExpr(Raw::CallExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCaptureListExpr(Raw::CaptureListExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructClassMetatypeToObjectExpr(Raw::ClassMetatypeToObjectExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructClosureExpr(Raw::ClosureExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCodeCompletionExpr(Raw::CodeCompletionExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCoerceExpr(Raw::CoerceExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCollectionUpcastConversionExpr(Raw::CollectionUpcastConversionExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConditionalBridgeFromObjCExpr(Raw::ConditionalBridgeFromObjCExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConditionalCheckedCastExpr(Raw::ConditionalCheckedCastExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructConstructorRefCallExpr(Raw::ConstructorRefCallExpr id) { any() }

View File

@@ -0,0 +1,6 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCovariantFunctionConversionExpr(Raw::CovariantFunctionConversionExpr id) {
any()
}

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructCovariantReturnConversionExpr(Raw::CovariantReturnConversionExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDeclRefExpr(Raw::DeclRefExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDefaultArgumentExpr(Raw::DefaultArgumentExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDerivedToBaseExpr(Raw::DerivedToBaseExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDestructureTupleExpr(Raw::DestructureTupleExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDictionaryExpr(Raw::DictionaryExpr id) { any() }

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDifferentiableFunctionExpr(Raw::DifferentiableFunctionExpr id) { any() }

View File

@@ -0,0 +1,8 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDifferentiableFunctionExtractOriginalExpr(
Raw::DifferentiableFunctionExtractOriginalExpr id
) {
any()
}

View File

@@ -0,0 +1,4 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.Raw
predicate constructDiscardAssignmentExpr(Raw::DiscardAssignmentExpr id) { any() }

Some files were not shown because too many files have changed in this diff Show More