Skip to content

Commit 0d845c2

Browse files
committed
unified/swift: Propagate parameter default values via context
Extends the context with a field for keeping track of the default value. In the process, we also rename the context to SwiftContext as it now doesn't only concern itself with properties.
1 parent 6d138c2 commit 0d845c2

1 file changed

Lines changed: 36 additions & 28 deletions

File tree

  • unified/extractor/src/languages/swift

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

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
use codeql_extractor::extractor::simple;
22
use yeast::{manual_rule, rule, tree, ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule};
33

4-
/// User context propagated from outer `property_binding` rules down to the
5-
/// inner accessor-translation rules so that every `accessor_declaration`
6-
/// emitted by an inner rule is born with the property's `name` (and
7-
/// optionally its `type`) already set — no schema-invalid intermediate
8-
/// state requiring post-hoc mutation.
4+
/// User context propagated from outer rules down to the inner rules that
5+
/// emit the corresponding output declarations, so that each emitted node
6+
/// is born with the outer information (name, type, modifiers, etc.)
7+
/// already set — no schema-invalid intermediate state requiring
8+
/// post-hoc mutation.
99
#[derive(Clone, Default)]
10-
struct PropertyContext {
11-
/// Identifier node for the property name, to be used as the
12-
/// `accessor_declaration.name`. Set by the outer property_binding rule
13-
/// before translating accessor children.
10+
struct SwiftContext {
11+
/// Identifier node for the property name. Set by the outer
12+
/// `property_binding` (computed accessors / willSet-didSet) rule
13+
/// before translating accessor children; read by
14+
/// `computed_getter`/`computed_setter`/`computed_modify`/
15+
/// `willset_clause`/`didset_clause`.
1416
property_name: Option<yeast::Id>,
15-
/// Translated type node for the property type, to be used as the
16-
/// `accessor_declaration.type`. Set by the outer property_binding rule
17-
/// when present.
17+
/// Translated type node for the property type. Set by the outer
18+
/// `property_binding` rule (computed accessors variant) when
19+
/// present; read by `computed_*` rules.
1820
property_type: Option<yeast::Id>,
21+
/// Default-value expression for the next translated `parameter`. Set
22+
/// by the outer `function_parameter` rule; read by the `parameter`
23+
/// rules.
24+
default_value: Option<yeast::Id>,
1925
}
2026

21-
fn translation_rules() -> Vec<Rule<PropertyContext>> {
27+
fn translation_rules() -> Vec<Rule<SwiftContext>> {
2228
vec![
2329
// ---- Top-level ----
2430
// Capture all top-level statements, including unnamed tokens like `nil`.
@@ -358,47 +364,49 @@ fn translation_rules() -> Vec<Rule<PropertyContext>> {
358364
body: (block stmt: {..body_stmts}))
359365
),
360366
// Parameters are wrapped in function_parameter, which also carries
361-
// optional default values.
362-
rule!(
367+
// optional default values. Publishes the default value into `ctx`
368+
// before translating the inner `parameter` so the `parameter`
369+
// rules can include it as a `default:` field directly.
370+
manual_rule!(
363371
(function_parameter parameter: @p default_value: _? @def)
364-
=>
365-
{..{
366-
let p_id: usize = p.into();
367-
for &d in def.iter().rev() {
368-
ctx.prepend_field(p_id, "default", d.into());
369-
}
370-
vec![p_id]
371-
}}
372+
{
373+
ctx.default_value = ctx.translate_opt(def)?;
374+
ctx.translate(p)
375+
}
372376
),
373377
// Parameter with external name and type
374378
rule!(
375379
(parameter external_name: @ext name: @name)
376380
=>
377381
(parameter
378382
external_name: (identifier #{ext})
379-
pattern: (name_pattern identifier: (identifier #{name})))
383+
pattern: (name_pattern identifier: (identifier #{name}))
384+
default: {..ctx.default_value})
380385
),
381386
rule!(
382387
(parameter external_name: @ext name: @name type: @ty)
383388
=>
384389
(parameter
385390
external_name: (identifier #{ext})
386391
pattern: (name_pattern identifier: (identifier #{name}))
387-
type: {ty})
392+
type: {ty}
393+
default: {..ctx.default_value})
388394
),
389395
// Parameter with just name and type (no external name)
390396
rule!(
391397
(parameter name: @name)
392398
=>
393399
(parameter
394-
pattern: (name_pattern identifier: (identifier #{name})))
400+
pattern: (name_pattern identifier: (identifier #{name}))
401+
default: {..ctx.default_value})
395402
),
396403
rule!(
397404
(parameter name: @name type: @ty)
398405
=>
399406
(parameter
400407
pattern: (name_pattern identifier: (identifier #{name}))
401-
type: {ty})
408+
type: {ty}
409+
default: {..ctx.default_value})
402410
),
403411
// Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels.
404412
// We don't want downstream QL to try to handle this as a call_expr with a weird argument, so explicitly mark it as unsupported for now.
@@ -1017,7 +1025,7 @@ fn translation_rules() -> Vec<Rule<PropertyContext>> {
10171025

10181026
pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec {
10191027
let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into();
1020-
let config = DesugaringConfig::<PropertyContext>::new()
1028+
let config = DesugaringConfig::<SwiftContext>::new()
10211029
.add_phase("translate", PhaseKind::OneShot, translation_rules())
10221030
.with_output_node_types_yaml(desugared_ast_schema);
10231031
let desugarer = ConcreteDesugarer::new(ts_language.clone(), config)

0 commit comments

Comments
 (0)