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}
@@ -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
0 commit comments