Skip to content

Commit ba9279d

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 de995a9 commit ba9279d

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))
@@ -681,12 +695,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
681695
label: _? @@lbl
682696
expression: (functionCallExpr
683697
calledExpression: @constructor
684-
arguments: _* @elements))
698+
arguments: _* @elements) @@call)
685699
=>
686700
argument {
701+
let value = tree_at!(
702+
ctx,
703+
call,
704+
(call_expr callee: {constructor} argument: {elements})
705+
);
687706
tree!((argument
688707
name_node: (identifier #{lbl})?
689-
value: (call_expr callee: {constructor} argument: {elements})))
708+
value: {value}))
690709
}
691710
),
692711
rule!(
@@ -859,6 +878,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
859878
// form is matched first.
860879
rule!(
861880
(optionalBindingCondition
881+
bindingSpecifier: @@spec
862882
pattern: (identifierPattern identifier: @name)
863883
initializer: (initializerClause value: @val))
864884
=>
@@ -867,18 +887,20 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
867887
pattern: (call_expr
868888
callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some"))
869889
argument: (argument value: (expr_pattern
870-
modifier: (modifier "let")
890+
modifier: (modifier #{spec})
871891
expr: (identifier #{name})))))
872892
),
873893
rule!(
874-
(optionalBindingCondition pattern: (identifierPattern identifier: @name))
894+
(optionalBindingCondition
895+
bindingSpecifier: @@spec
896+
pattern: (identifierPattern identifier: @name))
875897
=>
876898
(pattern_guard_expr
877899
value: (identifier #{name})
878900
pattern: (call_expr
879901
callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some"))
880902
argument: (argument value: (expr_pattern
881-
modifier: (modifier "let")
903+
modifier: (modifier #{spec})
882904
expr: (identifier #{name})))))
883905
),
884906
// A single condition in an `if`/`while`/`guard` condition list unwraps to
@@ -962,11 +984,19 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
962984
}),
963985
// try/try?/try! expr → unary_expr with operator "try", "try?" or "try!"
964986
rule!(
965-
(tryExpr questionOrExclamationMark: _? @@m expression: @e)
987+
(tryExpr
988+
tryKeyword: @@keyword
989+
questionOrExclamationMark: _? @@m
990+
expression: @e)
966991
=>
967992
expr {
968993
let op = format!("try{}", m.map(|m| ctx.source_text(m)).unwrap_or_default());
969-
tree!((unary_expr operator: (prefix_operator #{op}) operand: {e}))
994+
let operator = tree_spanning!(
995+
ctx,
996+
std::iter::once(keyword).chain(m),
997+
(prefix_operator #{op})
998+
);
999+
tree!((unary_expr operator: {operator} operand: {e}))
9701000
}
9711001
),
9721002
// Do-catch → try_expr
@@ -1000,17 +1030,29 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10001030
// Catch block without error binding
10011031
rule!((catchClause body: @body) => (catch_clause body: {body})),
10021032
// As expression (type cast) — as?, as!
1003-
rule!((asExpr expression: @val questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr {
1033+
rule!((asExpr expression: @val asKeyword: @@keyword questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr {
10041034
let op = format!("as{}", mark.map(|m| ctx.source_text(m)).unwrap_or_default());
1005-
tree!((type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty}))
1035+
let operator = tree_spanning!(
1036+
ctx,
1037+
std::iter::once(keyword).chain(mark),
1038+
(infix_operator #{op})
1039+
);
1040+
tree!((type_cast_expr expr: {val} operator: {operator} type: {ty}))
10061041
}),
10071042
// Check expression (`x is T`) → type_test_expr
1008-
rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})),
1043+
rule!((isExpr expression: @val isKeyword: @@keyword type: @ty) => (type_test_expr
1044+
expr: {val}
1045+
operator: {tree_at!(ctx, keyword, (infix_operator "is"))}
1046+
type: {ty})),
10091047
// Await expression → unary_expr with operator "await"
1010-
rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})),
1048+
rule!((awaitExpr awaitKeyword: @@keyword expression: @val) => (unary_expr
1049+
operator: {tree_at!(ctx, keyword, (prefix_operator "await"))}
1050+
operand: {val})),
10111051
// Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
10121052
// `forceUnwrapExpr` node.
1013-
rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})),
1053+
rule!((forceUnwrapExpr expression: @e exclamationMark: @@mark) => (unary_expr
1054+
operator: {tree_at!(ctx, mark, (postfix_operator "!"))}
1055+
operand: {e})),
10141056
// ---- Imports ----
10151057
// An import declaration. The dotted path (a list of
10161058
// `importPathComponent`s) becomes a `name_node`/`member_access_expr`
@@ -1025,14 +1067,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10251067
attributes: _* @attrs
10261068
modifiers: _* @mods
10271069
importKindSpecifier: _? @@kind
1028-
path: (importPathComponent name: @@parts)*)
1070+
path: (importPathComponent name: @@parts)*) @@decl
10291071
=>
10301072
import_declaration {
10311073
let last = *parts.last().ok_or("import has no path")?;
10321074
let pattern = match kind {
1033-
None => tree!((named_pattern
1034-
name_node: (identifier #{last})
1035-
sub_pattern: (bulk_importing_pattern))),
1075+
None => {
1076+
let bulk = tree_at!(ctx, decl, (bulk_importing_pattern));
1077+
tree!((named_pattern
1078+
name_node: (identifier #{last})
1079+
sub_pattern: {bulk}))
1080+
}
10361081
Some(_) => tree!((identifier #{last})),
10371082
};
10381083
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)