From 0d845c2ea9046bf3cf5d14d0f4b29cba7fdea4e3 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 24 Jun 2026 22:07:05 +0000 Subject: [PATCH] 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. --- .../extractor/src/languages/swift/swift.rs | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 3f9b3b371fe..5eb74cf99ce 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,24 +1,30 @@ use codeql_extractor::extractor::simple; use yeast::{manual_rule, rule, tree, ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule}; -/// User context propagated from outer `property_binding` rules down to the -/// inner accessor-translation rules so that every `accessor_declaration` -/// emitted by an inner rule is born with the property's `name` (and -/// optionally its `type`) already set — no schema-invalid intermediate -/// state requiring post-hoc mutation. +/// User context propagated from outer rules down to the inner rules that +/// emit the corresponding output declarations, so that each emitted node +/// is born with the outer information (name, type, modifiers, etc.) +/// already set — no schema-invalid intermediate state requiring +/// post-hoc mutation. #[derive(Clone, Default)] -struct PropertyContext { - /// Identifier node for the property name, to be used as the - /// `accessor_declaration.name`. Set by the outer property_binding rule - /// before translating accessor children. +struct SwiftContext { + /// Identifier node for the property name. Set by the outer + /// `property_binding` (computed accessors / willSet-didSet) rule + /// before translating accessor children; read by + /// `computed_getter`/`computed_setter`/`computed_modify`/ + /// `willset_clause`/`didset_clause`. property_name: Option, - /// Translated type node for the property type, to be used as the - /// `accessor_declaration.type`. Set by the outer property_binding rule - /// when present. + /// Translated type node for the property type. Set by the outer + /// `property_binding` rule (computed accessors variant) when + /// present; read by `computed_*` rules. property_type: Option, + /// Default-value expression for the next translated `parameter`. Set + /// by the outer `function_parameter` rule; read by the `parameter` + /// rules. + default_value: Option, } -fn translation_rules() -> Vec> { +fn translation_rules() -> Vec> { vec![ // ---- Top-level ---- // Capture all top-level statements, including unnamed tokens like `nil`. @@ -358,17 +364,15 @@ fn translation_rules() -> Vec> { body: (block stmt: {..body_stmts})) ), // Parameters are wrapped in function_parameter, which also carries - // optional default values. - rule!( + // optional default values. Publishes the default value into `ctx` + // before translating the inner `parameter` so the `parameter` + // rules can include it as a `default:` field directly. + manual_rule!( (function_parameter parameter: @p default_value: _? @def) - => - {..{ - let p_id: usize = p.into(); - for &d in def.iter().rev() { - ctx.prepend_field(p_id, "default", d.into()); - } - vec![p_id] - }} + { + ctx.default_value = ctx.translate_opt(def)?; + ctx.translate(p) + } ), // Parameter with external name and type rule!( @@ -376,7 +380,8 @@ fn translation_rules() -> Vec> { => (parameter external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name}))) + pattern: (name_pattern identifier: (identifier #{name})) + default: {..ctx.default_value}) ), rule!( (parameter external_name: @ext name: @name type: @ty) @@ -384,21 +389,24 @@ fn translation_rules() -> Vec> { (parameter external_name: (identifier #{ext}) pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) + type: {ty} + default: {..ctx.default_value}) ), // Parameter with just name and type (no external name) rule!( (parameter name: @name) => (parameter - pattern: (name_pattern identifier: (identifier #{name}))) + pattern: (name_pattern identifier: (identifier #{name})) + default: {..ctx.default_value}) ), rule!( (parameter name: @name type: @ty) => (parameter pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) + type: {ty} + default: {..ctx.default_value}) ), // Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels. // 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> { pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec { let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); - let config = DesugaringConfig::::new() + let config = DesugaringConfig::::new() .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); let desugarer = ConcreteDesugarer::new(ts_language.clone(), config)