Skip to content
Draft
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
25 changes: 20 additions & 5 deletions unified/extractor/src/languages/swift/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,21 +735,36 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
(switch_entry
pattern: (switch_pattern pattern: @first)
pattern: (switch_pattern pattern: @rest)+
where: (where_clause expr: @guard)?
statement: _* @body)
=>
(switch_case pattern: (or_pattern pattern: {first} pattern: {rest}) body: (block stmt: {body}))
(switch_case
pattern: (or_pattern pattern: {first} pattern: {rest})
guard: {guard}
body: (block stmt: {body}))
),
// Switch entry with exactly one pattern and body
rule!(
(switch_entry pattern: (switch_pattern pattern: @pat) statement: _* @body)
(switch_entry
pattern: (switch_pattern pattern: @pat)
where: (where_clause expr: @guard)?
statement: _* @body)
=>
(switch_case pattern: {pat} body: (block stmt: {body}))
(switch_case
pattern: {pat}
guard: {guard}
body: (block stmt: {body}))
),
// Switch entry: default case (no patterns)
rule!(
(switch_entry default: (default_keyword) statement: _* @body)
(switch_entry
default: (default_keyword)
where: (where_clause expr: @guard)?
statement: _* @body)
=>
(switch_case body: (block stmt: {body}))
(switch_case
guard: {guard}
body: (block stmt: {body}))
),
// if case PATTERN = expr — preserve the pattern directly (no Optional wrapping)
rule!(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
switch x {
case 1 where x > 0:
print("positive one")
case 2, 3:
print("small two or three")
default:
print("other")
}

---

source_file
statement:
switch_statement
entry:
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind: integer_literal "1"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "positive one"
where:
where_clause
expr:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
keyword: where_keyword "where"
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind: integer_literal "2"
switch_pattern
pattern:
pattern
kind: integer_literal "3"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "small two or three"
switch_entry
default: default_keyword "default"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "other"
expr: simple_identifier "x"

---

top_level
body:
block
stmt:
switch_expr
case:
switch_case
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"positive one\""
callee:
name_expr
identifier: identifier "print"
pattern:
expr_equality_pattern
expr: int_literal "1"
guard:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
right: int_literal "0"
switch_case
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"small two or three\""
callee:
name_expr
identifier: identifier "print"
pattern:
or_pattern
pattern:
expr_equality_pattern
expr: int_literal "2"
expr_equality_pattern
expr: int_literal "3"
switch_case
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"other\""
callee:
name_expr
identifier: identifier "print"
value:
name_expr
identifier: identifier "x"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
switch x {
case 1 where x > 0:
print("positive one")
case 2, 3:
print("small two or three")
default:
print("other")
}
2 changes: 0 additions & 2 deletions unified/ql/lib/codeql/unified/internal/Variables.qll
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,6 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig<Locatio
n = any(LocalFunctionDeclaration f).getName() and
n.(Identifier).getValue() = name
}

predicate lookupStartsAt(AstNode n, AstNode scope) { none() }
}

module LocalNameBindingOutput = LocalNameBinding<Location, LocalNameBindingInput>;
Expand Down
6 changes: 4 additions & 2 deletions unified/ql/test/library-tests/variables/test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func t10(value: Int) { // name=value1
// Switch with multiple cases
func t11(value: Int) { // name=value1
switch value { // $ access=value1
case let x where x > 0: // name=x1
case let x where x > 0: // $ access=x1 // name=x1
print(x) // $ access=x1
case let x: // name=x2
print(x) // $ access=x2
Expand Down Expand Up @@ -187,6 +187,8 @@ func t22() {
}
inner() // $ access=inner1
print(x) // $ access=x1
let inner = 2 // name=inner2
print(inner) // $ access=inner2
}

// Three levels of shadowing
Expand Down Expand Up @@ -214,7 +216,7 @@ func t24(optional: Int?) { // name=optional1
}
}

// Switch with same variable name in different cases
// Switch with variable shadowed within body of case
func t25(value: Int) { // name=value1
switch value { // $ access=value1
case let x: // name=x1
Expand Down
Loading