Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions unified/extractor/ast_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ supertypes:
- name_pattern
- tuple_pattern
- constructor_pattern
- or_pattern
- ignore_pattern
- expr_equality_pattern
- bulk_importing_pattern
Expand Down Expand Up @@ -359,12 +360,12 @@ named:
case*: switch_case

# A single `case ...:` (or `default:`) entry in a switch.
# An entry with multiple `case p1, p2:` patterns has multiple `pattern`s.
# A `default:` entry has no patterns.
# An entry with multiple `case p1, p2:` patterns uses an `or_pattern`.
# A `default:` entry has no pattern.
# An optional `guard` corresponds to a `where`-clause on the case.
switch_case:
modifier*: modifier
pattern*: pattern
pattern?: pattern
guard?: expr
body: block

Expand Down Expand Up @@ -421,6 +422,11 @@ named:
constructor: expr_or_type
element*: pattern_element

# A disjunction pattern that matches if any of its sub-patterns match.
or_pattern:
modifier*: modifier
pattern*: pattern

# A pattern with an optional associated name.
pattern_element:
modifier*: modifier
Expand Down
21 changes: 15 additions & 6 deletions unified/extractor/src/languages/swift/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,25 +652,34 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
=>
(switch_expr value: {val} case: {..cases})
),
// Switch entry with patterns and body
// Switch entry with multiple patterns and body
rule!(
(switch_entry pattern: (switch_pattern pattern: @pats)* statement: _* @body)
(switch_entry
pattern: (switch_pattern pattern: @first)
pattern: (switch_pattern pattern: @rest)+
statement: _* @body)
=>
(switch_case pattern: {..pats} body: (block stmt: {..body}))
(switch_case pattern: (or_pattern pattern: {first} pattern: {..rest}) body: (block stmt: {..body}))
),
// Switch entry with exactly one pattern and body
rule!(
(switch_entry pattern: (switch_pattern pattern: @pat) statement: _* @body)
=>
(switch_case pattern: {pat} body: (block stmt: {..body}))
),
// Switch entry: default case (no patterns)
rule!(
(switch_entry default: (default_keyword) statement: _* @body)
=>
(switch_case body: (block stmt: {..body}))
),
// if case let x = expr — the pattern is taken as-is (no Optional wrapping)
// if case PATTERN = expr — preserve the pattern directly (no Optional wrapping)
rule!(
(if_let_binding "case" (value_binding_pattern) bound_identifier: @name _ @val)
(if_let_binding "case" pattern: @pat value: @val)
=>
(pattern_guard_expr
value: {val}
pattern: (name_pattern identifier: (identifier #{name})))
pattern: {pat})
),
rule!(
(if_let_binding
Expand Down
87 changes: 83 additions & 4 deletions unified/extractor/tests/corpus/swift/control-flow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -573,10 +573,12 @@ top_level
name_expr
identifier: identifier "print"
pattern:
expr_equality_pattern
expr: int_literal "2"
expr_equality_pattern
expr: int_literal "3"
or_pattern
pattern:
expr_equality_pattern
expr: int_literal "2"
expr_equality_pattern
expr: int_literal "3"
switch_case
body:
block
Expand All @@ -592,6 +594,83 @@ top_level
name_expr
identifier: identifier "x"

===
If-case-let with shadowing in condition value
===

if case let x = x + 10 {
print(x)
}

---

source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
condition:
if_condition
kind:
if_let_binding
pattern:
pattern
kind:
binding_pattern
binding:
value_binding_pattern
mutability: let
pattern:
pattern
bound_identifier: simple_identifier "x"
value:
additive_expression
lhs: simple_identifier "x"
op: +
rhs: integer_literal "10"

---

top_level
body:
block
stmt:
if_expr
condition:
pattern_guard_expr
pattern:
name_pattern
identifier: identifier "x"
value:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "x"
right: int_literal "10"
then:
block
stmt:
call_expr
argument:
argument
value:
name_expr
identifier: identifier "x"
callee:
name_expr
identifier: identifier "print"

===
Switch with binding pattern
===
Expand Down
27 changes: 24 additions & 3 deletions unified/ql/lib/codeql/unified/Ast.qll
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,23 @@
}
}

/** A class representing `or_pattern` nodes. */
class OrPattern extends @unified_or_pattern, AstNode {
/** Gets the name of the primary QL class for this element. */
final override string getAPrimaryQlClass() { result = "OrPattern" }

/** Gets the node corresponding to the field `modifier`. */
final Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) }

Check warning

Code scanning / CodeQL

Missing QLDoc for parameter Warning

The QLDoc has no documentation for i, but the QLDoc mentions modifier

/** Gets the node corresponding to the field `pattern`. */
final Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) }

/** Gets a field or child node of this node. */
final override AstNode getAFieldOrChild() {
unified_or_pattern_modifier(this, _, result) or unified_or_pattern_pattern(this, _, result)
}
}

/** A class representing `parameter` nodes. */
class Parameter extends @unified_parameter, AstNode {
/** Gets the name of the primary QL class for this element. */
Expand Down Expand Up @@ -1109,14 +1126,14 @@
final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) }

/** Gets the node corresponding to the field `pattern`. */
final Pattern getPattern(int i) { unified_switch_case_pattern(this, i, result) }
final Pattern getPattern() { unified_switch_case_pattern(this, result) }

/** Gets a field or child node of this node. */
final override AstNode getAFieldOrChild() {
unified_switch_case_def(this, result) or
unified_switch_case_guard(this, result) or
unified_switch_case_modifier(this, _, result) or
unified_switch_case_pattern(this, _, result)
unified_switch_case_pattern(this, result)
}
}

Expand Down Expand Up @@ -1654,6 +1671,10 @@
i = -1 and
name = "getPrecedence"
or
result = node.(OrPattern).getModifier(i) and name = "getModifier"
or
result = node.(OrPattern).getPattern(i) and name = "getPattern"
or
result = node.(Parameter).getDefault() and i = -1 and name = "getDefault"
or
result = node.(Parameter).getExternalName() and i = -1 and name = "getExternalName"
Expand Down Expand Up @@ -1682,7 +1703,7 @@
or
result = node.(SwitchCase).getModifier(i) and name = "getModifier"
or
result = node.(SwitchCase).getPattern(i) and name = "getPattern"
result = node.(SwitchCase).getPattern() and i = -1 and name = "getPattern"
or
result = node.(SwitchExpr).getCase(i) and name = "getCase"
or
Expand Down
26 changes: 21 additions & 5 deletions unified/ql/lib/unified.dbscheme
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,24 @@ unified_operator_syntax_declaration_def(
int name: @unified_token_identifier ref
);

#keyset[unified_or_pattern, index]
unified_or_pattern_modifier(
int unified_or_pattern: @unified_or_pattern ref,
int index: int ref,
unique int modifier: @unified_token_modifier ref
);

#keyset[unified_or_pattern, index]
unified_or_pattern_pattern(
int unified_or_pattern: @unified_or_pattern ref,
int index: int ref,
unique int pattern: @unified_pattern ref
);

unified_or_pattern_def(
unique int id: @unified_or_pattern
);

unified_parameter_default(
unique int unified_parameter: @unified_parameter ref,
unique int default: @unified_expr ref
Expand Down Expand Up @@ -747,7 +765,7 @@ unified_parameter_def(
unique int id: @unified_parameter
);

@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern
@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern

unified_pattern_element_key(
unique int unified_pattern_element: @unified_pattern_element ref,
Expand Down Expand Up @@ -795,10 +813,8 @@ unified_switch_case_modifier(
unique int modifier: @unified_token_modifier ref
);

#keyset[unified_switch_case, index]
unified_switch_case_pattern(
int unified_switch_case: @unified_switch_case ref,
int index: int ref,
unique int unified_switch_case: @unified_switch_case ref,
unique int pattern: @unified_pattern ref
);

Expand Down Expand Up @@ -1056,7 +1072,7 @@ unified_trivia_tokeninfo(
string value: string ref
);

@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @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_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_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_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_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_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_variable_declaration | @unified_while_stmt
@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @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_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_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_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_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_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_variable_declaration | @unified_while_stmt

unified_ast_node_location(
unique int node: @unified_ast_node ref,
Expand Down
Loading