diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 47e1ebc7a8ec..0eaf1e8f02f1 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -41,6 +41,7 @@ supertypes: - bulk_importing_pattern - ignore_pattern - generic_type_expr + - modified_type_expr - inferred_type_expr # An element of an `unresolved_operator_sequence`: either an operand (`expr`) # or one of the infix operators separating the operands. @@ -553,5 +554,11 @@ named: base: expr type_argument*: expr + # A type with a modifier. In Swift this can be specifiers or attributes, such + # as `inout T`, `sending T` or `@escaping () -> Void`. + modified_type_expr: + modifier*: modifier + type: expr + # A modifier such as 'static', 'public', or 'async'. For now this is just a leaf node with a string value. modifier: diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 63da3f1f0acf..cbf80fb0da9b 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1168,6 +1168,24 @@ fn translation_rules() -> Vec> { // becomes a `modifier`; its source text is the modifier spelling. rule!((attribute) @m => (modifier #{m})), rule!((declModifier) @m => (modifier #{m})), + // Type specifiers (`inout`, `sending`, ...) are mapped to modifiers. + rule!((simpleTypeSpecifier) @m => (modifier #{m})), + rule!((lifetimeTypeSpecifier) @m => (modifier #{m})), + rule!((nonisolatedTypeSpecifier) @m => (modifier #{m})), + // An attributed type is mapped to a modified type of its base type. + rule!( + (attributedType + specifiers: _* @specs + attributes: _* @attrs + lateSpecifiers: _* @late + baseType: @base) + => + (modified_type_expr + modifier: {specs} + modifier: {attrs} + modifier: {late} + type: {base}) + ), // Preserve the `super` keyword as a dedicated expression, normally used // as the base of a member access (`super.foo`). rule!((superExpr superKeyword: @@keyword) => (super_expr #{keyword})), @@ -1475,7 +1493,6 @@ fn translation_rules() -> Vec> { // currently map them to the unified AST. Syntax nested inside one of // these roots is discarded with its parent and needs no separate rule. rule!((actorDecl) => (unsupported_node)), - rule!((attributedType) => (unsupported_node)), rule!((borrowExpr) => (unsupported_node)), rule!((classRestrictionType) => (unsupported_node)), rule!((compositionType) => (unsupported_node)), diff --git a/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.output b/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.output new file mode 100644 index 000000000000..b1e859cfd98c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.output @@ -0,0 +1,238 @@ +func f( + a: inout D, + b: sending T, + c: borrowing T, + d: consuming T, + e: @escaping (T) -> Void, + g: @Sendable @escaping () -> D +) {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + name: identifier "f" + genericParameterClause: + genericParameterClause + parameters: + genericParameter + attributes: + name: identifier "D" + trailingComma: , + genericParameter + attributes: + name: identifier "T" + leftAngle: < + rightAngle: > + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "D" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: inout + firstName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "T" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: sending + firstName: identifier "b" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "T" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: borrowing + firstName: identifier "c" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "T" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: consuming + firstName: identifier "d" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + attributedType + attributes: + attribute + atSign: @ + attributeName: + identifierType + name: identifier "escaping" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + identifierType + name: identifier "T" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + lateSpecifiers: + specifiers: + firstName: identifier "e" + functionParameter + colon: : + attributes: + modifiers: + type: + attributedType + attributes: + attribute + atSign: @ + attributeName: + identifierType + name: identifier "Sendable" + attribute + atSign: @ + attributeName: + identifierType + name: identifier "escaping" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "D" + lateSpecifiers: + specifiers: + firstName: identifier "g" + funcKeyword: func + +--- + +top_level source="⟨body⟩" + body: + block source="⟨stmt⟩" + stmt: + function_declaration source="func ⟨name_node⟩<⟨type_parameter⟩, ⟨type_parameter⟩>(\n ⟨parameter⟩,\n ⟨parameter⟩,\n ⟨parameter⟩,\n ⟨parameter⟩,\n ⟨parameter⟩,\n ⟨parameter⟩\n) ⟨body⟩" + name_node: identifier "f" source="f" + type_parameter: + type_parameter source="⟨name_node⟩" + name_node: identifier "D" source="D" + type_parameter source="⟨name_node⟩" + name_node: identifier "T" source="T" + parameter: + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "a" source="a" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "inout" source="inout" + type: identifier "D" source="D" + pattern: identifier "a" source="a" + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "b" source="b" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "sending" source="sending" + type: identifier "T" source="T" + pattern: identifier "b" source="b" + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "c" source="c" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "borrowing" source="borrowing" + type: identifier "T" source="T" + pattern: identifier "c" source="c" + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "d" source="d" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "consuming" source="consuming" + type: identifier "T" source="T" + pattern: identifier "d" source="d" + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "e" source="e" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "@escaping" source="@escaping" + type: + function_expr source="(⟨parameter⟩) -> ⟨return_type⟩" + parameter: + parameter source="⟨type⟩" + type: identifier "T" source="T" + return_type: identifier "Void" source="Void" + pattern: identifier "e" source="e" + parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" + external_name_node: identifier "g" source="g" + type: + modified_type_expr source="⟨modifier⟩ ⟨modifier⟩ ⟨type⟩" + modifier: + modifier "@Sendable" source="@Sendable" + modifier "@escaping" source="@escaping" + type: + function_expr source="() -> ⟨return_type⟩" + return_type: identifier "D" source="D" + pattern: identifier "g" source="g" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.swift b/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.swift new file mode 100644 index 000000000000..7cb9dde87401 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/attributed-parameter-types.swift @@ -0,0 +1,8 @@ +func f( + a: inout D, + b: sending T, + c: borrowing T, + d: consuming T, + e: @escaping (T) -> Void, + g: @Sendable @escaping () -> D +) {} diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output index 2cb14ccacbb2..1f39706707e1 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -66,7 +66,10 @@ top_level source="⟨body⟩" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" - type: unsupported_node "inout Int" source="inout Int" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "inout" source="inout" + type: identifier "Int" source="Int" pattern: identifier "x" source="x" body: block source="{\n ⟨stmt⟩\n}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output index 39273b1056d0..4943a564e3a9 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -65,7 +65,12 @@ top_level source="⟨body⟩" variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "callback" source="callback" - type: unsupported_node "@convention(c) () -> Void" source="@convention(c) () -> Void" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "@convention(c)" source="@convention(c)" + type: + function_expr source="() -> ⟨return_type⟩" + return_type: identifier "Void" source="Void" value: function_expr source="{}" body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.output new file mode 100644 index 000000000000..2f9b3823f7e8 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.output @@ -0,0 +1,83 @@ +let f: (inout Int) -> Void = { _ in } + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + inKeyword: in + parameterClause: + closureShorthandParameter + name: _ + statements: + pattern: + identifierPattern + identifier: identifier "f" + typeAnnotation: + typeAnnotation + colon: : + type: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "Int" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: inout + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + +--- + +top_level source="⟨body⟩" + body: + block source="⟨stmt⟩" + stmt: + variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩ = ⟨value⟩" + modifier: modifier "let" source="let" + pattern: identifier "f" source="f" + type: + function_expr source="(⟨parameter⟩) -> ⟨return_type⟩" + parameter: + parameter source="⟨type⟩" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "inout" source="inout" + type: identifier "Int" source="Int" + return_type: identifier "Void" source="Void" + value: + function_expr source="{ ⟨parameter⟩ in }" + parameter: + parameter source="⟨pattern⟩" + pattern: identifier "_" source="_" + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.swift new file mode 100644 index 000000000000..5f421dcb3106 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-inout-parameter.swift @@ -0,0 +1 @@ +let f: (inout Int) -> Void = { _ in } diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output index 9fbaf4167fd3..931aee0e53d7 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -58,7 +58,12 @@ top_level source="⟨body⟩" variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "handler" source="handler" - type: unsupported_node "@Sendable () -> Void" source="@Sendable () -> Void" + type: + modified_type_expr source="⟨modifier⟩ ⟨type⟩" + modifier: modifier "@Sendable" source="@Sendable" + type: + function_expr source="() -> ⟨return_type⟩" + return_type: identifier "Void" source="Void" value: function_expr source="{}" body: block source="" diff --git a/unified/ql/lib/codeql/unified/internal/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll index 9e8fb237ed2c..17c06cf1fd66 100644 --- a/unified/ql/lib/codeql/unified/internal/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -1041,6 +1041,27 @@ module Unified { } } + /** A class representing `modified_type_expr` nodes. */ + class ModifiedTypeExpr extends @unified_modified_type_expr, F::Expr { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ModifiedTypeExpr" } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_modified_type_expr_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + + /** Gets the node corresponding to the field `type`. */ + final F::Expr getType() { unified_modified_type_expr_def(this, result) } + + /** Gets a field or child node of this node. */ + final override F::AstNode getAFieldOrChild() { + unified_modified_type_expr_modifier(this, _, result) or + unified_modified_type_expr_def(this, result) + } + } + /** A class representing `modifier` tokens. */ class Modifier extends @unified_token_modifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ @@ -1781,6 +1802,10 @@ module Unified { or result = node.(MemberAccessExpr).getMemberNameNode() and i = -1 and name = "getMemberNameNode" or + result = node.(ModifiedTypeExpr).getModifier(i) and name = "getModifier" + or + result = node.(ModifiedTypeExpr).getType() and i = -1 and name = "getType" + or result = node.(NamedPattern).getModifier(i) and name = "getModifier" or result = node.(NamedPattern).getNameNode() and i = -1 and name = "getNameNode" @@ -2004,6 +2029,8 @@ module UnifiedFinal { final class MemberAccessExpr = F::MemberAccessExpr; + final class ModifiedTypeExpr = F::ModifiedTypeExpr; + final class Modifier = F::Modifier; final class NamedPattern = F::NamedPattern; diff --git a/unified/ql/lib/codeql/unified/internal/ExprPositions.qll b/unified/ql/lib/codeql/unified/internal/ExprPositions.qll index ed311bca83c8..2b40902f5c78 100644 --- a/unified/ql/lib/codeql/unified/internal/ExprPositions.qll +++ b/unified/ql/lib/codeql/unified/internal/ExprPositions.qll @@ -32,6 +32,8 @@ predicate isInTypeContext(Expr expr) { or expr = any(GenericTypeExpr gte).getATypeArgument() or + expr = any(ModifiedTypeExpr m).getType() + or expr.getParent() instanceof TypeConstraint or exists(Identifier id | id = NameBinding::getStaticBindingTargetFromRef(expr) | diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index 165eaffd4c3d..5c93d547be59 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -440,7 +440,7 @@ unified_equality_type_constraint_def( int right: @unified_expr ref ); -@unified_expr = @unified_array_literal | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_ignore_pattern | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unhandled_node | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence +@unified_expr = @unified_array_literal | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_modified_type_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_ignore_pattern | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unhandled_node | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence @unified_expr_or_operator = @unified_expr | @unified_token_infix_operator @@ -669,6 +669,18 @@ unified_member_access_expr_def( int member_name_node: @unified_token_identifier ref ); +#keyset[unified_modified_type_expr, index] +unified_modified_type_expr_modifier( + int unified_modified_type_expr: @unified_modified_type_expr ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_modified_type_expr_def( + unique int id: @unified_modified_type_expr, + int type__: @unified_expr ref +); + #keyset[unified_named_pattern, index] unified_named_pattern_modifier( int unified_named_pattern: @unified_named_pattern ref, @@ -1025,7 +1037,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_defer_stmt | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_defer_stmt | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_modified_type_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, diff --git a/unified/ql/test/library-tests/controlflow/cfg.expected b/unified/ql/test/library-tests/controlflow/cfg.expected index 8d4900d5fdbc..a2f876ffabff 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.expected +++ b/unified/ql/test/library-tests/controlflow/cfg.expected @@ -168,6 +168,7 @@ noCfg | cfg.swift:433:5:433:8 | init | | cfg.swift:440:5:440:8 | init | | cfg.swift:506:25:506:27 | Int | +| cfg.swift:564:49:564:51 | Int | nonSimple | cfg.swift:12:17:12:25 | withParam | 'withParam -? Block' | | cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ ... .error1 -> isZero -> Argument -V x -^ isZero(...) -? MyError -^ ... .error2 -^ ConditionalPattern -^ OrPattern' | diff --git a/unified/ql/test/library-tests/controlflow/cfg.swift b/unified/ql/test/library-tests/controlflow/cfg.swift index e6d9582efea3..cbd54f5bdc4f 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.swift +++ b/unified/ql/test/library-tests/controlflow/cfg.swift @@ -561,7 +561,7 @@ func testNilCoalescing2(x: Bool?) -> Int { } } -func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int { +func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int { // $ noCfg return expr() }