11use 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}
@@ -123,21 +127,15 @@ fn member_chain(
123127 ctx : & mut yeast:: build:: BuildCtx < ' _ , SwiftContext > ,
124128 parts : Vec < yeast:: Id > ,
125129) -> yeast:: Id {
126- // `member_chain` builds the imported expression inside the larger import
127- // declaration rule. The imported expression should span the import path,
128- // not the whole declaration including the `import` keyword.
129- let source_range = ctx. source_range . take ( ) ;
130130 let mut iter = parts. into_iter ( ) ;
131131 let first = iter
132132 . next ( )
133133 . expect ( "identifier with `part:` must have at least one part" ) ;
134134 let init = tree ! ( ( identifier #{ first} ) ) ;
135- let result = iter. fold (
135+ iter. fold (
136136 init,
137137 |acc, elem| tree ! ( ( member_access_expr base: { acc} member_name_node: ( identifier #{ elem} ) ) ) ,
138- ) ;
139- ctx. source_range = source_range;
140- result
138+ )
141139}
142140
143141/// Compound-assignment operator spellings (`+=`, `<<=`, ...). Used to tell a
@@ -495,14 +493,24 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
495493 // `enumCaseDecl` rule below) and are tagged `enum_case`, after any
496494 // `chained_declaration` tag.
497495 rule!(
498- ( enumCaseElement name: @name parameterClause: ( enumCaseParameterClause parameters: _* @params) )
499- =>
500- ( class_like_declaration
501- modifier: { ctx. outer_modifiers. clone( ) }
502- modifier: { chained_modifier( & mut ctx) }
503- modifier: ( modifier "enum_case" )
504- name_node: ( identifier #{ name} )
505- member: ( constructor_declaration parameter: { params} body: ( block) ) )
496+ ( enumCaseElement
497+ name: @name
498+ parameterClause: ( enumCaseParameterClause parameters: _* @params) ) @@element
499+ =>
500+ class_like_declaration {
501+ let body = tree!( ( block) ) ;
502+ let constructor = tree_at!(
503+ ctx,
504+ element,
505+ ( constructor_declaration parameter: { params} body: { body} )
506+ ) ;
507+ tree!( ( class_like_declaration
508+ modifier: { ctx. outer_modifiers. clone( ) }
509+ modifier: { chained_modifier( & mut ctx) }
510+ modifier: ( modifier "enum_case" )
511+ name_node: ( identifier #{ name} )
512+ member: { constructor} ) )
513+ }
506514 ) ,
507515 rule!(
508516 ( enumCaseElement name: @name rawValue: ( initializerClause value: @val) )
@@ -702,12 +710,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
702710 label: _? @@lbl
703711 expression: ( functionCallExpr
704712 calledExpression: @constructor
705- arguments: _* @elements) )
713+ arguments: _* @elements) @@call )
706714 =>
707715 argument {
716+ let value = tree_at!(
717+ ctx,
718+ call,
719+ ( call_expr callee: { constructor} argument: { elements} )
720+ ) ;
708721 tree!( ( argument
709722 name_node: ( identifier #{ lbl} ) ?
710- value: ( call_expr callee : { constructor } argument : { elements } ) ) )
723+ value: { value } ) )
711724 }
712725 ) ,
713726 rule!(
@@ -880,6 +893,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
880893 // form is matched first.
881894 rule!(
882895 ( optionalBindingCondition
896+ bindingSpecifier: @@spec
883897 pattern: ( identifierPattern identifier: @name)
884898 initializer: ( initializerClause value: @val) )
885899 =>
@@ -888,18 +902,20 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
888902 pattern: ( call_expr
889903 callee: ( member_access_expr base: ( identifier "Optional" ) member_name_node: ( identifier "some" ) )
890904 argument: ( argument value: ( expr_pattern
891- modifier: ( modifier "let" )
905+ modifier: ( modifier # { spec } )
892906 expr: ( identifier #{ name} ) ) ) ) )
893907 ) ,
894908 rule!(
895- ( optionalBindingCondition pattern: ( identifierPattern identifier: @name) )
909+ ( optionalBindingCondition
910+ bindingSpecifier: @@spec
911+ pattern: ( identifierPattern identifier: @name) )
896912 =>
897913 ( pattern_guard_expr
898914 value: ( identifier #{ name} )
899915 pattern: ( call_expr
900916 callee: ( member_access_expr base: ( identifier "Optional" ) member_name_node: ( identifier "some" ) )
901917 argument: ( argument value: ( expr_pattern
902- modifier: ( modifier "let" )
918+ modifier: ( modifier # { spec } )
903919 expr: ( identifier #{ name} ) ) ) ) )
904920 ) ,
905921 // A single condition in an `if`/`while`/`guard` condition list unwraps to
@@ -983,11 +999,19 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
983999 } ) ,
9841000 // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!"
9851001 rule!(
986- ( tryExpr questionOrExclamationMark: _? @@m expression: @e)
1002+ ( tryExpr
1003+ tryKeyword: @@keyword
1004+ questionOrExclamationMark: _? @@m
1005+ expression: @e)
9871006 =>
9881007 expr {
9891008 let op = format!( "try{}" , m. map( |m| ctx. source_text( m) ) . unwrap_or_default( ) ) ;
990- tree!( ( unary_expr operator: ( prefix_operator #{ op} ) operand: { e} ) )
1009+ let operator = tree_spanning!(
1010+ ctx,
1011+ std:: iter:: once( keyword) . chain( m) ,
1012+ ( prefix_operator #{ op} )
1013+ ) ;
1014+ tree!( ( unary_expr operator: { operator} operand: { e} ) )
9911015 }
9921016 ) ,
9931017 // Do-catch → try_expr
@@ -1021,17 +1045,29 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10211045 // Catch block without error binding
10221046 rule!( ( catchClause body: @body) => ( catch_clause body: { body} ) ) ,
10231047 // As expression (type cast) — as?, as!
1024- rule!( ( asExpr expression: @val questionOrExclamationMark: _? @@mark type : @ty) => type_cast_expr {
1048+ rule!( ( asExpr expression: @val asKeyword : @@keyword questionOrExclamationMark: _? @@mark type : @ty) => type_cast_expr {
10251049 let op = format!( "as{}" , mark. map( |m| ctx. source_text( m) ) . unwrap_or_default( ) ) ;
1026- tree!( ( type_cast_expr expr: { val} operator: ( infix_operator #{ op} ) type : { ty} ) )
1050+ let operator = tree_spanning!(
1051+ ctx,
1052+ std:: iter:: once( keyword) . chain( mark) ,
1053+ ( infix_operator #{ op} )
1054+ ) ;
1055+ tree!( ( type_cast_expr expr: { val} operator: { operator} type : { ty} ) )
10271056 } ) ,
10281057 // Check expression (`x is T`) → type_test_expr
1029- rule!( ( isExpr expression: @val type : @ty) => ( type_test_expr expr: { val} operator: ( infix_operator "is" ) type : { ty} ) ) ,
1058+ rule!( ( isExpr expression: @val isKeyword: @@keyword type : @ty) => ( type_test_expr
1059+ expr: { val}
1060+ operator: { tree_at!( ctx, keyword, ( infix_operator "is" ) ) }
1061+ type : { ty} ) ) ,
10301062 // Await expression → unary_expr with operator "await"
1031- rule!( ( awaitExpr expression: @val) => ( unary_expr operator: ( prefix_operator "await" ) operand: { val} ) ) ,
1063+ rule!( ( awaitExpr awaitKeyword: @@keyword expression: @val) => ( unary_expr
1064+ operator: { tree_at!( ctx, keyword, ( prefix_operator "await" ) ) }
1065+ operand: { val} ) ) ,
10321066 // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
10331067 // `forceUnwrapExpr` node.
1034- rule!( ( forceUnwrapExpr expression: @e) => ( unary_expr operator: ( postfix_operator "!" ) operand: { e} ) ) ,
1068+ rule!( ( forceUnwrapExpr expression: @e exclamationMark: @@mark) => ( unary_expr
1069+ operator: { tree_at!( ctx, mark, ( postfix_operator "!" ) ) }
1070+ operand: { e} ) ) ,
10351071 // ---- Imports ----
10361072 // An import declaration. The dotted path (a list of
10371073 // `importPathComponent`s) becomes a `name_node`/`member_access_expr`
@@ -1046,14 +1082,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10461082 attributes: _* @attrs
10471083 modifiers: _* @mods
10481084 importKindSpecifier: _? @@kind
1049- path: ( importPathComponent name: @@parts) * )
1085+ path: ( importPathComponent name: @@parts) * ) @@decl
10501086 =>
10511087 import_declaration {
10521088 let last = * parts. last( ) . ok_or( "import has no path" ) ?;
10531089 let pattern = match kind {
1054- None => tree!( ( named_pattern
1055- name_node: ( identifier #{ last} )
1056- sub_pattern: ( bulk_importing_pattern) ) ) ,
1090+ None => {
1091+ let bulk = tree_at!( ctx, decl, ( bulk_importing_pattern) ) ;
1092+ tree!( ( named_pattern
1093+ name_node: ( identifier #{ last} )
1094+ sub_pattern: { bulk} ) )
1095+ }
10571096 Some ( _) => tree!( ( identifier #{ last} ) ) ,
10581097 } ;
10591098 tree!( ( import_declaration
0 commit comments