Skip to content
Open
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
16 changes: 12 additions & 4 deletions unified/extractor/src/languages/swift/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,18 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!((awaitExpr awaitKeyword: @@keyword expression: @val) => (unary_expr
operator: (prefix_operator "await" location: {keyword})
operand: {val})),
rule!((borrowExpr borrowKeyword: @@keyword expression: @val) => (unary_expr
Comment thread
Copilot marked this conversation as resolved.
Resolved
operator: (prefix_operator #{keyword})
operand: {val})),
rule!((consumeExpr consumeKeyword: @@keyword expression: @val) => (unary_expr
operator: (prefix_operator #{keyword})
operand: {val})),
rule!((copyExpr copyKeyword: @@keyword expression: @val) => (unary_expr
operator: (prefix_operator #{keyword})
operand: {val})),
rule!((unsafeExpr unsafeKeyword: @@keyword expression: @val) => (unary_expr
operator: (prefix_operator #{keyword})
operand: {val})),
// Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
// `forceUnwrapExpr` node.
rule!((forceUnwrapExpr expression: @e exclamationMark: @@mark) => (unary_expr
Expand Down Expand Up @@ -1553,11 +1565,8 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// these roots is discarded with its parent and needs no separate rule.
// Explicit empty content preserves their existing representation
// instead of inheriting the matched source text.
rule!((borrowExpr) => (unsupported_node "")),
rule!((classRestrictionType) => (unsupported_node "")),
rule!((compositionType) => (unsupported_node "")),
rule!((consumeExpr) => (unsupported_node "")),
rule!((copyExpr) => (unsupported_node "")),
rule!((discardStmt) => (unsupported_node "")),
rule!((fallThroughStmt) => (unsupported_node "")),
rule!((ifConfigDecl) => (unsupported_node "")),
Expand All @@ -1578,7 +1587,6 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!((subscriptDecl) => (unsupported_node "")),
rule!((suppressedType) => (unsupported_node "")),
rule!((typeExpr) => (unsupported_node "")),
rule!((unsafeExpr) => (unsupported_node "")),
rule!((yieldStmt) => (unsupported_node "")),
// Anything reaching this final generic handler has neither a
// dedicated rule nor an explicit unsupported entry.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
let original = [1, 2, 3]
let borrowed = borrow original

---

sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
arrayExpr
elements:
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "2"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "3"
leftSquare: [
rightSquare: ]
pattern:
identifierPattern
identifier: identifier "original"
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
borrowExpr
expression:
declReferenceExpr
baseName: identifier "original"
borrowKeyword: borrow
pattern:
identifierPattern
identifier: identifier "borrowed"

---

top_level source="⟨body⟩"
body:
block source="⟨stmt⟩\n⟨stmt⟩"
stmt:
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
modifier: modifier "let" source="let"
pattern: identifier "original" source="original"
value:
array_literal source="[⟨element⟩, ⟨element⟩, ⟨element⟩]"
element:
int_literal "1" source="1"
int_literal "2" source="2"
int_literal "3" source="3"
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
modifier: modifier "let" source="let"
pattern: identifier "borrowed" source="borrowed"
value:
unary_expr source="⟨operator⟩ ⟨operand⟩"
operand: identifier "original" source="original"
operator: prefix_operator "borrow" source="borrow"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let original = [1, 2, 3]
let borrowed = borrow original
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,7 @@ top_level source="⟨body⟩"
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
modifier: modifier "let" source="let"
pattern: identifier "consumed" source="consumed"
value: unsupported_node "consume original" source="consume original"
value:
unary_expr source="⟨operator⟩ ⟨operand⟩"
operand: identifier "original" source="original"
operator: prefix_operator "consume" source="consume"
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,7 @@ top_level source="⟨body⟩"
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
modifier: modifier "let" source="let"
pattern: identifier "copied" source="copied"
value: unsupported_node "copy original" source="copy original"
value:
unary_expr source="⟨operator⟩ ⟨operand⟩"
operand: identifier "original" source="original"
operator: prefix_operator "copy" source="copy"
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ top_level source="⟨body⟩"
function_declaration source="func ⟨name_node⟩() ⟨body⟩"
name_node: identifier "doWork" source="doWork"
body: block "{}" source="{}"
unsupported_node "unsafe doWork()" source="unsafe doWork()"
unary_expr source="⟨operator⟩ ⟨operand⟩"
operand:
call_expr source="⟨callee⟩()"
callee: identifier "doWork" source="doWork"
operator: prefix_operator "unsafe" source="unsafe"
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ private class SwiftDataFlowPlugin extends DataFlowPlugin {
)
or
exists(UnaryExpr expr |
expr.getOperator().(PrefixOperator).getValue() = ["try", "try!", "try?", "await"] and
expr.getOperator().(PrefixOperator).getValue() =
["try", "try!", "try?", "await", "borrow", "consume", "copy", "unsafe"] and
node1.isResultValue(expr.getOperand()) and
step.value() and
node2.isResultValue(expr)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
func testBorrow() {
let original = source("borrow")
let borrowed = borrow original
sink(borrowed) // $ hasValueFlow=borrow
}

func testConsume() {
let original = source("consume")
let consumed = consume original
sink(consumed) // $ hasValueFlow=consume
}

func testCopy() {
let original = source("copy")
let copied = copy original
sink(copied) // $ hasValueFlow=copy
}

func testUnsafe() {
let original = source("unsafe")
let unchecked = unsafe original
sink(unchecked) // $ hasValueFlow=unsafe
}
40 changes: 40 additions & 0 deletions unified/ql/test/library-tests/dataflow/test.expected
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,22 @@ edges
| implicit-self.swift:85:9:85:14 | [incoming] ... .x | implicit-self.swift:85:9:85:12 | [post] self [x] | provenance | |
| implicit-self.swift:85:29:85:43 | source(...) | implicit-self.swift:85:9:85:14 | [incoming] ... .x | provenance | |
| implicit-self.swift:87:14:87:17 | self [x] | implicit-self.swift:87:14:87:19 | ... .x | provenance | |
| modified-expressions.swift:2:9:2:16 | original | modified-expressions.swift:3:27:3:34 | original | provenance | |
| modified-expressions.swift:2:20:2:35 | source(...) | modified-expressions.swift:2:9:2:16 | original | provenance | |
| modified-expressions.swift:3:9:3:16 | borrowed | modified-expressions.swift:4:10:4:17 | borrowed | provenance | |
| modified-expressions.swift:3:27:3:34 | original | modified-expressions.swift:3:9:3:16 | borrowed | provenance | |
| modified-expressions.swift:8:9:8:16 | original | modified-expressions.swift:9:28:9:35 | original | provenance | |
| modified-expressions.swift:8:20:8:36 | source(...) | modified-expressions.swift:8:9:8:16 | original | provenance | |
| modified-expressions.swift:9:9:9:16 | consumed | modified-expressions.swift:10:10:10:17 | consumed | provenance | |
| modified-expressions.swift:9:28:9:35 | original | modified-expressions.swift:9:9:9:16 | consumed | provenance | |
| modified-expressions.swift:14:9:14:16 | original | modified-expressions.swift:15:23:15:30 | original | provenance | |
| modified-expressions.swift:14:20:14:33 | source(...) | modified-expressions.swift:14:9:14:16 | original | provenance | |
| modified-expressions.swift:15:9:15:14 | copied | modified-expressions.swift:16:10:16:15 | copied | provenance | |
| modified-expressions.swift:15:23:15:30 | original | modified-expressions.swift:15:9:15:14 | copied | provenance | |
| modified-expressions.swift:20:9:20:16 | original | modified-expressions.swift:21:28:21:35 | original | provenance | |
| modified-expressions.swift:20:20:20:35 | source(...) | modified-expressions.swift:20:9:20:16 | original | provenance | |
| modified-expressions.swift:21:9:21:17 | unchecked | modified-expressions.swift:22:10:22:18 | unchecked | provenance | |
| modified-expressions.swift:21:28:21:35 | original | modified-expressions.swift:21:9:21:17 | unchecked | provenance | |
| short-return.swift:7:33:7:46 | source(...) | short-return.swift:8:10:8:19 | getValue(...) | provenance | |
| test.swift:17:10:17:23 | source(...) | test.swift:17:10:17:32 | ... + ... | provenance | |
| test.swift:18:19:18:32 | source(...) | test.swift:18:10:18:32 | ... + ... | provenance | |
Expand Down Expand Up @@ -985,6 +1001,26 @@ nodes
| implicit-self.swift:86:14:86:14 | x | semmle.label | x |
| implicit-self.swift:87:14:87:17 | self [x] | semmle.label | self [x] |
| implicit-self.swift:87:14:87:19 | ... .x | semmle.label | ... .x |
| modified-expressions.swift:2:9:2:16 | original | semmle.label | original |
| modified-expressions.swift:2:20:2:35 | source(...) | semmle.label | source(...) |
| modified-expressions.swift:3:9:3:16 | borrowed | semmle.label | borrowed |
| modified-expressions.swift:3:27:3:34 | original | semmle.label | original |
| modified-expressions.swift:4:10:4:17 | borrowed | semmle.label | borrowed |
| modified-expressions.swift:8:9:8:16 | original | semmle.label | original |
| modified-expressions.swift:8:20:8:36 | source(...) | semmle.label | source(...) |
| modified-expressions.swift:9:9:9:16 | consumed | semmle.label | consumed |
| modified-expressions.swift:9:28:9:35 | original | semmle.label | original |
| modified-expressions.swift:10:10:10:17 | consumed | semmle.label | consumed |
| modified-expressions.swift:14:9:14:16 | original | semmle.label | original |
| modified-expressions.swift:14:20:14:33 | source(...) | semmle.label | source(...) |
| modified-expressions.swift:15:9:15:14 | copied | semmle.label | copied |
| modified-expressions.swift:15:23:15:30 | original | semmle.label | original |
| modified-expressions.swift:16:10:16:15 | copied | semmle.label | copied |
| modified-expressions.swift:20:9:20:16 | original | semmle.label | original |
| modified-expressions.swift:20:20:20:35 | source(...) | semmle.label | source(...) |
| modified-expressions.swift:21:9:21:17 | unchecked | semmle.label | unchecked |
| modified-expressions.swift:21:28:21:35 | original | semmle.label | original |
| modified-expressions.swift:22:10:22:18 | unchecked | semmle.label | unchecked |
| short-return.swift:7:33:7:46 | source(...) | semmle.label | source(...) |
| short-return.swift:8:10:8:19 | getValue(...) | semmle.label | getValue(...) |
| test.swift:9:10:9:21 | source(...) | semmle.label | source(...) |
Expand Down Expand Up @@ -1342,6 +1378,10 @@ testFailures
| implicit-self.swift:80:14:80:19 | ... .x | implicit-self.swift:78:24:78:38 | source(...) | implicit-self.swift:80:14:80:19 | ... .x | $@ | implicit-self.swift:78:24:78:38 | source(...) | source(...) |
| implicit-self.swift:86:14:86:14 | x | implicit-self.swift:85:29:85:43 | source(...) | implicit-self.swift:86:14:86:14 | x | $@ | implicit-self.swift:85:29:85:43 | source(...) | source(...) |
| implicit-self.swift:87:14:87:19 | ... .x | implicit-self.swift:85:29:85:43 | source(...) | implicit-self.swift:87:14:87:19 | ... .x | $@ | implicit-self.swift:85:29:85:43 | source(...) | source(...) |
| modified-expressions.swift:4:10:4:17 | borrowed | modified-expressions.swift:2:20:2:35 | source(...) | modified-expressions.swift:4:10:4:17 | borrowed | $@ | modified-expressions.swift:2:20:2:35 | source(...) | source(...) |
| modified-expressions.swift:10:10:10:17 | consumed | modified-expressions.swift:8:20:8:36 | source(...) | modified-expressions.swift:10:10:10:17 | consumed | $@ | modified-expressions.swift:8:20:8:36 | source(...) | source(...) |
| modified-expressions.swift:16:10:16:15 | copied | modified-expressions.swift:14:20:14:33 | source(...) | modified-expressions.swift:16:10:16:15 | copied | $@ | modified-expressions.swift:14:20:14:33 | source(...) | source(...) |
| modified-expressions.swift:22:10:22:18 | unchecked | modified-expressions.swift:20:20:20:35 | source(...) | modified-expressions.swift:22:10:22:18 | unchecked | $@ | modified-expressions.swift:20:20:20:35 | source(...) | source(...) |
| short-return.swift:8:10:8:19 | getValue(...) | short-return.swift:7:33:7:46 | source(...) | short-return.swift:8:10:8:19 | getValue(...) | $@ | short-return.swift:7:33:7:46 | source(...) | source(...) |
| test.swift:9:10:9:21 | source(...) | test.swift:9:10:9:21 | source(...) | test.swift:9:10:9:21 | source(...) | $@ | test.swift:9:10:9:21 | source(...) | source(...) |
| test.swift:17:10:17:32 | ... + ... | test.swift:17:10:17:23 | source(...) | test.swift:17:10:17:32 | ... + ... | $@ | test.swift:17:10:17:23 | source(...) | source(...) |
Expand Down
Loading