Skip to content

Commit b762904

Browse files
authored
Merge pull request #22740 from github/unified/swift-macro
Unified: Extract Swift macro calls
2 parents 9837879 + e08ffdd commit b762904

7 files changed

Lines changed: 266 additions & 7 deletions

File tree

‎unified/extractor/ast_types.yml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ supertypes:
1313
- binary_expr
1414
- unary_expr
1515
- call_expr
16+
- macro_call_expr
1617
- member_access_expr
1718
- super_expr
1819
- function_expr
@@ -175,6 +176,13 @@ named:
175176
callee: expr
176177
argument*: argument
177178

179+
# A macro call expression, such as `#expect(x == y)` in Swift or
180+
# `assert!(x == y)` in Rust.
181+
macro_call_expr:
182+
macro_name_node: identifier
183+
type_argument*: expr
184+
argument*: argument
185+
178186
argument:
179187
modifier*: modifier
180188
name_node?: identifier

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,28 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
729729
=>
730730
(argument name_node: (identifier #{lbl})? value: {val})
731731
),
732+
// An additional labeled trailing closure, such as the `c: { ... }` in
733+
// `foo { 42 } c: { ... }`, is turned into an argument to the function.
734+
rule!(
735+
(multipleTrailingClosureElement label: @@label closure: @closure)
736+
=>
737+
(argument name_node: (identifier #{label}) value: {closure})
738+
),
739+
rule!(
740+
(macroExpansionExpr
741+
macroName: @@name
742+
genericArgumentClause: (genericArgumentClause arguments: (genericArgument argument: @type_args)*)?
743+
arguments: _* @args
744+
trailingClosure: _? @trailing
745+
additionalTrailingClosures: _* @additional)
746+
=>
747+
(macro_call_expr
748+
macro_name_node: (identifier #{name})
749+
type_argument: {type_args}
750+
argument: {args}
751+
argument: {trailing.map(|trailing| tree!((argument value: {trailing})))}
752+
argument: {additional})
753+
),
732754
// Member access (`list.append`). The `declName` is itself a
733755
// `declReferenceExpr`; pull its `baseName` out as the member identifier.
734756
// A leading-dot access (`.foo`) has no explicit base — the base is an
@@ -1216,10 +1238,6 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
12161238
}
12171239
}
12181240
),
1219-
// Selector expression: `#selector(inner)` -- not yet supported
1220-
// (swift-syntax represents `#selector`/`#keyPath` and other macro
1221-
// expansions uniformly as a `macroExpansionExpr`).
1222-
rule!((macroExpansionExpr) => (unsupported_node)),
12231241
// A nominal type's `inheritanceClause` (`: Base, Proto`) becomes a list
12241242
// of `base_type`s, one per inherited type. Each declaration keyword
12251243
// gets its own rule; the bodies are identical but for the keyword.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#expect(value == 42)
2+
3+
#custom<Int>(value) {
4+
value
5+
} completion: {
6+
value
7+
}
8+
9+
#Preview {
10+
let previewValue = 42
11+
previewValue
12+
}
13+
14+
---
15+
16+
sourceFile
17+
endOfFileToken: endOfFile
18+
statements:
19+
codeBlockItem
20+
item:
21+
macroExpansionExpr
22+
leftParen: (
23+
rightParen: )
24+
arguments:
25+
labeledExpr
26+
expression:
27+
infixOperatorExpr
28+
operator:
29+
binaryOperatorExpr
30+
operator: binaryOperator "=="
31+
leftOperand:
32+
declReferenceExpr
33+
baseName: identifier "value"
34+
rightOperand:
35+
integerLiteralExpr
36+
literal: integerLiteral "42"
37+
additionalTrailingClosures:
38+
macroName: identifier "expect"
39+
pound: #
40+
codeBlockItem
41+
item:
42+
macroExpansionExpr
43+
leftParen: (
44+
rightParen: )
45+
arguments:
46+
labeledExpr
47+
expression:
48+
declReferenceExpr
49+
baseName: identifier "value"
50+
additionalTrailingClosures:
51+
multipleTrailingClosureElement
52+
colon: :
53+
label: identifier "completion"
54+
closure:
55+
closureExpr
56+
leftBrace: {
57+
rightBrace: }
58+
statements:
59+
codeBlockItem
60+
item:
61+
declReferenceExpr
62+
baseName: identifier "value"
63+
trailingClosure:
64+
closureExpr
65+
leftBrace: {
66+
rightBrace: }
67+
statements:
68+
codeBlockItem
69+
item:
70+
declReferenceExpr
71+
baseName: identifier "value"
72+
genericArgumentClause:
73+
genericArgumentClause
74+
arguments:
75+
genericArgument
76+
argument:
77+
identifierType
78+
name: identifier "Int"
79+
leftAngle: <
80+
rightAngle: >
81+
macroName: identifier "custom"
82+
pound: #
83+
codeBlockItem
84+
item:
85+
macroExpansionExpr
86+
arguments:
87+
additionalTrailingClosures:
88+
trailingClosure:
89+
closureExpr
90+
leftBrace: {
91+
rightBrace: }
92+
statements:
93+
codeBlockItem
94+
item:
95+
variableDecl
96+
attributes:
97+
modifiers:
98+
bindingSpecifier: let
99+
bindings:
100+
patternBinding
101+
initializer:
102+
initializerClause
103+
equal: =
104+
value:
105+
integerLiteralExpr
106+
literal: integerLiteral "42"
107+
pattern:
108+
identifierPattern
109+
identifier: identifier "previewValue"
110+
codeBlockItem
111+
item:
112+
declReferenceExpr
113+
baseName: identifier "previewValue"
114+
macroName: identifier "Preview"
115+
pound: #
116+
117+
---
118+
119+
top_level source="⟨body⟩"
120+
body:
121+
block source="⟨stmt⟩\n\n⟨stmt⟩\n\n⟨stmt⟩"
122+
stmt:
123+
macro_call_expr source="#⟨macro_name_node⟩(⟨argument⟩)"
124+
macro_name_node: identifier "expect" source="expect"
125+
argument:
126+
argument source="⟨value⟩"
127+
value:
128+
binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩"
129+
left: identifier "value" source="value"
130+
operator: infix_operator "==" source="=="
131+
right: int_literal "42" source="42"
132+
macro_call_expr source="#⟨macro_name_node⟩<⟨type_argument⟩>(⟨argument⟩) ⟨argument⟩ ⟨argument⟩"
133+
macro_name_node: identifier "custom" source="custom"
134+
type_argument: identifier "Int" source="Int"
135+
argument:
136+
argument source="⟨value⟩"
137+
value: identifier "value" source="value"
138+
argument source="⟨value⟩"
139+
value:
140+
function_expr source="{\n ⟨body⟩\n}"
141+
body:
142+
block source="⟨stmt⟩"
143+
stmt: identifier "value" source="value"
144+
argument source="⟨name_node⟩: ⟨value⟩"
145+
name_node: identifier "completion" source="completion"
146+
value:
147+
function_expr source="{\n ⟨body⟩\n}"
148+
body:
149+
block source="⟨stmt⟩"
150+
stmt: identifier "value" source="value"
151+
macro_call_expr source="#⟨macro_name_node⟩ ⟨argument⟩"
152+
macro_name_node: identifier "Preview" source="Preview"
153+
argument:
154+
argument source="⟨value⟩"
155+
value:
156+
function_expr source="{\n ⟨body⟩\n}"
157+
body:
158+
block source="⟨stmt⟩\n ⟨stmt⟩"
159+
stmt:
160+
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
161+
modifier: modifier "let" source="let"
162+
pattern: identifier "previewValue" source="previewValue"
163+
value: int_literal "42" source="42"
164+
identifier "previewValue" source="previewValue"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#expect(value == 42)
2+
3+
#custom<Int>(value) {
4+
value
5+
} completion: {
6+
value
7+
}
8+
9+
#Preview {
10+
let previewValue = 42
11+
previewValue
12+
}

‎unified/extractor/tests/corpus/swift/literals/line-magic-literal.output‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ top_level source="⟨body⟩"
3535
variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
3636
modifier: modifier "let" source="let"
3737
pattern: identifier "currentLine" source="currentLine"
38-
value: unsupported_node "#line" source="#line"
38+
value:
39+
macro_call_expr source="#⟨macro_name_node⟩"
40+
macro_name_node: identifier "line" source="line"

‎unified/ql/lib/codeql/unified/internal/Ast.qll‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,34 @@ module Unified {
964964
}
965965
}
966966

967+
/** A class representing `macro_call_expr` nodes. */
968+
class MacroCallExpr extends @unified_macro_call_expr, F::Expr {
969+
/** Gets the name of the primary QL class for this element. */
970+
final override string getAPrimaryQlClass() { result = "MacroCallExpr" }
971+
972+
/** Gets the node corresponding to the field `argument`. */
973+
final F::Argument getArgument(int i) { unified_macro_call_expr_argument(this, i, result) }
974+
975+
/** Gets the node corresponding to the field `argument`. */
976+
final F::Argument getAnArgument() { result = this.getArgument(_) }
977+
978+
/** Gets the node corresponding to the field `macro_name_node`. */
979+
final F::Identifier getMacroNameNode() { unified_macro_call_expr_def(this, result) }
980+
981+
/** Gets the node corresponding to the field `type_argument`. */
982+
final F::Expr getTypeArgument(int i) { unified_macro_call_expr_type_argument(this, i, result) }
983+
984+
/** Gets the node corresponding to the field `type_argument`. */
985+
final F::Expr getATypeArgument() { result = this.getTypeArgument(_) }
986+
987+
/** Gets a field or child node of this node. */
988+
final override F::AstNode getAFieldOrChild() {
989+
unified_macro_call_expr_argument(this, _, result) or
990+
unified_macro_call_expr_def(this, result) or
991+
unified_macro_call_expr_type_argument(this, _, result)
992+
}
993+
}
994+
967995
/** A class representing `map_literal` nodes. */
968996
class MapLiteral extends @unified_map_literal, F::Expr {
969997
/** Gets the name of the primary QL class for this element. */
@@ -1725,6 +1753,12 @@ module Unified {
17251753
or
17261754
result = node.(LabeledStmt).getStmt() and i = -1 and name = "getStmt"
17271755
or
1756+
result = node.(MacroCallExpr).getArgument(i) and name = "getArgument"
1757+
or
1758+
result = node.(MacroCallExpr).getMacroNameNode() and i = -1 and name = "getMacroNameNode"
1759+
or
1760+
result = node.(MacroCallExpr).getTypeArgument(i) and name = "getTypeArgument"
1761+
or
17281762
result = node.(MapLiteral).getElement(i) and name = "getElement"
17291763
or
17301764
result = node.(MemberAccessExpr).getBase() and i = -1 and name = "getBase"
@@ -1946,6 +1980,8 @@ module UnifiedFinal {
19461980

19471981
final class LabeledStmt = F::LabeledStmt;
19481982

1983+
final class MacroCallExpr = F::MacroCallExpr;
1984+
19491985
final class MapLiteral = F::MapLiteral;
19501986

19511987
final class Member = F::Member;

‎unified/ql/lib/unified.dbscheme‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ unified_equality_type_constraint_def(
440440
int right: @unified_expr ref
441441
);
442442

443-
@unified_expr = @unified_array_literal | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_ignore_pattern | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unhandled_node | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence
443+
@unified_expr = @unified_array_literal | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_conditional_pattern | @unified_continue_expr | @unified_expr_pattern | @unified_function_expr | @unified_generic_type_expr | @unified_if_expr | @unified_key_value_pair | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_or_pattern | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_identifier | @unified_token_ignore_pattern | @unified_token_inferred_type_expr | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unhandled_node | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence
444444

445445
@unified_expr_or_operator = @unified_expr | @unified_token_infix_operator
446446

@@ -631,6 +631,25 @@ unified_labeled_stmt_def(
631631
int stmt: @unified_stmt ref
632632
);
633633

634+
#keyset[unified_macro_call_expr, index]
635+
unified_macro_call_expr_argument(
636+
int unified_macro_call_expr: @unified_macro_call_expr ref,
637+
int index: int ref,
638+
unique int argument: @unified_argument ref
639+
);
640+
641+
#keyset[unified_macro_call_expr, index]
642+
unified_macro_call_expr_type_argument(
643+
int unified_macro_call_expr: @unified_macro_call_expr ref,
644+
int index: int ref,
645+
unique int type_argument: @unified_expr ref
646+
);
647+
648+
unified_macro_call_expr_def(
649+
unique int id: @unified_macro_call_expr,
650+
int macro_name_node: @unified_token_identifier ref
651+
);
652+
634653
#keyset[unified_map_literal, index]
635654
unified_map_literal_element(
636655
int unified_map_literal: @unified_map_literal ref,
@@ -1006,7 +1025,7 @@ unified_trivia_tokeninfo(
10061025
string value: string ref
10071026
);
10081027

1009-
@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_defer_stmt | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt
1028+
@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_conditional_pattern | @unified_constructor_declaration | @unified_continue_expr | @unified_defer_stmt | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_macro_call_expr | @unified_map_literal | @unified_member_access_expr | @unified_named_pattern | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_guard_expr | @unified_return_expr | @unified_string_interpolation_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt
10101029

10111030
unified_ast_node_location(
10121031
unique int node: @unified_ast_node ref,

0 commit comments

Comments
 (0)