Skip to content

Commit c953ebd

Browse files
committed
Unified: Fix locations of various tokens
Handles things like `try!` (which is represented as two separate tokens -- we explicitly union their ranges) and "let" binding modifiers (where we reuse the bindingSpecifier, getting its location and string value for free).
1 parent 0bf705a commit c953ebd

15 files changed

Lines changed: 158 additions & 63 deletions

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

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use codeql_extractor::extractor::desugaring;
2-
use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at};
2+
use yeast::{
3+
ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at, tree_spanning,
4+
};
35

46
/// User context propagated from outer rules down to the inner rules that
57
/// emit the corresponding output declarations, so that each emitted node
@@ -97,7 +99,9 @@ fn and_chain(
9799
conds
98100
.into_iter()
99101
.reduce(|acc, elem| {
100-
tree!((binary_expr operator: (infix_operator "&&") left: {acc} right: {elem}))
102+
let operator_range = ctx.empty_source_range_between(acc, elem);
103+
let operator = ctx.literal_with_source_range("infix_operator", "&&", operator_range);
104+
tree!((binary_expr operator: {operator} left: {acc} right: {elem}))
101105
})
102106
.expect("control-flow statement must have at least one condition")
103107
}
@@ -474,14 +478,24 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
474478
// `enumCaseDecl` rule below) and are tagged `enum_case`, after any
475479
// `chained_declaration` tag.
476480
rule!(
477-
(enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params))
478-
=>
479-
(class_like_declaration
480-
modifier: {ctx.outer_modifiers.clone()}
481-
modifier: {chained_modifier(&mut ctx)}
482-
modifier: (modifier "enum_case")
483-
name_node: (identifier #{name})
484-
member: (constructor_declaration parameter: {params} body: (block)))
481+
(enumCaseElement
482+
name: @name
483+
parameterClause: (enumCaseParameterClause parameters: _* @params)) @@element
484+
=>
485+
class_like_declaration {
486+
let body = tree!((block));
487+
let constructor = tree_at!(
488+
ctx,
489+
element,
490+
(constructor_declaration parameter: {params} body: {body})
491+
);
492+
tree!((class_like_declaration
493+
modifier: {ctx.outer_modifiers.clone()}
494+
modifier: {chained_modifier(&mut ctx)}
495+
modifier: (modifier "enum_case")
496+
name_node: (identifier #{name})
497+
member: {constructor}))
498+
}
485499
),
486500
rule!(
487501
(enumCaseElement name: @name rawValue: (initializerClause value: @val))
@@ -686,12 +700,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
686700
label: _? @@lbl
687701
expression: (functionCallExpr
688702
calledExpression: @constructor
689-
arguments: _* @elements))
703+
arguments: _* @elements) @@call)
690704
=>
691705
argument {
706+
let value = tree_at!(
707+
ctx,
708+
call,
709+
(call_expr callee: {constructor} argument: {elements})
710+
);
692711
tree!((argument
693712
name_node: (identifier #{lbl})?
694-
value: (call_expr callee: {constructor} argument: {elements})))
713+
value: {value}))
695714
}
696715
),
697716
rule!(
@@ -864,6 +883,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
864883
// form is matched first.
865884
rule!(
866885
(optionalBindingCondition
886+
bindingSpecifier: @@spec
867887
pattern: (identifierPattern identifier: @name)
868888
initializer: (initializerClause value: @val))
869889
=>
@@ -872,18 +892,20 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
872892
pattern: (call_expr
873893
callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some"))
874894
argument: (argument value: (expr_pattern
875-
modifier: (modifier "let")
895+
modifier: (modifier #{spec})
876896
expr: (identifier #{name})))))
877897
),
878898
rule!(
879-
(optionalBindingCondition pattern: (identifierPattern identifier: @name))
899+
(optionalBindingCondition
900+
bindingSpecifier: @@spec
901+
pattern: (identifierPattern identifier: @name))
880902
=>
881903
(pattern_guard_expr
882904
value: (identifier #{name})
883905
pattern: (call_expr
884906
callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some"))
885907
argument: (argument value: (expr_pattern
886-
modifier: (modifier "let")
908+
modifier: (modifier #{spec})
887909
expr: (identifier #{name})))))
888910
),
889911
// A single condition in an `if`/`while`/`guard` condition list unwraps to
@@ -967,11 +989,19 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
967989
}),
968990
// try/try?/try! expr → unary_expr with operator "try", "try?" or "try!"
969991
rule!(
970-
(tryExpr questionOrExclamationMark: _? @@m expression: @e)
992+
(tryExpr
993+
tryKeyword: @@keyword
994+
questionOrExclamationMark: _? @@m
995+
expression: @e)
971996
=>
972997
expr {
973998
let op = format!("try{}", m.map(|m| ctx.source_text(m)).unwrap_or_default());
974-
tree!((unary_expr operator: (prefix_operator #{op}) operand: {e}))
999+
let operator = tree_spanning!(
1000+
ctx,
1001+
std::iter::once(keyword).chain(m),
1002+
(prefix_operator #{op})
1003+
);
1004+
tree!((unary_expr operator: {operator} operand: {e}))
9751005
}
9761006
),
9771007
// Do-catch → try_expr
@@ -1005,17 +1035,29 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10051035
// Catch block without error binding
10061036
rule!((catchClause body: @body) => (catch_clause body: {body})),
10071037
// As expression (type cast) — as?, as!
1008-
rule!((asExpr expression: @val questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr {
1038+
rule!((asExpr expression: @val asKeyword: @@keyword questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr {
10091039
let op = format!("as{}", mark.map(|m| ctx.source_text(m)).unwrap_or_default());
1010-
tree!((type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty}))
1040+
let operator = tree_spanning!(
1041+
ctx,
1042+
std::iter::once(keyword).chain(mark),
1043+
(infix_operator #{op})
1044+
);
1045+
tree!((type_cast_expr expr: {val} operator: {operator} type: {ty}))
10111046
}),
10121047
// Check expression (`x is T`) → type_test_expr
1013-
rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})),
1048+
rule!((isExpr expression: @val isKeyword: @@keyword type: @ty) => (type_test_expr
1049+
expr: {val}
1050+
operator: {tree_at!(ctx, keyword, (infix_operator "is"))}
1051+
type: {ty})),
10141052
// Await expression → unary_expr with operator "await"
1015-
rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})),
1053+
rule!((awaitExpr awaitKeyword: @@keyword expression: @val) => (unary_expr
1054+
operator: {tree_at!(ctx, keyword, (prefix_operator "await"))}
1055+
operand: {val})),
10161056
// Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
10171057
// `forceUnwrapExpr` node.
1018-
rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})),
1058+
rule!((forceUnwrapExpr expression: @e exclamationMark: @@mark) => (unary_expr
1059+
operator: {tree_at!(ctx, mark, (postfix_operator "!"))}
1060+
operand: {e})),
10191061
// ---- Imports ----
10201062
// An import declaration. The dotted path (a list of
10211063
// `importPathComponent`s) becomes a `name_node`/`member_access_expr`
@@ -1030,14 +1072,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10301072
attributes: _* @attrs
10311073
modifiers: _* @mods
10321074
importKindSpecifier: _? @@kind
1033-
path: (importPathComponent name: @@parts)*)
1075+
path: (importPathComponent name: @@parts)*) @@decl
10341076
=>
10351077
import_declaration {
10361078
let last = *parts.last().ok_or("import has no path")?;
10371079
let pattern = match kind {
1038-
None => tree!((named_pattern
1039-
name_node: (identifier #{last})
1040-
sub_pattern: (bulk_importing_pattern))),
1080+
None => {
1081+
let bulk = tree_at!(ctx, decl, (bulk_importing_pattern));
1082+
tree!((named_pattern
1083+
name_node: (identifier #{last})
1084+
sub_pattern: {bulk}))
1085+
}
10411086
Some(_) => tree!((identifier #{last})),
10421087
};
10431088
tree!((import_declaration

‎unified/extractor/tests/corpus/swift/control-flow/guard-let.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ top_level source="⟨body⟩"
5252
argument:
5353
argument source="⟨value⟩"
5454
value:
55-
expr_pattern source="let ⟨expr⟩"
56-
modifier: modifier "let" source=""
55+
expr_pattern source="⟨modifier⟩ ⟨expr⟩"
56+
modifier: modifier "let" source="let"
5757
expr: identifier "value" source="value"
5858
value: identifier "optional" source="optional"
5959
else:

‎unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ top_level source="⟨body⟩"
6565
argument:
6666
argument source="⟨value⟩"
6767
value:
68-
expr_pattern source="let ⟨expr⟩"
69-
modifier: modifier "let" source=""
68+
expr_pattern source="⟨modifier⟩ ⟨expr⟩"
69+
modifier: modifier "let" source="let"
7070
expr: identifier "value" source="value"
7171
value: identifier "optional" source="optional"
7272
then:

‎unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ top_level source="⟨body⟩"
173173
base: inferred_type_expr "." source="."
174174
member_name_node: identifier "received" source="received"
175175
argument:
176-
argument source="⟨value⟩),"
176+
argument source="⟨value⟩,"
177177
value:
178-
call_expr source="⟨callee⟩(⟨argument⟩"
178+
call_expr source="⟨callee⟩(⟨argument⟩)"
179179
callee:
180180
member_access_expr source="⟨base⟩⟨member_name_node⟩"
181181
base: inferred_type_expr "." source="."

‎unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -350,23 +350,23 @@ top_level source="⟨body⟩"
350350
argument:
351351
argument source="⟨value⟩"
352352
value: identifier "optional" source="optional"
353-
unary_expr source="try ⟨operand⟩"
353+
unary_expr source="⟨operator⟩ ⟨operand⟩"
354354
operand: identifier "value" source="value"
355-
operator: prefix_operator "try" source=""
356-
unary_expr source="⟨operand⟩!"
355+
operator: prefix_operator "try" source="try"
356+
unary_expr source="⟨operand⟩⟨operator⟩"
357357
operand: identifier "value" source="value"
358-
operator: postfix_operator "!" source=""
359-
type_cast_expr source="⟨expr⟩ as ⟨type⟩"
358+
operator: postfix_operator "!" source="!"
359+
type_cast_expr source="⟨expr⟩ ⟨operator⟩ ⟨type⟩"
360360
expr: identifier "value" source="value"
361-
operator: infix_operator "as" source=""
361+
operator: infix_operator "as" source="as"
362362
type: identifier "Target" source="Target"
363-
type_test_expr source="⟨expr⟩ is ⟨type⟩"
363+
type_test_expr source="⟨expr⟩ ⟨operator⟩ ⟨type⟩"
364364
expr: identifier "value" source="value"
365-
operator: infix_operator "is" source=""
365+
operator: infix_operator "is" source="is"
366366
type: identifier "Target" source="Target"
367-
unary_expr source="await ⟨operand⟩"
367+
unary_expr source="⟨operator⟩ ⟨operand⟩"
368368
operand: identifier "value" source="value"
369-
operator: prefix_operator "await" source=""
369+
operator: prefix_operator "await" source="await"
370370
body:
371371
block source="⟨stmt⟩"
372372
stmt:

‎unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ top_level source="⟨body⟩"
3636
member_name_node: identifier "Networking" source="Networking"
3737
member_name_node: identifier "URLSession" source="URLSession"
3838
pattern:
39-
named_pattern source="import Foundation.Networking.⟨name_node⟩"
39+
named_pattern source="⟨sub_pattern⟩⟨name_node⟩"
4040
name_node: identifier "URLSession" source="URLSession"
41-
sub_pattern: bulk_importing_pattern source=""
41+
sub_pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" source="import Foundation.Networking.URLSession"

‎unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ top_level source="⟨body⟩"
3030
base: identifier "Foundation" source="Foundation"
3131
member_name_node: identifier "Networking" source="Networking"
3232
pattern:
33-
named_pattern source="import Foundation.⟨name_node⟩"
33+
named_pattern source="⟨sub_pattern⟩⟨name_node⟩"
3434
name_node: identifier "Networking" source="Networking"
35-
sub_pattern: bulk_importing_pattern source=""
35+
sub_pattern: bulk_importing_pattern "import Foundation.Networking" source="import Foundation.Networking"

‎unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ top_level source="⟨body⟩"
2424
import_declaration source="⟨pattern⟩⟨imported_expr⟩"
2525
imported_expr: identifier "Foundation" source="Foundation"
2626
pattern:
27-
named_pattern source="import ⟨name_node⟩"
27+
named_pattern source="⟨sub_pattern⟩⟨name_node⟩"
2828
name_node: identifier "Foundation" source="Foundation"
29-
sub_pattern: bulk_importing_pattern source=""
29+
sub_pattern: bulk_importing_pattern "import Foundation" source="import Foundation"

‎unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ top_level source="⟨body⟩"
144144
body:
145145
block source="{\n ⟨stmt⟩\n}"
146146
stmt:
147-
unary_expr source="try ⟨operand⟩"
147+
unary_expr source="⟨operator⟩ ⟨operand⟩"
148148
operand:
149149
call_expr source="⟨callee⟩()"
150150
callee: identifier "foo" source="foo"
151-
operator: prefix_operator "try" source=""
151+
operator: prefix_operator "try" source="try"
152152
catch_clause:
153153
catch_clause source="catch ⟨pattern⟩ ⟨body⟩"
154154
pattern:

‎unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ top_level source="⟨body⟩"
6565
body:
6666
block source="{\n ⟨stmt⟩\n}"
6767
stmt:
68-
unary_expr source="try ⟨operand⟩"
68+
unary_expr source="⟨operator⟩ ⟨operand⟩"
6969
operand:
7070
call_expr source="⟨callee⟩()"
7171
callee: identifier "foo" source="foo"
72-
operator: prefix_operator "try" source=""
72+
operator: prefix_operator "try" source="try"
7373
catch_clause:
7474
catch_clause source="catch ⟨body⟩"
7575
body:

0 commit comments

Comments
 (0)