Swift: simplify GetImmediateParent.qll

This commit is contained in:
Paolo Tranquilli
2022-06-01 14:59:30 +02:00
parent 6b90b2b05f
commit 3414028b1b
5 changed files with 244 additions and 261 deletions

View File

@@ -119,8 +119,7 @@ def generate(opts, renderer):
all_imports = ql.ImportList(list(sorted(imports.values())))
renderer.render(all_imports, include_file)
renderer.render(ql.GetParentImplementation(classes=classes, imports=[get_import(include_file, opts.swift_dir)]),
out / 'GetImmediateParent.qll')
renderer.render(ql.GetParentImplementation(classes), out / 'GetImmediateParent.qll')
renderer.cleanup(existing)
if opts.ql_format:

View File

@@ -99,4 +99,3 @@ class GetParentImplementation:
template: ClassVar = 'ql_parent'
classes: List[Class] = field(default_factory=list)
imports: List[str] = field(default_factory=list)

View File

@@ -1,39 +1,35 @@
// generated by {{generator}}
{{#imports}}
import {{.}}
{{/imports}}
// we are defining this class mainly to leverage existing generation machinery
// when we generate getters in classes we use the db predicate with `this`. In order to reuse that we need a class here
// as well
private class ElementWithChildAccessor extends Element {
// why does this look more complicated than it should?
// * the none() simplifies generation, as we can append `or ...` without a special case for the first item
// * the `exists` and the `x` variables are there to reuse the same generation done in classes (where the variables
// are used to hide nodes via resolution)
Element getAnImmediateChild() {
none()
{{#classes}}
{{#properties}}
{{#is_child}}
or
exists({{type}} {{local_var}}{{#is_repeated}}, int index{{/is_repeated}} | {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) and result = {{local_var}})
{{/is_child}}
{{/properties}}
{{/classes}}
}
}
import codeql.swift.elements.Element
/**
* Gets any of the "immediate" children of `e`. "Immediate" means not taking into account node resolution: for example
* if the AST child is the first of a series of conversions that would normally be hidden away, this will select the
* next conversion down the hidden AST tree instead of the corresponding fully uncoverted node at the bottom.
* This predicate is mainly intended to be used to test uniqueness of parents.
* Outside this module this file is mainly intended to be used to test uniqueness of parents.
*/
cached
Element getAnImmediateChild(Element e) {
result = e.(ElementWithChildAccessor).getAnImmediateChild()
// 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}}
))
}
/**

View File

@@ -18,8 +18,8 @@ stub_path = lambda: paths.swift_dir / "ql/lib/stub/path"
ql_output_path = lambda: paths.swift_dir / "ql/lib/other/path"
import_file = lambda: stub_path().with_suffix(".qll")
children_file = lambda: ql_output_path() / "GetImmediateParent.qll"
stub_import = "stub.path"
stub_import_prefix = f"{stub_import}."
stub_import_prefix = "stub.path."
root_import = stub_import_prefix + "Element"
gen_import_prefix = "other.path."
@@ -69,7 +69,7 @@ def generate_classes(opts, renderer):
def test_empty(opts, input, renderer):
assert generate(opts, renderer) == {
import_file(): ql.ImportList(),
children_file(): ql.GetParentImplementation(imports=[stub_import]),
children_file(): ql.GetParentImplementation(),
}
@@ -127,7 +127,6 @@ def test_hierarchy_children(opts, input, renderer):
ql.Class(name="D", final=True, bases=["B", "C"],
imports=[stub_import_prefix + cls for cls in "BC"]),
],
imports=[stub_import],
)

View File

@@ -1,240 +1,230 @@
// generated by codegen/codegen.py
import codeql.swift.elements
// we are defining this class mainly to leverage existing generation machinery
// when we generate getters in classes we use the db predicate with `this`. In order to reuse that we need a class here
// as well
private class ElementWithChildAccessor extends Element {
// why does this look more complicated than it should?
// * the none() simplifies generation, as we can append `or ...` without a special case for the first item
// * the `exists` and the `x` variables are there to reuse the same generation done in classes (where the variables
// are used to hide nodes via resolution)
Element getAnImmediateChild() {
none()
or
exists(BraceStmt x | abstract_function_decl_bodies(this, x) and result = x)
or
exists(ParamDecl x, int index | abstract_function_decl_params(this, index, x) and result = x)
or
exists(AccessorDecl x, int index |
abstract_storage_decl_accessor_decls(this, index, x) and result = x
)
or
exists(Expr x | any_try_exprs(this, x) and result = x)
or
exists(Expr x | apply_exprs(this, x) and result = x)
or
exists(Argument x, int index | apply_expr_arguments(this, index, x) and result = x)
or
exists(Expr x | arguments(this, _, x) and result = x)
or
exists(Expr x, int index | array_expr_elements(this, index, x) and result = x)
or
exists(Expr x | assign_exprs(this, x, _) and result = x)
or
exists(Expr x | assign_exprs(this, _, x) and result = x)
or
exists(BraceStmt x | auto_closure_exprs(this, x) and result = x)
or
exists(Expr x | bind_optional_exprs(this, x) and result = x)
or
exists(Pattern x | binding_patterns(this, x) and result = x)
or
exists(AstNode x, int index | brace_stmt_elements(this, index, x) and result = x)
or
exists(PatternBindingDecl x, int index |
capture_list_expr_binding_decls(this, index, x) and result = x
)
or
exists(ClosureExpr x | capture_list_exprs(this, x) and result = x)
or
exists(Pattern x | case_label_items(this, x) and result = x)
or
exists(Expr x | case_label_item_guards(this, x) and result = x)
or
exists(Stmt x | case_stmts(this, x) and result = x)
or
exists(CaseLabelItem x, int index | case_stmt_labels(this, index, x) and result = x)
or
exists(BraceStmt x | closure_exprs(this, x) and result = x)
or
exists(Expr x | condition_element_booleans(this, x) and result = x)
or
exists(Pattern x | condition_element_patterns(this, x) and result = x)
or
exists(Expr x | condition_element_initializers(this, x) and result = x)
or
exists(BraceStmt x | defer_stmts(this, x) and result = x)
or
exists(Expr x, int index | dictionary_expr_elements(this, index, x) and result = x)
or
exists(Stmt x | do_catch_stmts(this, x) and result = x)
or
exists(CaseStmt x, int index | do_catch_stmt_catches(this, index, x) and result = x)
or
exists(BraceStmt x | do_stmts(this, x) and result = x)
or
exists(Expr x | dot_syntax_base_ignored_exprs(this, x, _) and result = x)
or
exists(Expr x | dot_syntax_base_ignored_exprs(this, _, x) and result = x)
or
exists(Expr x | dynamic_type_exprs(this, x) and result = x)
or
exists(EnumElementDecl x, int index | enum_case_decl_elements(this, index, x) and result = x)
or
exists(ParamDecl x, int index | enum_element_decl_params(this, index, x) and result = x)
or
exists(Pattern x | enum_element_pattern_sub_patterns(this, x) and result = x)
or
exists(Expr x | enum_is_case_exprs(this, x, _, _) and result = x)
or
exists(TypeRepr x | enum_is_case_exprs(this, _, x, _) and result = x)
or
exists(EnumElementDecl x | enum_is_case_exprs(this, _, _, x) and result = x)
or
exists(Expr x | explicit_cast_exprs(this, x) and result = x)
or
exists(Expr x | expr_patterns(this, x) and result = x)
or
exists(Pattern x | for_each_stmts(this, x, _, _) and result = x)
or
exists(Expr x | for_each_stmts(this, _, x, _) and result = x)
or
exists(Expr x | for_each_stmt_wheres(this, x) and result = x)
or
exists(BraceStmt x | for_each_stmts(this, _, _, x) and result = x)
or
exists(Expr x | force_value_exprs(this, x) and result = x)
or
exists(BraceStmt x | guard_stmts(this, x) and result = x)
or
exists(Expr x | identity_exprs(this, x) and result = x)
or
exists(Expr x | if_exprs(this, x, _, _) and result = x)
or
exists(Expr x | if_exprs(this, _, x, _) and result = x)
or
exists(Expr x | if_exprs(this, _, _, x) and result = x)
or
exists(Stmt x | if_stmts(this, x) and result = x)
or
exists(Stmt x | if_stmt_elses(this, x) and result = x)
or
exists(Expr x | implicit_conversion_exprs(this, x) and result = x)
or
exists(Expr x | in_out_exprs(this, x) and result = x)
or
exists(Expr x |
interpolated_string_literal_expr_interpolation_count_exprs(this, x) and result = x
)
or
exists(Expr x | interpolated_string_literal_expr_literal_capacity_exprs(this, x) and result = x)
or
exists(TapExpr x | interpolated_string_literal_expr_appending_exprs(this, x) and result = x)
or
exists(TypeRepr x | is_pattern_cast_type_reprs(this, x) and result = x)
or
exists(Pattern x | is_pattern_sub_patterns(this, x) and result = x)
or
exists(Expr x | key_path_application_exprs(this, x, _) and result = x)
or
exists(Expr x | key_path_application_exprs(this, _, x) and result = x)
or
exists(Expr x | key_path_expr_parsed_roots(this, x) and result = x)
or
exists(Expr x | key_path_expr_parsed_paths(this, x) and result = x)
or
exists(StmtCondition x | labeled_conditional_stmts(this, x) and result = x)
or
exists(Expr x | lazy_initializer_exprs(this, x) and result = x)
or
exists(Expr x | lookup_exprs(this, x, _) and result = x)
or
exists(OpaqueValueExpr x | make_temporarily_escapable_exprs(this, x, _, _) and result = x)
or
exists(Expr x | make_temporarily_escapable_exprs(this, _, x, _) and result = x)
or
exists(Expr x | make_temporarily_escapable_exprs(this, _, _, x) and result = x)
or
exists(Expr x | obj_c_selector_exprs(this, x, _) and result = x)
or
exists(Expr x | one_way_exprs(this, x) and result = x)
or
exists(Expr x | open_existential_exprs(this, x, _, _) and result = x)
or
exists(Expr x | open_existential_exprs(this, _, x, _) and result = x)
or
exists(OpaqueValueExpr x | open_existential_exprs(this, _, _, x) and result = x)
or
exists(Expr x | optional_evaluation_exprs(this, x) and result = x)
or
exists(Pattern x | optional_some_patterns(this, x) and result = x)
or
exists(Pattern x | paren_patterns(this, x) and result = x)
or
exists(Expr x, int index | pattern_binding_decl_inits(this, index, x) and result = x)
or
exists(Pattern x, int index | pattern_binding_decl_patterns(this, index, x) and result = x)
or
exists(Expr x | rebind_self_in_constructor_exprs(this, x, _) and result = x)
or
exists(VarDecl x | rebind_self_in_constructor_exprs(this, _, x) and result = x)
or
exists(Expr x | repeat_while_stmts(this, x, _) and result = x)
or
exists(Stmt x | repeat_while_stmts(this, _, x) and result = x)
or
exists(Expr x | return_stmt_results(this, x) and result = x)
or
exists(Expr x | self_apply_exprs(this, x) and result = x)
or
exists(ConditionElement x, int index | stmt_condition_elements(this, index, x) and result = x)
or
exists(ParamDecl x, int index | subscript_decl_params(this, index, x) and result = x)
or
exists(Argument x, int index | subscript_expr_arguments(this, index, x) and result = x)
or
exists(Expr x | switch_stmts(this, x) and result = x)
or
exists(CaseStmt x, int index | switch_stmt_cases(this, index, x) and result = x)
or
exists(Expr x | tap_expr_sub_exprs(this, x) and result = x)
or
exists(BraceStmt x | tap_exprs(this, x, _) and result = x)
or
exists(Expr x | throw_stmts(this, x) and result = x)
or
exists(BraceStmt x | top_level_code_decls(this, x) and result = x)
or
exists(Expr x | tuple_element_exprs(this, x, _) and result = x)
or
exists(Expr x, int index | tuple_expr_elements(this, index, x) and result = x)
or
exists(Pattern x, int index | tuple_pattern_elements(this, index, x) and result = x)
or
exists(TypeRepr x | type_expr_type_reprs(this, x) and result = x)
or
exists(Pattern x | typed_patterns(this, x) and result = x)
or
exists(TypeRepr x | typed_pattern_type_reprs(this, x) and result = x)
or
exists(Expr x | vararg_expansion_exprs(this, x) and result = x)
or
exists(Stmt x | while_stmts(this, x) and result = x)
or
exists(Expr x, int index | yield_stmt_results(this, index, x) and result = x)
}
}
import codeql.swift.elements.Element
/**
* Gets any of the "immediate" children of `e`. "Immediate" means not taking into account node resolution: for example
* if the AST child is the first of a series of conversions that would normally be hidden away, this will select the
* next conversion down the hidden AST tree instead of the corresponding fully uncoverted node at the bottom.
* This predicate is mainly intended to be used to test uniqueness of parents.
* Outside this module this file is mainly intended to be used to test uniqueness of parents.
*/
cached
Element getAnImmediateChild(Element e) {
result = e.(ElementWithChildAccessor).getAnImmediateChild()
// 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()
or
abstract_function_decl_bodies(e, x)
or
abstract_function_decl_params(e, _, x)
or
abstract_storage_decl_accessor_decls(e, _, x)
or
any_try_exprs(e, x)
or
apply_exprs(e, x)
or
apply_expr_arguments(e, _, x)
or
arguments(e, _, x)
or
array_expr_elements(e, _, x)
or
assign_exprs(e, x, _)
or
assign_exprs(e, _, x)
or
auto_closure_exprs(e, x)
or
bind_optional_exprs(e, x)
or
binding_patterns(e, x)
or
brace_stmt_elements(e, _, x)
or
capture_list_expr_binding_decls(e, _, x)
or
capture_list_exprs(e, x)
or
case_label_items(e, x)
or
case_label_item_guards(e, x)
or
case_stmts(e, x)
or
case_stmt_labels(e, _, x)
or
closure_exprs(e, x)
or
condition_element_booleans(e, x)
or
condition_element_patterns(e, x)
or
condition_element_initializers(e, x)
or
defer_stmts(e, x)
or
dictionary_expr_elements(e, _, x)
or
do_catch_stmts(e, x)
or
do_catch_stmt_catches(e, _, x)
or
do_stmts(e, x)
or
dot_syntax_base_ignored_exprs(e, x, _)
or
dot_syntax_base_ignored_exprs(e, _, x)
or
dynamic_type_exprs(e, x)
or
enum_case_decl_elements(e, _, x)
or
enum_element_decl_params(e, _, x)
or
enum_element_pattern_sub_patterns(e, x)
or
enum_is_case_exprs(e, x, _, _)
or
enum_is_case_exprs(e, _, x, _)
or
enum_is_case_exprs(e, _, _, x)
or
explicit_cast_exprs(e, x)
or
expr_patterns(e, x)
or
for_each_stmts(e, x, _, _)
or
for_each_stmts(e, _, x, _)
or
for_each_stmt_wheres(e, x)
or
for_each_stmts(e, _, _, x)
or
force_value_exprs(e, x)
or
guard_stmts(e, x)
or
identity_exprs(e, x)
or
if_exprs(e, x, _, _)
or
if_exprs(e, _, x, _)
or
if_exprs(e, _, _, x)
or
if_stmts(e, x)
or
if_stmt_elses(e, x)
or
implicit_conversion_exprs(e, x)
or
in_out_exprs(e, x)
or
interpolated_string_literal_expr_interpolation_count_exprs(e, x)
or
interpolated_string_literal_expr_literal_capacity_exprs(e, x)
or
interpolated_string_literal_expr_appending_exprs(e, x)
or
is_pattern_cast_type_reprs(e, x)
or
is_pattern_sub_patterns(e, x)
or
key_path_application_exprs(e, x, _)
or
key_path_application_exprs(e, _, x)
or
key_path_expr_parsed_roots(e, x)
or
key_path_expr_parsed_paths(e, x)
or
labeled_conditional_stmts(e, x)
or
lazy_initializer_exprs(e, x)
or
lookup_exprs(e, x, _)
or
make_temporarily_escapable_exprs(e, x, _, _)
or
make_temporarily_escapable_exprs(e, _, x, _)
or
make_temporarily_escapable_exprs(e, _, _, x)
or
obj_c_selector_exprs(e, x, _)
or
one_way_exprs(e, x)
or
open_existential_exprs(e, x, _, _)
or
open_existential_exprs(e, _, x, _)
or
open_existential_exprs(e, _, _, x)
or
optional_evaluation_exprs(e, x)
or
optional_some_patterns(e, x)
or
paren_patterns(e, x)
or
pattern_binding_decl_inits(e, _, x)
or
pattern_binding_decl_patterns(e, _, x)
or
rebind_self_in_constructor_exprs(e, x, _)
or
rebind_self_in_constructor_exprs(e, _, x)
or
repeat_while_stmts(e, x, _)
or
repeat_while_stmts(e, _, x)
or
return_stmt_results(e, x)
or
self_apply_exprs(e, x)
or
stmt_condition_elements(e, _, x)
or
subscript_decl_params(e, _, x)
or
subscript_expr_arguments(e, _, x)
or
switch_stmts(e, x)
or
switch_stmt_cases(e, _, x)
or
tap_expr_sub_exprs(e, x)
or
tap_exprs(e, x, _)
or
throw_stmts(e, x)
or
top_level_code_decls(e, x)
or
tuple_element_exprs(e, x, _)
or
tuple_expr_elements(e, _, x)
or
tuple_pattern_elements(e, _, x)
or
type_expr_type_reprs(e, x)
or
typed_patterns(e, x)
or
typed_pattern_type_reprs(e, x)
or
vararg_expansion_exprs(e, x)
or
while_stmts(e, x)
or
yield_stmt_results(e, _, x)
)
)
}
/**