mirror of
https://github.com/github/codeql.git
synced 2026-07-29 23:00:09 +02:00
unified: Port variable-binding rules to swift-syntax
Retarget `let`/`var` bindings to the swift-syntax AST, preserving the output: - A `variableDecl` publishes its `bindingSpecifier` (`let`/`var`) as the binding modifier, followed by its attributes and modifiers (`@objc`, `public`, `static`, …), and flattens each `patternBinding` into its own `variable_declaration`, tagging non-first ones `chained_declaration`. - One `patternBinding` rule with optional `typeAnnotation`/`initializer` covers `let x`, `let x = e`, `let x: T`, and `let x: T = e`. - `identifierPattern` -> `name_pattern`; `tuplePattern` / `tuplePatternElement` -> `tuple_pattern` / `pattern_element` (tuple destructuring), carrying an optional element label through as the `pattern_element` key. - `codeBlockItem` now captures `_*` / annotates `stmt*` so a multi-binding declaration splices as several statements. - Add a `declModifier` -> `modifier` rule (swift-syntax unifies the visibility/function/member/mutation/ownership modifiers into one kind). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -144,7 +144,11 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
=>
|
||||
(top_level body: (block stmt: {items}))
|
||||
),
|
||||
rule!((codeBlockItem item: @item) => stmt { item }),
|
||||
// `codeBlockItem` wraps a top-level statement. It is a simple unwrapper,
|
||||
// but a single wrapped `variableDecl` can translate to *several*
|
||||
// declarations (`let x = 1, y = 2`), so the wrapped node is captured with
|
||||
// `_*` and the result annotated `stmt*` to splice all of them.
|
||||
rule!((codeBlockItem item: _* @item) => stmt* { item }),
|
||||
// ---- Literals ----
|
||||
// swift-syntax does not distinguish the lexical integer/string forms
|
||||
// (hex/binary/octal, single- vs multi-line, raw): each is a single
|
||||
@@ -328,18 +332,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
result
|
||||
}
|
||||
),
|
||||
// property_binding with any pattern name (identifier or
|
||||
// destructuring). Reads outer modifiers / chained tag from `ctx`.
|
||||
//
|
||||
// The enclosing `property_declaration` leads `ctx.outer_modifiers`
|
||||
// with the `let`/`var` binding modifier, so the auto-translated name
|
||||
// pattern (the LHS) becomes a binding, while the initializer value is
|
||||
// translated with a reset context (see `SwiftContext::reset`).
|
||||
// The individual bindings of a `variableDecl`. The binding modifier and
|
||||
// chained tag come from `ctx` (set by the `variableDecl` rule below). The
|
||||
// type annotation and initializer are both optional (one combined rule
|
||||
// covers `let x`, `let x = e`, `let x: T`, and `let x: T = e`); the
|
||||
// initializer value is translated in a reset scope so it is not treated
|
||||
// as a binding.
|
||||
rule!(
|
||||
(property_binding
|
||||
name: @pattern
|
||||
type: _? @ty
|
||||
value: _? @@val)
|
||||
(patternBinding
|
||||
pattern: @pattern
|
||||
typeAnnotation: (typeAnnotation type: @ty)?
|
||||
initializer: (initializerClause value: @@val)?)
|
||||
=>
|
||||
(variable_declaration
|
||||
modifier: {ctx.outer_modifiers.clone()}
|
||||
@@ -348,34 +351,28 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
type: {ty}
|
||||
value: {ctx.reset(); ctx.translate(val)?})
|
||||
),
|
||||
// property_declaration: flatten declarators (each may translate
|
||||
// to multiple nodes — variable_declaration and/or
|
||||
// accessor_declaration) and attach the binding modifier
|
||||
// (let/var), outer modifiers, and `chained_declaration` for
|
||||
// non-first declarations. Manual rule: publishes
|
||||
// binding/outer modifiers into `ctx` and translates each
|
||||
// declarator with `ctx.is_chained` toggled per iteration. The
|
||||
// inner declaration rules (`property_binding` variants,
|
||||
// accessor inner rules) read these fields and emit complete
|
||||
// `modifier:` lists from the start.
|
||||
// A `let`/`var` declaration binds one or more comma-separated patterns
|
||||
// (`let x = 1, y = 2`). The `bindingSpecifier` (`let`/`var`) is published
|
||||
// as the binding modifier, followed by any attributes and modifiers
|
||||
// (`@objc`, `public`, `static`, …); each `patternBinding` becomes its own
|
||||
// `variable_declaration`, with non-first ones tagged `chained_declaration`.
|
||||
// Accessor/observer forms are handled by the earlier rules.
|
||||
rule!(
|
||||
(property_declaration
|
||||
binding: (value_binding_pattern mutability: @@binding_kind)
|
||||
declarator: _* @@decls
|
||||
(modifiers)* @mods)
|
||||
(variableDecl
|
||||
attributes: _* @attrs
|
||||
modifiers: _* @mods
|
||||
bindingSpecifier: @@spec
|
||||
bindings: _* @@bindings)
|
||||
=>
|
||||
member* {
|
||||
let binding_text = ctx.ast.source_text(binding_kind);
|
||||
let binding = ctx.literal("modifier", &binding_text);
|
||||
// The `let`/`var` binding modifier leads the declaration's
|
||||
// modifier list and doubles as the "this is a binding" signal
|
||||
// for pattern translation (see `in_binding_pattern`).
|
||||
ctx.outer_modifiers = std::iter::once(binding).chain(mods).collect();
|
||||
|
||||
stmt* {
|
||||
let binding = tree!((modifier #{spec}));
|
||||
// The binding (`let`/`var`) leads, then attributes then modifiers
|
||||
// in source order (Swift writes attributes before modifiers).
|
||||
ctx.outer_modifiers = std::iter::once(binding).chain(attrs).chain(mods).collect();
|
||||
let mut result = Vec::new();
|
||||
for (i, decl) in decls.into_iter().enumerate() {
|
||||
for (i, b) in bindings.into_iter().enumerate() {
|
||||
ctx.is_chained = i > 0;
|
||||
result.extend(ctx.translate(decl)?);
|
||||
result.extend(ctx.translate(b)?);
|
||||
}
|
||||
result
|
||||
}
|
||||
@@ -451,9 +448,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
),
|
||||
// Unwrap `type` wrapper node
|
||||
rule!((type name: @inner) => type_expr { inner }),
|
||||
// Pattern with bound_identifier → name_pattern.
|
||||
// `identifierPattern` wraps a single identifier token.
|
||||
rule!(
|
||||
(pattern bound_identifier: @name)
|
||||
(identifierPattern identifier: @name)
|
||||
=>
|
||||
(name_pattern identifier: (identifier #{name}))
|
||||
),
|
||||
@@ -485,10 +482,15 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
constructor: (member_access_expr base: (inferred_type_expr #{dot}) member: (identifier #{name}))
|
||||
element: {items})
|
||||
),
|
||||
// Tuple pattern and its (optionally named) items
|
||||
rule!((pattern kind: (tuple_pattern item: _* @elems)) => (tuple_pattern element: {elems})),
|
||||
rule!((tuple_pattern_item name: @key pattern: @pat) => (pattern_element key: (identifier #{key}) pattern: {pat})),
|
||||
rule!((tuple_pattern_item pattern: @pat) => (pattern_element pattern: {pat})),
|
||||
// A tuple destructuring pattern (`let (a, b) = …`). A labelled element
|
||||
// (`let (x: a) = …`) carries its label through as the `pattern_element`
|
||||
// key; unlabelled elements have no key.
|
||||
rule!((tuplePattern elements: _* @els) => (tuple_pattern element: {els})),
|
||||
rule!(
|
||||
(tuplePatternElement label: _? @label pattern: @p)
|
||||
=>
|
||||
(pattern_element key: {label.map(|l| tree!((identifier #{l})))} pattern: {p})
|
||||
),
|
||||
// Type casting pattern (TODO)
|
||||
rule!((pattern kind: (type_casting_pattern)) => (unsupported_node)),
|
||||
// Wildcard pattern
|
||||
@@ -906,6 +908,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// Modifiers — unwrap to individual modifier children
|
||||
rule!((modifiers _* @mods) => modifier* { mods }),
|
||||
rule!((attribute) @m => (modifier #{m})),
|
||||
// swift-syntax models every access/function/member/mutation/ownership
|
||||
// modifier as a single `declModifier`; its source text is the modifier.
|
||||
rule!((declModifier) @m => (modifier #{m})),
|
||||
rule!((visibility_modifier) @m => (modifier #{m})),
|
||||
rule!((function_modifier) @m => (modifier #{m})),
|
||||
rule!((member_modifier) @m => (modifier #{m})),
|
||||
|
||||
Reference in New Issue
Block a user