Skip to content

Commit 9ed68d8

Browse files
committed
Unified: Add locations for blocks
Blocks are slightly awkward, since we destructure them (as codeBlock) in the query, and then reconstruct them (as `block`) in the rule body, meaning the location of the block is (by default) assigned to the wrong place by the heuristic. To get around this, I added a helper function that updates the location appropriately, including handling cases where we only optionally match a block. (Also, in some cases we can fix this by just not destructuring `codeBlock`s in the first place -- there's already a rule that maps `codeBlock` to `block`.)
1 parent 7cc7408 commit 9ed68d8

8 files changed

Lines changed: 49 additions & 18 deletions

File tree

‎unified/extractor/src/languages/swift/swift.rs‎

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use codeql_extractor::extractor::desugaring;
2-
use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree};
2+
use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at};
33

44
/// User context propagated from outer rules down to the inner rules that
55
/// emit the corresponding output declarations, so that each emitted node
@@ -60,6 +60,17 @@ impl SwiftContext {
6060
}
6161
}
6262

63+
fn block_with_anchor(
64+
ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>,
65+
statements: Vec<yeast::Id>,
66+
anchor: Option<yeast::Id>,
67+
) -> yeast::Id {
68+
match anchor {
69+
Some(anchor) => tree_at!(ctx, anchor, (block stmt: {statements})),
70+
None => tree!(ctx, (block stmt: {statements})),
71+
}
72+
}
73+
6374
/// Build a freshly-created `chained_declaration` modifier node if
6475
/// `ctx.is_chained`, else `None`. Used by inner declaration rules to
6576
/// emit the chained tag for non-first children of a flattening outer
@@ -301,14 +312,14 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
301312
bindings: (patternBinding
302313
pattern: (identifierPattern identifier: @@name)
303314
typeAnnotation: (typeAnnotation type: @ty)
304-
accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body)))
315+
accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body) @@accessor_block))
305316
=>
306317
(accessor_declaration
307318
modifier: (modifier #{spec})
308319
name_node: (identifier #{name})
309320
type: {ty}
310-
accessor_kind: (accessor_kind "get")
311-
body: (block stmt: {body}))
321+
accessor_kind: {ctx.literal_at_start_of("accessor_kind", "get", accessor_block)}
322+
body: {block_with_anchor(&mut ctx, body, Some(accessor_block))})
312323
),
313324
// A property with an explicit accessor block. swift-syntax makes both
314325
// shapes plain `accessorDecl`s, so they are told apart by the presence
@@ -564,15 +575,15 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
564575
signature: (functionSignature
565576
parameterClause: (functionParameterClause parameters: _* @params)
566577
returnClause: (returnClause type: @ret)?)
567-
body: (codeBlock statements: _* @body))
578+
body: (codeBlock) @body)
568579
=>
569580
(function_declaration
570581
modifier: {mods}
571582
name_node: (identifier #{name})
572583
type_parameter: {type_params}
573584
parameter: {params}
574585
return_type: {ret}
575-
body: (block stmt: {body}))
586+
body: {body})
576587
),
577588
rule!(
578589
(functionDecl
@@ -747,14 +758,14 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
747758
capture: (closureCaptureClause items: _* @captures)?
748759
parameterClause: _* @params
749760
returnClause: (returnClause type: @ret)?)?
750-
statements: _* @body)
761+
statements: _* @body) @@closure
751762
=>
752763
(function_expr
753764
modifier: {attrs}
754765
capture_declaration: {captures}
755766
parameter: {params}
756767
return_type: {ret}
757-
body: (block stmt: {body}))
768+
body: {block_with_anchor(&mut ctx, body, Some(closure))})
758769
),
759770
// A closure capture (`[weak self]`, `[x]`, `[y = expr]`). The optional
760771
// ownership specifier (`weak`/`unowned`) becomes a modifier; the
@@ -1277,22 +1288,33 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
12771288
modifiers: _* @mods
12781289
signature: (functionSignature
12791290
parameterClause: (functionParameterClause parameters: _* @params))
1280-
body: (codeBlock statements: _* @body_stmts)?)
1291+
body: (codeBlock) @body)
12811292
=>
12821293
(constructor_declaration
12831294
modifier: {mods}
12841295
parameter: {params}
1285-
body: (block stmt: {body_stmts}))
1296+
body: {body})
1297+
),
1298+
rule!(
1299+
(initializerDecl
1300+
modifiers: _* @mods
1301+
signature: (functionSignature
1302+
parameterClause: (functionParameterClause parameters: _* @params)))
1303+
=>
1304+
(constructor_declaration
1305+
modifier: {mods}
1306+
parameter: {params}
1307+
body: (block))
12861308
),
12871309
// Deinit declaration → destructor_declaration. Body statements optional.
12881310
rule!(
12891311
(deinitializerDecl
12901312
modifiers: _* @mods
1291-
body: (codeBlock statements: _* @body_stmts))
1313+
body: (codeBlock) @body)
12921314
=>
12931315
(destructor_declaration
12941316
modifier: {mods}
1295-
body: (block stmt: {body_stmts}))
1317+
body: {body})
12961318
),
12971319
// Typealias declaration
12981320
rule!(

‎unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,5 @@ top_level
4747
stmt:
4848
function_declaration
4949
name_node: identifier "doWork"
50-
body: block
50+
body: block "{}"
5151
unsupported_node "unsafe doWork()"

‎unified/extractor/tests/corpus/swift/types/class-function.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@ top_level
5454
function_declaration
5555
modifier: modifier "class"
5656
name_node: identifier "make"
57-
body: block
57+
body: block "{}"

‎unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ top_level
7777
external_name_node: identifier "height"
7878
type: identifier "Int"
7979
pattern: identifier "h"
80-
body: block
80+
body: block "{}"

‎unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ top_level
6868
type: unsupported_node "@convention(c) () -> Void"
6969
value:
7070
function_expr
71-
body: block
71+
body: block "{}"

‎unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ top_level
6161
type: unsupported_node "@Sendable () -> Void"
6262
value:
6363
function_expr
64-
body: block
64+
body: block "{}"

‎unified/extractor/tests/corpus/swift/types/static-function.output‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@ top_level
5454
function_declaration
5555
modifier: modifier "static"
5656
name_node: identifier "make"
57-
body: block
57+
body: block "{}"

‎unified/extractor/tests/location_tests.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ fn generic_type_children_have_local_ranges() {
7171
assert_has_span(&ast, source, "identifier", Some("Foo"), "Foo");
7272
}
7373

74+
#[test]
75+
fn declaration_and_operator_tokens_keep_precise_ranges() {
76+
let source = "func f() { return x }";
77+
let ast = desugar(source);
78+
79+
assert_has_span(&ast, source, "block", None, "{ return x }");
80+
assert_has_span(&ast, source, "return_expr", None, "return x");
81+
}
82+
7483
#[test]
7584
fn synthetic_type_and_modifier_nodes_use_empty_scope_start_ranges() {
7685
let source = "let array: [T]\nlet optional: T?\nenum E { case a, b }";

0 commit comments

Comments
 (0)