From bc1b012984e077b4b22e809101601000407c1679 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 11 Sep 2026 13:20:54 +0000 Subject: [PATCH 01/14] yeast: Track child source ranges in separate contexts NB: This temporarily changes the test output for bulk imports, blocks, and things like synthesised Array and Option literals. Later commits will fix these up again. --- shared/yeast-macros/src/parse.rs | 1 + shared/yeast/doc/yeast.md | 21 +++ shared/yeast/src/build.rs | 101 +++++++++-- shared/yeast/src/lib.rs | 32 +++- shared/yeast/tests/test.rs | 170 +++++++++++++++++- unified/extractor/BUILD.bazel | 5 + .../extractor/src/languages/swift/swift.rs | 10 +- .../closures/closure-with-capture-list.output | 4 +- .../closure-with-explicit-parameters.output | 4 +- .../closure-with-shorthand-parameters.output | 4 +- .../closures/multi-statement-closure.output | 4 +- .../swift/closures/trailing-closure.output | 8 +- .../empty-array-literal-with-type.output | 4 +- ...g-modifier-does-not-leak-to-sibling.output | 8 +- .../swift/control-flow/defer-statement.output | 4 +- .../control-flow/discard-statement.output | 8 +- .../swift/control-flow/fallthrough.output | 12 +- .../swift/control-flow/guard-let.output | 14 +- .../if-let-optional-binding.output | 14 +- .../nested-enum-case-pattern.output | 16 +- .../switch-case-item-where-clauses.output | 14 +- .../switch-expression-pattern.output | 44 ++--- .../control-flow/switch-statement.output | 14 +- .../switch-with-binding-pattern.output | 8 +- ...with-labeled-case-pattern-arguments.output | 8 +- ...with-deeply-nested-path-three-parts.output | 6 +- .../import-with-dotted-path-two-parts.output | 6 +- .../simple-import-with-single-name.output | 6 +- .../expressions/array-type-constructor.output | 18 +- .../expressions/array-type-metatype.output | 6 +- .../swift/expressions/super-expression.output | 12 +- .../expressions/unsafe-expression.output | 4 +- ...nction-with-default-parameter-value.output | 4 +- .../function-with-inout-parameter.output | 4 +- .../function-with-named-parameters.output | 4 +- .../function-with-no-parameters.output | 4 +- ...ion-with-parameters-and-return-type.output | 4 +- .../swift/functions/generic-function.output | 4 +- .../swift/functions/variadic-function.output | 4 +- .../literals/string-with-interpolation.output | 36 ++-- ...solved-operator-sequence-with-casts.output | 4 +- ...lved-operator-sequence-with-ternary.output | 4 +- .../unresolved-operator-sequence.output | 4 +- .../catch-where-clauses.output | 8 +- .../optionals-and-errors/do-catch.output | 4 +- .../optionals-and-errors/force-unwrap.output | 4 +- .../optional-enum-case-binding.output | 10 +- .../optional-type-annotation.output | 4 +- .../throwing-function.output | 4 +- .../try-expression-2.output | 4 +- .../try-expression.output | 4 +- ...er-does-not-leak-into-accessor-body.output | 12 +- .../corpus/swift/types/class-function.output | 4 +- .../swift/types/class-inheritance.output | 4 +- .../swift/types/class-with-initializer.output | 4 +- .../swift/types/class-with-method.output | 4 +- .../class-with-multiple-base-types.output | 6 +- .../swift/types/computed-property.output | 6 +- .../types/constructor-with-parameters.output | 4 +- .../types/enum-with-associated-values.output | 16 +- .../corpus/swift/types/enum-with-cases.output | 16 +- ...separated-cases-chained-declaration.output | 22 +-- .../tests/corpus/swift/types/extension.output | 4 +- ...tion-type-with-convention-attribute.output | 4 +- ...nction-type-with-sendable-attribute.output | 4 +- .../swift/types/noncopyable-type.output | 4 +- .../property-with-getter-and-setter.output | 4 +- .../swift/types/protocol-declaration.output | 8 +- ...nd-read-write-property-requirements.output | 4 +- .../corpus/swift/types/static-function.output | 4 +- ...fier-does-not-leak-into-initializer.output | 8 +- .../multiple-bindings-on-one-line.output | 4 +- ...y-with-willset-and-didset-observers.output | 8 +- unified/extractor/tests/location_tests.rs | 100 +++++++++++ 74 files changed, 666 insertions(+), 296 deletions(-) create mode 100644 unified/extractor/tests/location_tests.rs diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index c81febe7a649..5ab3f80fa162 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -987,6 +987,7 @@ pub fn parse_rule_top(input: TokenStream) -> Result { #(#translated_bindings)* let mut #ctx_ident = yeast::build::BuildCtx::with_translator(__ast, &__captures, __fresh, __source_range, __user_ctx, __translator); let __result: Vec = { #transform_body }; + let __result = #ctx_ident.finish_rule(__result); Ok(__result) }), ) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index b586bed71435..b4ef1905b141 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -235,6 +235,27 @@ yeast::trees!(ctx, (identifier #{name}) // an identifier from a Rust variable ``` +### Source locations + +Captured nodes keep the locations assigned by their own translations. New +nodes in an output template derive their locations from their children. After +the transform completes, the matched input node's range is added only to +locally-created nodes returned as rule results: + +```rust +rule!( + (wrapper child: (_) @child) + => + (outer nested: (inner value: {child})) +) +``` + +Here `inner` derives its range from `child`, while the returned `outer` node +also includes the full `wrapper` range. This lets replacement roots include +elided keywords or delimiters without assigning the same broad range to every +synthetic descendant. A transform that simply returns a translated capture +does not widen that capture to the wrapper's range. + For reviewing locations, `DumpOptions::show_abridged_source` prints each node's source range with every direct child replaced by its field name in Unicode angle brackets. This keeps delimiters and other parent-owned syntax visible diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index f4f5ae5d18f3..7a15f77dc524 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -1,8 +1,8 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use crate::captures::Captures; use crate::tree_builder::FreshScope; -use crate::{Ast, FieldId, Id, NodeContent, Range, TranslatorHandle}; +use crate::{Ast, FieldId, Id, KindId, NodeContent, Range, TranslatorHandle}; /// Context for building new AST nodes during a transformation. /// @@ -33,13 +33,22 @@ pub struct BuildCtx<'a, C: 'a = ()> { pub ast: &'a mut Ast, pub captures: &'a Captures, pub fresh: &'a FreshScope, - /// Source range of the matched node, inherited by synthetic nodes. + /// Source range of the node matched by the current rule. + /// + /// The `rule!` macro applies this range to locally-created result roots + /// after the transform completes. Nested synthetic nodes derive their + /// ranges from their children. pub source_range: Option, /// User-supplied context, accessible directly via `ctx.field` (via Deref). pub user_ctx: &'a mut C, /// Optional translator handle, populated when the context is built by /// the framework's rule driver. None when the context is built by hand. pub(crate) translator: Option>, + /// Nodes built directly through this context without an explicit source + /// range in either their content or constructor argument. Recursive + /// translations use their own context and therefore do not contribute to + /// this list. + created_nodes: BTreeSet, } impl<'a, C> BuildCtx<'a, C> { @@ -56,9 +65,11 @@ impl<'a, C> BuildCtx<'a, C> { source_range: None, user_ctx, translator: None, + created_nodes: BTreeSet::new(), } } + /// Construct a context carrying a matched input source range. pub fn with_source_range( ast: &'a mut Ast, captures: &'a Captures, @@ -73,6 +84,7 @@ impl<'a, C> BuildCtx<'a, C> { source_range, user_ctx, translator: None, + created_nodes: BTreeSet::new(), } } @@ -93,7 +105,59 @@ impl<'a, C> BuildCtx<'a, C> { source_range, user_ctx, translator: Some(translator), + created_nodes: BTreeSet::new(), + } + } + + /// Create a node and record it as constructed by this rule invocation. + pub fn create_node_with_range( + &mut self, + kind: KindId, + content: NodeContent, + fields: BTreeMap>, + is_named: bool, + source_range: Option, + ) -> Id { + let has_explicit_source_range = + source_range.is_some() || matches!(&content, NodeContent::Range(_)); + let id = self + .ast + .create_node_with_range(kind, content, fields, is_named, source_range); + if !has_explicit_source_range { + self.created_nodes.insert(id); + } + id + } + + /// Create a named token and record it as constructed by this rule invocation. + pub fn create_named_token_with_range( + &mut self, + kind: &'static str, + content: String, + source_range: Option, + ) -> Id { + let has_explicit_source_range = source_range.is_some(); + let id = self + .ast + .create_named_token_with_range(kind, content, source_range); + if !has_explicit_source_range { + self.created_nodes.insert(id); } + id + } + + /// Finish the current rule invocation by applying the matched source range + /// to locally-created result roots. + #[doc(hidden)] + pub fn finish_rule(self, results: Vec) -> Vec { + if let Some(source_range) = self.source_range { + for &id in &results { + if self.created_nodes.contains(&id) { + self.ast.extend_source_range(id, source_range); + } + } + } + results } /// Look up a capture variable, returning its node Id. @@ -133,41 +197,34 @@ impl<'a, C> BuildCtx<'a, C> { .unwrap_or_else(|| panic!("build: field '{name}' not found")); field_map.entry(field_id).or_default().extend(ids); } - self.ast.create_node_with_range( + self.create_node_with_range( kind_id, NodeContent::DynamicString(String::new()), field_map, true, - self.source_range, + None, ) } /// Create a leaf node with a fixed string content. pub fn literal(&mut self, kind: &'static str, value: &str) -> Id { - self.ast - .create_named_token_with_range(kind, value.to_string(), self.source_range) + self.create_named_token_with_range(kind, value.to_string(), None) } - /// Create a leaf node with fixed content and an optional preferred source range. - /// If `source_range` is `None`, falls back to this context's inherited range. + /// Create a leaf node with fixed content and an optional source range. pub fn literal_with_source_range( &mut self, kind: &'static str, value: &str, source_range: Option, ) -> Id { - self.ast.create_named_token_with_range( - kind, - value.to_string(), - source_range.or(self.source_range), - ) + self.create_named_token_with_range(kind, value.to_string(), source_range) } /// Create a leaf node with an auto-generated unique name. pub fn fresh(&mut self, kind: &'static str, name: &str) -> Id { let generated = self.fresh.resolve(name); - self.ast - .create_named_token_with_range(kind, generated, self.source_range) + self.create_named_token_with_range(kind, generated, None) } } @@ -203,8 +260,9 @@ impl BuildCtx<'_, C> { /// Run `f` with a temporary child [`BuildCtx`] whose `user_ctx` is /// a fresh clone of the current one, sharing everything else - /// (`ast`, `captures`, `fresh`, `source_range`, `translator`) by - /// re-borrow. Any mutations `f` makes to the child's `user_ctx` + /// (`ast`, `captures`, `fresh`, source ranges, `translator`) by re-borrow. + /// Nodes constructed through the child remain part of the current rule + /// invocation. Any mutations `f` makes to the child's `user_ctx` /// are discarded when it returns — no restore needed, because the /// mutations only ever happened on a local clone. /// @@ -238,8 +296,13 @@ impl BuildCtx<'_, C> { source_range: self.source_range, user_ctx: &mut child_user_ctx, translator: self.translator, + created_nodes: BTreeSet::new(), }; - f(&mut child) + let result = f(&mut child); + let created_nodes = std::mem::take(&mut child.created_nodes); + drop(child); + self.created_nodes.extend(created_nodes); + result // child_user_ctx dropped; the outer `self` is unaffected. } } diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 76bfa58124d6..cae721db6586 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -128,9 +128,10 @@ pub trait YeastDisplay { /// Optional source range for values used in `#{expr}` interpolations. /// -/// By default this returns `None`, so synthesized leaves inherit the matched -/// rule's source range. `Id` returns the referenced node's range, letting -/// `(kind #{capture})` carry the captured node's location. +/// By default this returns `None`, so synthesized leaves use the current +/// [`crate::build::BuildCtx`] default range, if any. `Id` returns the +/// referenced node's range, letting `(kind #{capture})` carry the captured +/// node's location. pub trait YeastSourceRange { fn yeast_source_range(&self, ast: &Ast) -> Option; } @@ -592,8 +593,7 @@ impl Ast { // Parsed nodes already carry an exact source range in their content. NodeContent::Range(_) => source_range, // Synthesized nodes derive location from both their children and - // the inherited rule-match range, so tokens matched by a rule but - // elided from its output still contribute to the replacement range. + // any explicitly supplied source range. _ => self .union_source_range_of_children(&fields) .map_or(source_range, |child_range| { @@ -618,6 +618,24 @@ impl Ast { Id(id) } + /// Extend a synthetic node's source range to include `source_range`. + /// + /// Parsed nodes carry their exact range in [`NodeContent::Range`] and must + /// not be modified through this API. + pub fn extend_source_range(&mut self, id: Id, source_range: Range) { + let node = self + .nodes + .get_mut(id.0) + .unwrap_or_else(|| panic!("extend_source_range: invalid node id {}", id.0)); + if matches!(node.content, NodeContent::Range(_)) { + panic!("extend_source_range: cannot modify a parsed node"); + } + node.source_range = Some(match node.source_range { + Some(existing) => union_source_ranges(existing, source_range), + None => source_range, + }); + } + /// Register a named node kind, returning its id (idempotent). Lets callers /// build an AST in a single pass, registering kinds as nodes are created /// rather than pre-populating the schema. @@ -1134,8 +1152,8 @@ impl Rule { } } - /// Run this rule's transform with the given captures, using `node`'s - /// source range as the source range of the produced nodes. + /// Run this rule's transform with the given captures, making `node`'s + /// source range available to the transform. fn run_transform( &self, ast: &mut Ast, diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index e0abe51053d9..dbaee55beb22 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -1579,7 +1579,7 @@ fn test_hash_brace_renders_capture_source_text() { r#" program call - arguments: argument_list "foo.bar()" + arguments: argument_list method: identifier "bar" receiver: identifier "foo" "#, @@ -1674,6 +1674,174 @@ fn test_elided_tokens_contribute_to_replacement_location() { assert_eq!(call.end_byte(), 9); } +/// Nested nodes constructed by a rule derive their location from their own +/// children rather than inheriting the range of the rule's matched root. +#[test] +fn test_nested_synthetic_node_uses_child_location() { + let rule: Rule = rule!( + (call + method: (identifier) @name + receiver: (identifier) @recv + ) + => + (call + method: {name} + receiver: {recv} + arguments: (argument_list argument: {recv}) + ) + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + let call = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "call") + .expect("call exists"); + assert_eq!(call.byte_range(), 0..9); + + let arguments = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "argument_list") + .expect("argument list exists"); + assert_eq!(arguments.byte_range(), 0..3); +} + +/// A rule that only unwraps and returns a translated capture must not widen +/// that capture to the wrapper's source range. +#[test] +fn test_returned_capture_keeps_its_location() { + let rule: Rule = rule!( + (call method: (identifier) @name) + => + identifier { name } + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + let identifier = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "identifier") + .expect("identifier exists"); + assert_eq!(identifier.byte_range(), 4..7); +} + +/// Nodes allocated by an explicit recursive translation belong to that nested +/// rule invocation, even when the outer rule returns one directly. +#[test] +fn test_explicit_recursive_translation_keeps_nested_rule_location() { + let program: Rule = rule!( + (program (_)* @stmts) + => + (program stmt: {stmts}) + ); + let unwrap: Rule = rule!( + (call method: (identifier) @@name) + => + identifier { + ctx.translate(name)? + .into_iter() + .next() + .ok_or("identifier translation produced no result")? + } + ); + let translate_identifier: Rule = rule!((identifier) @@identifier => (identifier #{identifier})); + + let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); + let schema = + yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); + let phases = vec![Phase::new( + "translate", + PhaseKind::OneShot, + vec![program, unwrap, translate_identifier], + )]; + let runner: Runner = Runner::with_schema(lang, &schema, &phases); + let ast = runner.run("foo.bar()").unwrap(); + let identifier = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "identifier") + .expect("identifier exists"); + assert_eq!(identifier.byte_range(), 4..7); +} + +/// Explicit ranges on multiple results must not be widened to the range of the +/// input node matched by the rule. +#[test] +fn test_explicitly_located_multiple_results_keep_their_ranges() { + let rule: Rule = rule!( + (assignment + left: (identifier) @@left + right: (integer) @@right) + => + identifier* { + let left_text = ctx.source_text(left); + let right_text = ctx.source_text(right); + let left_range = left.yeast_source_range(&*ctx.ast); + let right_range = right.yeast_source_range(&*ctx.ast); + vec![ + ctx.literal_with_source_range("identifier", &left_text, left_range), + ctx.literal_with_source_range("identifier", &right_text, right_range), + ] + } + ); + + let ast = run_and_ast("x = 1", vec![rule]); + let mut ranges: Vec<_> = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| { + let node = ast.get_node(id)?; + (node.kind_name() == "identifier").then(|| (ast.source_text(id), node.byte_range())) + }) + .collect(); + ranges.sort_by_key(|(_, range)| range.start); + + assert_eq!( + ranges, + vec![("x".to_string(), 0..1), ("1".to_string(), 4..5)] + ); +} + +/// A range-backed node already carries an exact parsed range and must not be +/// finalized as a synthetic result. +#[test] +fn test_range_backed_result_keeps_its_range() { + use std::collections::BTreeMap; + + let rule: Rule = rule!( + (assignment left: (identifier) @@left) + => + identifier { + let range = left.yeast_source_range(&*ctx.ast).unwrap(); + let kind = ctx.ast.id_for_node_kind("identifier").unwrap(); + ctx.create_node_with_range( + kind, + NodeContent::Range(range), + BTreeMap::new(), + true, + None, + ) + } + ); + + let ast = run_and_ast("x = 1", vec![rule]); + let identifiers: Vec<_> = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| { + let node = ast.get_node(id)?; + (node.kind_name() == "identifier").then(|| (ast.source_text(id), node.byte_range())) + }) + .collect(); + + assert_eq!(identifiers, vec![("x".to_string(), 0..1)]); +} + // ---- `rules!` macro tests (compile-time type-checking) ---- /// `rules!` should accept well-typed rules using the bare-rule-body diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel index f8814c4572a1..26e815d49e8a 100644 --- a/unified/extractor/BUILD.bazel +++ b/unified/extractor/BUILD.bazel @@ -34,6 +34,11 @@ _TESTS = { "compile_data": [], "size": "medium", }, + "location_tests": { + "data": [], + "compile_data": [], + "size": "small", + }, # `include_str!`s a checked-in `parse_to_json` dump. "swift_syntax_pipeline": { "data": [], diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index ae7f42fa0f1e..4bcdce18595b 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -112,21 +112,15 @@ fn member_chain( ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, parts: Vec, ) -> yeast::Id { - // `member_chain` builds the imported expression inside the larger import - // declaration rule. The imported expression should span the import path, - // not the whole declaration including the `import` keyword. - let source_range = ctx.source_range.take(); let mut iter = parts.into_iter(); let first = iter .next() .expect("identifier with `part:` must have at least one part"); let init = tree!((identifier #{first})); - let result = iter.fold( + iter.fold( init, |acc, elem| tree!((member_access_expr base: {acc} member_name_node: (identifier #{elem}))), - ); - ctx.source_range = source_range; - result + ) } fn translation_rules() -> Vec> { diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output index 1e28176add2b..a2b19c5503a7 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output @@ -68,13 +68,13 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="⟨body⟩⟨capture_declaration⟩" + function_expr source="{ [⟨capture_declaration⟩] in ⟨body⟩ }" capture_declaration: variable_declaration source="⟨modifier⟩ ⟨pattern⟩" modifier: modifier "weak" source="weak" pattern: identifier "self" source="self" body: - block source="{ [weak self] in ⟨stmt⟩ }" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩()" callee: diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output index a44783d172d1..786e7d7fb4ee 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output @@ -70,14 +70,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="⟨body⟩⟨parameter⟩⟨return_type⟩" + function_expr source="{ (⟨parameter⟩) -> ⟨return_type⟩ in ⟨body⟩ }" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" return_type: identifier "Int" source="Int" body: - block source="{ (x: Int) -> Int in ⟨stmt⟩ }" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output index 6de0b9bea57c..3e30fac78c01 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output @@ -47,9 +47,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="⟨body⟩" + function_expr source="{ ⟨body⟩ }" body: - block source="{ ⟨stmt⟩ }" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "$0" source="$0" diff --git a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output index 36649bd5ac0d..f9c054aa0b96 100644 --- a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output @@ -101,14 +101,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="⟨body⟩⟨parameter⟩⟨return_type⟩" + function_expr source="{ (⟨parameter⟩) -> ⟨return_type⟩ in\n ⟨body⟩\n}" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" return_type: identifier "Int" source="Int" body: - block source="{ (x: Int) -> Int in\n ⟨stmt⟩\n ⟨stmt⟩\n}" + block source="⟨stmt⟩\n ⟨stmt⟩" stmt: variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" diff --git a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output index ad75555b1002..c50bbde02dcc 100644 --- a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output @@ -43,17 +43,17 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - call_expr source="⟨callee⟩⟨argument⟩" + call_expr source="⟨callee⟩ ⟨argument⟩" callee: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: identifier "xs" source="xs" member_name_node: identifier "map" source="map" argument: - argument source="xs.map ⟨value⟩" + argument source="⟨value⟩" value: - function_expr source="⟨body⟩" + function_expr source="{ ⟨body⟩ }" body: - block source="{ ⟨stmt⟩ }" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "$0" source="$0" diff --git a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output index 28958f323827..a8bd2282ef02 100644 --- a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output +++ b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output @@ -45,7 +45,7 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "xs" source="xs" type: - generic_type_expr source="⟨base⟩⟨type_argument⟩" - base: identifier "Array" source="[Int]" + generic_type_expr source="[⟨type_argument⟩]" + base: identifier "Array" source= type_argument: identifier "Int" source="Int" value: array_literal "[]" source="[]" diff --git a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output index f960f16a50f9..73c3312ea09e 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output +++ b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output @@ -95,17 +95,17 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n}" value: identifier "y" source="y" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: identifier "someConstant" source="someConstant" body: - block source="case someConstant:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"matched\"" source="\"matched\"" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: break_expr "break" source="break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output index 78f25fbd9551..ba856ea604f4 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output @@ -79,10 +79,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n}" name_node: identifier "withCleanup" source="withCleanup" body: - block source="func withCleanup() {\n ⟨stmt⟩\n ⟨stmt⟩\n}" + block source="⟨stmt⟩\n ⟨stmt⟩" stmt: unsupported_node "defer { print(\"cleanup\") }" source="defer { print(\"cleanup\") }" call_expr source="⟨callee⟩(⟨argument⟩)" diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output index b2c21eee642e..3e3a36d98330 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output @@ -67,16 +67,16 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩⟨base_type⟩⟨name_node⟩⟨member⟩" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩ {\n ⟨member⟩\n}" modifier: modifier "struct" source="struct" name_node: identifier "Resource" source="Resource" base_type: - base_type source="struct Resource: ⟨type⟩ {\n consuming func close() {\n discard self\n }\n}" + base_type source="⟨type⟩" type: unsupported_node "~Copyable" source="~Copyable" member: - function_declaration source="⟨modifier⟩⟨body⟩⟨name_node⟩" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {\n ⟨body⟩\n }" modifier: modifier "consuming" source="consuming" name_node: identifier "close" source="close" body: - block source="consuming func close() {\n ⟨stmt⟩\n }" + block source="⟨stmt⟩" stmt: unsupported_node "discard self" source="discard self" diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output index c5752060af62..03ed5d1acc38 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output @@ -86,7 +86,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "classify" source="classify" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -94,17 +94,17 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" body: - block source="func classify(_ x: Int) {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: switch_expr source="switch ⟨value⟩ {\n ⟨case⟩\n ⟨case⟩\n }" value: identifier "x" source="x" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: int_literal "1" source="1" body: - block source="case 1:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: unsupported_node "fallthrough" source="fallthrough" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: break_expr "break" source="break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index aefb475a5bde..9312e38adefc 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -42,18 +42,18 @@ top_level source="⟨body⟩" stmt: guard_if_stmt source="guard ⟨condition⟩ else ⟨else⟩" condition: - pattern_guard_expr source="⟨pattern⟩⟨value⟩" + pattern_guard_expr source="let ⟨pattern⟩ = ⟨value⟩" pattern: - call_expr source="⟨argument⟩⟨callee⟩" + call_expr source="⟨argument⟩" callee: - member_access_expr source="⟨base⟩⟨member_name_node⟩" - base: identifier "Optional" source="let value = optional" - member_name_node: identifier "some" source="let value = optional" + member_access_expr source= + base: identifier "Optional" source= + member_name_node: identifier "some" source= argument: argument source="⟨value⟩" value: - expr_pattern source="⟨modifier⟩⟨expr⟩" - modifier: modifier "let" source="let value = optional" + expr_pattern source="⟨expr⟩" + modifier: modifier "let" source= expr: identifier "value" source="value" value: identifier "optional" source="optional" else: diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index e878953ff7b4..09085763f268 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -55,18 +55,18 @@ top_level source="⟨body⟩" stmt: if_expr source="if ⟨condition⟩ ⟨then⟩" condition: - pattern_guard_expr source="⟨pattern⟩⟨value⟩" + pattern_guard_expr source="let ⟨pattern⟩ = ⟨value⟩" pattern: - call_expr source="⟨argument⟩⟨callee⟩" + call_expr source="⟨argument⟩" callee: - member_access_expr source="⟨base⟩⟨member_name_node⟩" - base: identifier "Optional" source="let value = optional" - member_name_node: identifier "some" source="let value = optional" + member_access_expr source= + base: identifier "Optional" source= + member_name_node: identifier "some" source= argument: argument source="⟨value⟩" value: - expr_pattern source="⟨modifier⟩⟨expr⟩" - modifier: modifier "let" source="let value = optional" + expr_pattern source="⟨expr⟩" + modifier: modifier "let" source= expr: identifier "value" source="value" value: identifier "optional" source="optional" then: diff --git a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output index 0d403fd592ea..d8cea8bdf335 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output @@ -162,7 +162,7 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n⟨case⟩\n}" value: identifier "event" source="event" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: expr_pattern source="⟨modifier⟩ ⟨expr⟩" modifier: modifier "let" source="let" @@ -173,9 +173,9 @@ top_level source="⟨body⟩" base: inferred_type_expr "." source="." member_name_node: identifier "received" source="received" argument: - argument source="⟨value⟩" + argument source="⟨value⟩)," value: - call_expr source="⟨callee⟩(⟨argument⟩)," + call_expr source="⟨callee⟩(⟨argument⟩" callee: member_access_expr source="⟨base⟩⟨member_name_node⟩" base: inferred_type_expr "." source="." @@ -186,7 +186,7 @@ top_level source="⟨body⟩" argument source="⟨value⟩" value: identifier "timestamp" source="timestamp" body: - block source="case let .received(.some(value), timestamp):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" callee: identifier "print" source="print" @@ -195,7 +195,7 @@ top_level source="⟨body⟩" value: identifier "value" source="value" argument source="⟨value⟩" value: identifier "timestamp" source="timestamp" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: call_expr source="⟨callee⟩(⟨argument⟩)" callee: @@ -209,14 +209,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" expr: identifier "value" source="value" body: - block source="case Type.some(let value):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: identifier "value" source="value" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: break_expr "break" source="break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output index a14f115a3f72..a60324f47a3d 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output @@ -157,7 +157,7 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n⟨case⟩\n}" value: identifier "n" source="n" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: conditional_pattern source="⟨pattern⟩ where ⟨condition⟩" condition: @@ -170,16 +170,16 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" expr: identifier "x" source="x" body: - block source="case let x where x > 0:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"positive\"" source="\"positive\"" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: - or_pattern source="case ⟨pattern⟩ ⟨pattern⟩:\n print(\"non-positive\")" + or_pattern source="⟨pattern⟩ ⟨pattern⟩" pattern: conditional_pattern source="⟨pattern⟩ where ⟨condition⟩," condition: @@ -193,16 +193,16 @@ top_level source="⟨body⟩" expr: identifier "y" source="y" int_literal "0" source="0" body: - block source="case let y where y < 0, 0:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"non-positive\"" source="\"non-positive\"" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output index e86af77df08d..a0da0f15d1e6 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output @@ -307,9 +307,9 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n⟨case⟩\n}" value: identifier "subject" source="subject" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: - or_pattern source="case ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩,\n ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩,\n ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩:\n consume(value)" + or_pattern source="⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩,\n ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩,\n ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩, ⟨pattern⟩" pattern: identifier "value" source="value" binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" @@ -342,54 +342,54 @@ top_level source="⟨body⟩" array_literal source="[⟨element⟩]" element: identifier "value" source="value" map_literal "[key: value]" source="[key: value]" - call_expr source="⟨argument⟩⟨callee⟩" + call_expr source="⟨argument⟩?" callee: - member_access_expr source="⟨base⟩⟨member_name_node⟩" - base: identifier "Optional" source="optional?" - member_name_node: identifier "some" source="optional?" + member_access_expr source= + base: identifier "Optional" source= + member_name_node: identifier "some" source= argument: - argument source="⟨value⟩?" + argument source="⟨value⟩" value: identifier "optional" source="optional" - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="try ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "try" source="try value" - unary_expr source="⟨operand⟩⟨operator⟩" + operator: prefix_operator "try" source= + unary_expr source="⟨operand⟩!" operand: identifier "value" source="value" - operator: postfix_operator "!" source="value!" - type_cast_expr source="⟨expr⟩⟨operator⟩⟨type⟩" + operator: postfix_operator "!" source= + type_cast_expr source="⟨expr⟩ as ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "as" source="value as Target" + operator: infix_operator "as" source= type: identifier "Target" source="Target" - type_test_expr source="⟨expr⟩⟨operator⟩⟨type⟩" + type_test_expr source="⟨expr⟩ is ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "is" source="value is Target" + operator: infix_operator "is" source= type: identifier "Target" source="Target" - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="await ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "await" source="await value" + operator: prefix_operator "await" source= body: - block source="case value, value + offset, -value, lower...upper, makeValue(), makeValue().member,\n .inferred, (value, offset), [value], [key: value], optional?, try value,\n value!, value as Target, value is Target, await value:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "consume" source="consume" argument: argument source="⟨value⟩" value: identifier "value" source="value" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: if_expr source="⟨condition⟩ ? ⟨then⟩ : ⟨else⟩" condition: identifier "condition" source="condition" then: identifier "value" source="value" else: identifier "fallback" source="fallback" body: - block source="case condition ? value : fallback:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "consume" source="consume" argument: argument source="⟨value⟩" value: identifier "fallback" source="fallback" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: break_expr "break" source="break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output index 90372a736d22..7ff90754ac7a 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output @@ -127,33 +127,33 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n⟨case⟩\n}" value: identifier "x" source="x" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: int_literal "1" source="1" body: - block source="case 1:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"one\"" source="\"one\"" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: - or_pattern source="case ⟨pattern⟩, ⟨pattern⟩:\n print(\"two or three\")" + or_pattern source="⟨pattern⟩, ⟨pattern⟩" pattern: int_literal "2" source="2" int_literal "3" source="3" body: - block source="case 2, 3:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"two or three\"" source="\"two or three\"" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output index 8d4d98ec7078..9d417531b74e 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output @@ -122,7 +122,7 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n}" value: identifier "shape" source="shape" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: call_expr source="⟨callee⟩(⟨argument⟩)" callee: @@ -136,14 +136,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" expr: identifier "r" source="r" body: - block source="case .circle(let r):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: identifier "r" source="r" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: call_expr source="⟨callee⟩(⟨argument⟩)" callee: @@ -157,7 +157,7 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" expr: identifier "s" source="s" body: - block source="case .square(let s):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output index 8f7a0ae5f1f1..889e155ae46b 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output @@ -130,7 +130,7 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n}" value: identifier "x" source="x" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: call_expr source="⟨callee⟩(⟨argument⟩)" callee: @@ -142,14 +142,14 @@ top_level source="⟨body⟩" name_node: identifier "isAcknowledged" source="isAcknowledged" value: boolean_literal "false" source="false" body: - block source="case .implicit(isAcknowledged: false):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" argument: argument source="⟨value⟩" value: string_literal "\"yes\"" source="\"yes\"" - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" callee: @@ -166,7 +166,7 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" expr: identifier "rowId" source="rowId" body: - block source="case .thread(threadRowId: _, let rowId):\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index a35890d96301..51bb4af69e5b 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -27,7 +27,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="⟨pattern⟩⟨imported_expr⟩" + import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" imported_expr: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: @@ -36,6 +36,6 @@ top_level source="⟨body⟩" member_name_node: identifier "Networking" source="Networking" member_name_node: identifier "URLSession" source="URLSession" pattern: - named_pattern source="⟨sub_pattern⟩⟨name_node⟩" + named_pattern source="⟨name_node⟩" name_node: identifier "URLSession" source="URLSession" - sub_pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" source="import Foundation.Networking.URLSession" + sub_pattern: bulk_importing_pattern source= diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index 3f069a347481..462a807f0859 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -24,12 +24,12 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="⟨pattern⟩⟨imported_expr⟩" + import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" imported_expr: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: identifier "Foundation" source="Foundation" member_name_node: identifier "Networking" source="Networking" pattern: - named_pattern source="⟨sub_pattern⟩⟨name_node⟩" + named_pattern source="⟨name_node⟩" name_node: identifier "Networking" source="Networking" - sub_pattern: bulk_importing_pattern "import Foundation.Networking" source="import Foundation.Networking" + sub_pattern: bulk_importing_pattern source= diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index d52673da8dda..af9a65e04a90 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -21,9 +21,9 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="⟨pattern⟩⟨imported_expr⟩" + import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" imported_expr: identifier "Foundation" source="Foundation" pattern: - named_pattern source="⟨sub_pattern⟩⟨name_node⟩" + named_pattern source="⟨name_node⟩" name_node: identifier "Foundation" source="Foundation" - sub_pattern: bulk_importing_pattern "import Foundation" source="import Foundation" + sub_pattern: bulk_importing_pattern source= diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index 2ab188e028f7..06a7cb6fd7b5 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -132,10 +132,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "values" source="values" value: - call_expr source="⟨callee⟩" + call_expr source="[⟨callee⟩]()" callee: - generic_type_expr source="⟨base⟩⟨type_argument⟩" - base: identifier "Array" source="[Result]()" + generic_type_expr source="⟨type_argument⟩" + base: identifier "Array" source= type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" @@ -144,10 +144,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "initialized" source="initialized" value: - call_expr source="⟨argument⟩⟨callee⟩⟨argument⟩" + call_expr source="[⟨callee⟩](⟨argument⟩) ⟨argument⟩" callee: - generic_type_expr source="⟨base⟩⟨type_argument⟩" - base: identifier "Array" source="[Result](unsafeUninitializedCapacity: 1) { _, count in\n\tcount = 0\n}" + generic_type_expr source="⟨type_argument⟩" + base: identifier "Array" source= type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" @@ -156,16 +156,16 @@ top_level source="⟨body⟩" argument source="⟨name_node⟩: ⟨value⟩" name_node: identifier "unsafeUninitializedCapacity" source="unsafeUninitializedCapacity" value: int_literal "1" source="1" - argument source="[Result](unsafeUninitializedCapacity: 1) ⟨value⟩" + argument source="⟨value⟩" value: - function_expr source="⟨body⟩⟨parameter⟩⟨parameter⟩" + function_expr source="{ ⟨parameter⟩ ⟨parameter⟩ in\n\t⟨body⟩\n}" parameter: parameter source="⟨pattern⟩," pattern: identifier "_" source="_" parameter source="⟨pattern⟩" pattern: identifier "count" source="count" body: - block source="{ _, count in\n\t⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "count" source="count" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output index 98c721af9fab..91ec160cbf4a 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output @@ -56,10 +56,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "type" source="type" value: - member_access_expr source="⟨base⟩⟨member_name_node⟩" + member_access_expr source="[⟨base⟩].⟨member_name_node⟩" base: - generic_type_expr source="⟨base⟩⟨type_argument⟩" - base: identifier "Array" source="[Result].self" + generic_type_expr source="⟨type_argument⟩" + base: identifier "Array" source= type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" diff --git a/unified/extractor/tests/corpus/swift/expressions/super-expression.output b/unified/extractor/tests/corpus/swift/expressions/super-expression.output index 21a04195c28b..85aa721365cf 100644 --- a/unified/extractor/tests/corpus/swift/expressions/super-expression.output +++ b/unified/extractor/tests/corpus/swift/expressions/super-expression.output @@ -154,21 +154,21 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "value" source="value" value: int_literal "0" source="0" - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩() {}" name_node: identifier "update" source="update" - body: block "func update() {}" source="func update() {}" - class_like_declaration source="⟨modifier⟩⟨base_type⟩⟨name_node⟩⟨member⟩" + body: block source= + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩ {\n ⟨member⟩\n}" modifier: modifier "class" source="class" name_node: identifier "Derived" source="Derived" base_type: - base_type source="class Derived: ⟨type⟩ {\n override func update() {\n _ = super.value\n super.update()\n }\n}" + base_type source="⟨type⟩" type: identifier "Base" source="Base" member: - function_declaration source="⟨modifier⟩⟨body⟩⟨name_node⟩" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {\n ⟨body⟩\n }" modifier: modifier "override" source="override" name_node: identifier "update" source="update" body: - block source="override func update() {\n ⟨stmt⟩\n ⟨stmt⟩\n }" + block source="⟨stmt⟩\n ⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "_" source="_" diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output index 06d2e76d6f55..2ef5fc67213e 100644 --- a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output @@ -45,7 +45,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩\n⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩() {}" name_node: identifier "doWork" source="doWork" - body: block "func doWork() {}" source="func doWork() {}" + body: block source= unsupported_node "unsafe doWork()" source="unsafe doWork()" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index e4a29f540ab9..8cc7fb0a5f81 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -65,7 +65,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "greet" source="greet" parameter: parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩ = ⟨default⟩" @@ -74,7 +74,7 @@ top_level source="⟨body⟩" pattern: identifier "name" source="name" default: string_literal "\"world\"" source="\"world\"" body: - block source="func greet(name: String = \"world\") {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output index 54133b022968..e44356fe9606 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -61,7 +61,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "increment" source="increment" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -69,7 +69,7 @@ top_level source="⟨body⟩" type: unsupported_node "inout Int" source="inout Int" pattern: identifier "x" source="x" body: - block source="func increment(_ x: inout Int) {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index 96d34925e8e7..632da0f8efc6 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -56,7 +56,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "greet" source="greet" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -64,7 +64,7 @@ top_level source="⟨body⟩" type: identifier "String" source="String" pattern: identifier "name" source="name" body: - block source="func greet(person name: String) {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output index 901624c3b423..b555273112d9 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output @@ -51,10 +51,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n}" name_node: identifier "greet" source="greet" body: - block source="func greet() {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index 1c200d26c675..6d4d1c903a71 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -73,7 +73,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩⟨parameter⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" name_node: identifier "add" source="add" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -86,7 +86,7 @@ top_level source="⟨body⟩" pattern: identifier "b" source="b" return_type: identifier "Int" source="Int" body: - block source="func add(_ a: Int, _ b: Int) -> Int {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index 280996f96f32..ba87c47a7b4f 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -63,7 +63,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨type_parameter⟩⟨parameter⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩<⟨type_parameter⟩>(⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" name_node: identifier "identity" source="identity" type_parameter: type_parameter source="⟨name_node⟩" @@ -75,7 +75,7 @@ top_level source="⟨body⟩" pattern: identifier "x" source="x" return_type: identifier "T" source="T" body: - block source="func identity(_ x: T) -> T {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index 0f73aabfd8cd..da0c84c07d74 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -77,7 +77,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" name_node: identifier "sum" source="sum" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩..." @@ -86,7 +86,7 @@ top_level source="⟨body⟩" pattern: identifier "values" source="values" return_type: identifier "Int" source="Int" body: - block source="func sum(_ values: Int...) -> Int {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output index 6e02c0f92968..3531178c0f21 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output +++ b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output @@ -228,8 +228,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "hello " source="hello " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(name)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩" value: identifier "name" source="name" @@ -237,14 +237,14 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩⟨element⟩⟨element⟩\"" element: string_literal "hello " source="hello " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(first)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩" value: identifier "first" source="first" string_literal " " source=" " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(last)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩" value: identifier "last" source="last" @@ -252,8 +252,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "result: " source="result: " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(x + y)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩" value: @@ -265,8 +265,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩⟨element⟩\"" element: string_literal "prefix " source="prefix " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(value)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩" value: identifier "value" source="value" @@ -274,8 +274,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="⟨callee⟩⟨argument⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(x, y)" + call_expr source="\\(⟨argument⟩ ⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩," value: identifier "x" source="x" @@ -285,8 +285,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="⟨callee⟩⟨argument⟩⟨argument⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(x, y, z)" + call_expr source="\\(⟨argument⟩ ⟨argument⟩ ⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨value⟩," value: identifier "x" source="x" @@ -298,8 +298,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="⟨callee⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(arg: x)" + call_expr source="\\(⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨name_node⟩: ⟨value⟩" name_node: identifier "arg" source="arg" @@ -308,8 +308,8 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="⟨callee⟩⟨argument⟩⟨argument⟩" - callee: builtin_expr "interpolation" source="\\(arg: x, arg2: y)" + call_expr source="\\(⟨argument⟩ ⟨argument⟩)" + callee: builtin_expr "interpolation" source= argument: argument source="⟨name_node⟩: ⟨value⟩," name_node: identifier "arg" source="arg" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output index 0cdfd8b9d43b..f0bb8aefa70c 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -93,7 +93,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "casts" source="casts" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -105,7 +105,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "b" source="b" body: - block source="func casts(_ a: Any, _ b: Int) {\n ⟨stmt⟩\n ⟨stmt⟩\n}" + block source="⟨stmt⟩\n ⟨stmt⟩" stmt: unresolved_operator_sequence source="⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩" element: diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output index f0b2c64b9d91..4b7d12ff3420 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -99,7 +99,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩⟨parameter⟩⟨parameter⟩⟨parameter⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" name_node: identifier "choose" source="choose" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -120,7 +120,7 @@ top_level source="⟨body⟩" pattern: identifier "d" source="d" return_type: identifier "Int" source="Int" body: - block source="func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output index 2ed6779f4c89..846ab17caac4 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -66,7 +66,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨parameter⟩⟨parameter⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {\n ⟨body⟩\n}" name_node: identifier "combine" source="combine" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -78,7 +78,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "b" source="b" body: - block source="func combine(_ a: Int, _ b: Int) {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: unresolved_operator_sequence source="⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩" element: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output index c1937aca8255..8a7c088b4c1b 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -144,15 +144,15 @@ top_level source="⟨body⟩" body: block source="{\n ⟨stmt⟩\n}" stmt: - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="try ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source="try foo()" + operator: prefix_operator "try" source= catch_clause: - catch_clause source="⟨pattern⟩⟨body⟩" + catch_clause source="catch ⟨pattern⟩ ⟨body⟩" pattern: - or_pattern source="catch ⟨pattern⟩ ⟨pattern⟩ {\n print(\"retry\")\n}" + or_pattern source="⟨pattern⟩ ⟨pattern⟩" pattern: conditional_pattern source="⟨pattern⟩ where ⟨condition⟩," condition: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index 0c5009e02fc3..cb91d71f311e 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -65,11 +65,11 @@ top_level source="⟨body⟩" body: block source="{\n ⟨stmt⟩\n}" stmt: - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="try ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source="try foo()" + operator: prefix_operator "try" source= catch_clause: catch_clause source="catch ⟨body⟩" body: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output index 4d8b84743253..67f5fc5ee2c9 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output @@ -36,6 +36,6 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "n" source="n" value: - unary_expr source="⟨operand⟩⟨operator⟩" + unary_expr source="⟨operand⟩!" operand: identifier "opt" source="opt" - operator: postfix_operator "!" source="opt!" + operator: postfix_operator "!" source= diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output index 739fcb48ec29..35b898deaedd 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output @@ -80,13 +80,13 @@ top_level source="⟨body⟩" condition: pattern_guard_expr source="case ⟨pattern⟩ = ⟨value⟩" pattern: - call_expr source="⟨argument⟩⟨callee⟩" + call_expr source="⟨argument⟩?" callee: - member_access_expr source="⟨base⟩⟨member_name_node⟩" - base: identifier "Optional" source=".some(let value)?" - member_name_node: identifier "some" source=".some(let value)?" + member_access_expr source= + base: identifier "Optional" source= + member_name_node: identifier "some" source= argument: - argument source="⟨value⟩?" + argument source="⟨value⟩" value: call_expr source="⟨callee⟩(⟨argument⟩)" callee: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output index 6860e38d7a3a..ef0e79bc0e7d 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output @@ -42,7 +42,7 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "x" source="x" type: - generic_type_expr source="⟨type_argument⟩⟨base⟩" - base: identifier "Optional" source="Int?" + generic_type_expr source="⟨type_argument⟩?" + base: identifier "Optional" source= type_argument: identifier "Int" source="Int" value: builtin_expr "nil" source="nil" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output index 5be898e21651..1d080dbeefa6 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output @@ -55,11 +55,11 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="⟨body⟩⟨name_node⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩() throws -> ⟨return_type⟩ {\n ⟨body⟩\n}" name_node: identifier "read" source="read" return_type: identifier "String" source="String" body: - block source="func read() throws -> String {\n ⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: string_literal "\"\"" source="\"\"" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output index 4faa3545ea5c..4d7b105688c8 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output @@ -43,8 +43,8 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "result" source="result" value: - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="try! ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try!" source="try! foo()" + operator: prefix_operator "try!" source= diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output index 57464ed82141..fdf08e347588 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output @@ -43,8 +43,8 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "result" source="result" value: - unary_expr source="⟨operator⟩⟨operand⟩" + unary_expr source="try? ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try?" source="try? foo()" + operator: prefix_operator "try?" source= diff --git a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output index 6a02642ced38..17004c0c8959 100644 --- a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output +++ b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output @@ -92,9 +92,9 @@ sourceFile --- -top_level source="⟨body⟩" +top_level source="⟨body⟩\n}" body: - block source="⟨stmt⟩\n}" + block source="⟨stmt⟩" stmt: accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" @@ -107,16 +107,16 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n ⟨case⟩\n ⟨case⟩\n }" value: identifier "y" source="y" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: identifier "someConstant" source="someConstant" body: - block source="case someConstant:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: int_literal "1" source="1" - switch_case source="⟨body⟩" + switch_case source="default:\n ⟨body⟩" body: - block source="default:\n ⟨stmt⟩" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: int_literal "2" source="2" diff --git a/unified/extractor/tests/corpus/swift/types/class-function.output b/unified/extractor/tests/corpus/swift/types/class-function.output index a3084367cea1..c161b663b50a 100644 --- a/unified/extractor/tests/corpus/swift/types/class-function.output +++ b/unified/extractor/tests/corpus/swift/types/class-function.output @@ -51,7 +51,7 @@ top_level source="⟨body⟩" modifier: modifier "class" source="class" name_node: identifier "Factory" source="Factory" member: - function_declaration source="⟨modifier⟩⟨body⟩⟨name_node⟩" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" modifier: modifier "class" source="class" name_node: identifier "make" source="make" - body: block "class func make() {}" source="class func make() {}" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/class-inheritance.output b/unified/extractor/tests/corpus/swift/types/class-inheritance.output index 28a35c0906ff..7ab4d280ebc6 100644 --- a/unified/extractor/tests/corpus/swift/types/class-inheritance.output +++ b/unified/extractor/tests/corpus/swift/types/class-inheritance.output @@ -32,9 +32,9 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩⟨base_type⟩⟨name_node⟩" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩ {}" modifier: modifier "class" source="class" name_node: identifier "Dog" source="Dog" base_type: - base_type source="class Dog: ⟨type⟩ {}" + base_type source="⟨type⟩" type: identifier "Animal" source="Animal" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 76becbc9005e..c5eb62255469 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -98,7 +98,7 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "x" source="x" type: identifier "Int" source="Int" - constructor_declaration source="⟨name_node⟩⟨body⟩⟨parameter⟩" + constructor_declaration source="⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n }" name_node: identifier "init" source="init" parameter: parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" @@ -106,7 +106,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" body: - block source="init(x: Int) {\n ⟨stmt⟩\n }" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index 64981979359d..7d181dae78d2 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -85,10 +85,10 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "n" source="n" value: int_literal "0" source="0" - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n }" name_node: identifier "bump" source="bump" body: - block source="func bump() {\n ⟨stmt⟩\n }" + block source="⟨stmt⟩" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "n" source="n" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output index f2a839add74c..700a0e6eccc2 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output @@ -37,11 +37,11 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩⟨base_type⟩⟨base_type⟩⟨name_node⟩" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩, ⟨base_type⟩ {}" modifier: modifier "class" source="class" name_node: identifier "Button" source="Button" base_type: - base_type source="class Button: ⟨type⟩, Drawable {}" + base_type source="⟨type⟩" type: identifier "Control" source="Control" - base_type source="class Button: Control, ⟨type⟩ {}" + base_type source="⟨type⟩" type: identifier "Drawable" source="Drawable" diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index b4021e9dfdbb..5025163d5a2f 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -113,13 +113,13 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "h" source="h" type: identifier "Double" source="Double" - accessor_declaration source="⟨modifier⟩⟨accessor_kind⟩⟨body⟩⟨name_node⟩⟨type⟩" + accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨body⟩\n }" modifier: modifier "var" source="var" name_node: identifier "area" source="area" - accessor_kind: accessor_kind "get" source="var area: Double {\n return w * h\n }" + accessor_kind: accessor_kind "get" source= type: identifier "Double" source="Double" body: - block source="var area: Double {\n ⟨stmt⟩\n }" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output index 82bda546786f..e6c32e55ff46 100644 --- a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -67,7 +67,7 @@ top_level source="⟨body⟩" modifier: modifier "struct" source="struct" name_node: identifier "Size" source="Size" member: - constructor_declaration source="⟨name_node⟩⟨body⟩⟨parameter⟩⟨parameter⟩" + constructor_declaration source="⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {}" name_node: identifier "init" source="init" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -78,4 +78,4 @@ top_level source="⟨body⟩" external_name_node: identifier "height" source="height" type: identifier "Int" source="Int" pattern: identifier "h" source="h" - body: block "init(width w: Int, height h: Int) {}" source="init(width w: Int, height h: Int) {}" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index ef7a079eabf9..0d80213f4eb9 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -73,23 +73,23 @@ top_level source="⟨body⟩" modifier: modifier "enum" source="enum" name_node: identifier "Shape" source="Shape" member: - class_like_declaration source="⟨name_node⟩⟨member⟩⟨modifier⟩" - modifier: modifier "enum_case" source="circle(radius: Double)" + class_like_declaration source="⟨name_node⟩(⟨member⟩)" + modifier: modifier "enum_case" source= name_node: identifier "circle" source="circle" member: - constructor_declaration source="⟨body⟩⟨parameter⟩" + constructor_declaration source="⟨parameter⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" pattern: identifier "radius" source="radius" - body: block "circle(radius: Double)" source="circle(radius: Double)" - class_like_declaration source="⟨name_node⟩⟨member⟩⟨modifier⟩" - modifier: modifier "enum_case" source="square(side: Double)" + body: block source= + class_like_declaration source="⟨name_node⟩(⟨member⟩)" + modifier: modifier "enum_case" source= name_node: identifier "square" source="square" member: - constructor_declaration source="⟨body⟩⟨parameter⟩" + constructor_declaration source="⟨parameter⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" pattern: identifier "side" source="side" - body: block "square(side: Double)" source="square(side: Double)" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output index a66dc1f2d7c0..9fdf78ce054e 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output @@ -69,15 +69,15 @@ top_level source="⟨body⟩" modifier: modifier "enum" source="enum" name_node: identifier "Direction" source="Direction" member: - variable_declaration source="⟨modifier⟩⟨pattern⟩" - modifier: modifier "enum_case" source="north" + variable_declaration source="⟨pattern⟩" + modifier: modifier "enum_case" source= pattern: identifier "north" source="north" - variable_declaration source="⟨modifier⟩⟨pattern⟩" - modifier: modifier "enum_case" source="south" + variable_declaration source="⟨pattern⟩" + modifier: modifier "enum_case" source= pattern: identifier "south" source="south" - variable_declaration source="⟨modifier⟩⟨pattern⟩" - modifier: modifier "enum_case" source="east" + variable_declaration source="⟨pattern⟩" + modifier: modifier "enum_case" source= pattern: identifier "east" source="east" - variable_declaration source="⟨modifier⟩⟨pattern⟩" - modifier: modifier "enum_case" source="west" + variable_declaration source="⟨pattern⟩" + modifier: modifier "enum_case" source= pattern: identifier "west" source="west" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index 97945a6cc910..cc2c30590e27 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -48,21 +48,21 @@ top_level source="⟨body⟩" modifier: modifier "enum" source="enum" name_node: identifier "Suit" source="Suit" member: - variable_declaration source="⟨pattern⟩⟨modifier⟩" - modifier: modifier "enum_case" source="clubs," + variable_declaration source="⟨pattern⟩," + modifier: modifier "enum_case" source= pattern: identifier "clubs" source="clubs" - variable_declaration source="⟨pattern⟩⟨modifier⟩⟨modifier⟩" + variable_declaration source="⟨pattern⟩," modifier: - modifier "chained_declaration" source="diamonds," - modifier "enum_case" source="diamonds," + modifier "chained_declaration" source= + modifier "enum_case" source= pattern: identifier "diamonds" source="diamonds" - variable_declaration source="⟨pattern⟩⟨modifier⟩⟨modifier⟩" + variable_declaration source="⟨pattern⟩," modifier: - modifier "chained_declaration" source="hearts," - modifier "enum_case" source="hearts," + modifier "chained_declaration" source= + modifier "enum_case" source= pattern: identifier "hearts" source="hearts" - variable_declaration source="⟨modifier⟩⟨modifier⟩⟨pattern⟩" + variable_declaration source="⟨pattern⟩" modifier: - modifier "chained_declaration" source="spades" - modifier "enum_case" source="spades" + modifier "chained_declaration" source= + modifier "enum_case" source= pattern: identifier "spades" source="spades" diff --git a/unified/extractor/tests/corpus/swift/types/extension.output b/unified/extractor/tests/corpus/swift/types/extension.output index 0ab670eb5cfd..d1358e2f2f17 100644 --- a/unified/extractor/tests/corpus/swift/types/extension.output +++ b/unified/extractor/tests/corpus/swift/types/extension.output @@ -72,11 +72,11 @@ top_level source="⟨body⟩" modifier: modifier "extension" source="extension" extension_target: identifier "Int" source="Int" member: - function_declaration source="⟨body⟩⟨name_node⟩⟨return_type⟩" + function_declaration source="func ⟨name_node⟩() -> ⟨return_type⟩ { ⟨body⟩ }" name_node: identifier "squared" source="squared" return_type: identifier "Int" source="Int" body: - block source="func squared() -> Int { ⟨stmt⟩ }" + block source="⟨stmt⟩" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output index e26e022261f4..299c609c8022 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -67,5 +67,5 @@ top_level source="⟨body⟩" pattern: identifier "callback" source="callback" type: unsupported_node "@convention(c) () -> Void" source="@convention(c) () -> Void" value: - function_expr source="⟨body⟩" - body: block "{}" source="{}" + function_expr source="{}" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output index 3d4a80ebea18..15eb240a8f64 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -60,5 +60,5 @@ top_level source="⟨body⟩" pattern: identifier "handler" source="handler" type: unsupported_node "@Sendable () -> Void" source="@Sendable () -> Void" value: - function_expr source="⟨body⟩" - body: block "{}" source="{}" + function_expr source="{}" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.output b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output index 0a22d1ca0b07..4e3238bf4e62 100644 --- a/unified/extractor/tests/corpus/swift/types/noncopyable-type.output +++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output @@ -54,11 +54,11 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩⟨base_type⟩⟨name_node⟩⟨member⟩" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩ {\n ⟨member⟩\n}" modifier: modifier "struct" source="struct" name_node: identifier "FileHandle" source="FileHandle" base_type: - base_type source="struct FileHandle: ⟨type⟩ {\n let descriptor: Int\n}" + base_type source="⟨type⟩" type: unsupported_node "~Copyable" source="~Copyable" member: variable_declaration source="⟨modifier⟩ ⟨pattern⟩: ⟨type⟩" diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index f84cf98e24c4..f73a341020af 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -126,10 +126,10 @@ top_level source="⟨body⟩" stmt: return_expr source="return ⟨value⟩" value: identifier "_v" source="_v" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n get { return _v }\n ⟨accessor_kind⟩⟨modifier⟩⟨body⟩" + accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n get { return _v }\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source="set { _v = newValue }" + modifier "chained_declaration" source= name_node: identifier "v" source="v" accessor_kind: accessor_kind "set" source="set" type: identifier "Int" source="Int" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output index b2bc4b1e1867..261e40a59f76 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output @@ -61,10 +61,10 @@ top_level source="⟨body⟩" modifier: modifier "protocol" source="protocol" name_node: identifier "Drawable" source="Drawable" member: - function_declaration source="⟨body⟩⟨name_node⟩" + function_declaration source="func ⟨name_node⟩()" name_node: identifier "draw" source="draw" - body: block "func draw()" source="func draw()" - function_declaration source="⟨modifier⟩⟨body⟩⟨name_node⟩" + body: block source= + function_declaration source="⟨modifier⟩ func ⟨name_node⟩()" modifier: modifier "static" source="static" name_node: identifier "make" source="make" - body: block "static func make()" source="static func make()" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index 0a3277df185c..d8efdbcc7bd0 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -118,8 +118,8 @@ top_level source="⟨body⟩" name_node: identifier "bar" source="bar" accessor_kind: accessor_kind "get" source="get" type: identifier "String" source="String" - accessor_declaration source="⟨name_node⟩: ⟨type⟩ { get ⟨accessor_kind⟩⟨modifier⟩" - modifier: modifier "chained_declaration" source="set" + accessor_declaration source="⟨name_node⟩: ⟨type⟩ { get ⟨accessor_kind⟩" + modifier: modifier "chained_declaration" source= name_node: identifier "bar" source="bar" accessor_kind: accessor_kind "set" source="set" type: identifier "String" source="String" diff --git a/unified/extractor/tests/corpus/swift/types/static-function.output b/unified/extractor/tests/corpus/swift/types/static-function.output index b7f87ab13d76..0c66ba1c251b 100644 --- a/unified/extractor/tests/corpus/swift/types/static-function.output +++ b/unified/extractor/tests/corpus/swift/types/static-function.output @@ -51,7 +51,7 @@ top_level source="⟨body⟩" modifier: modifier "class" source="class" name_node: identifier "Factory" source="Factory" member: - function_declaration source="⟨modifier⟩⟨body⟩⟨name_node⟩" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" modifier: modifier "static" source="static" name_node: identifier "make" source="make" - body: block "static func make() {}" source="static func make() {}" + body: block source= diff --git a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output index 90e58be069ad..d42155011399 100644 --- a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output +++ b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output @@ -72,12 +72,12 @@ top_level source="⟨body⟩" switch_expr source="switch ⟨value⟩ {\n⟨case⟩\n⟨case⟩\n}" value: identifier "y" source="y" case: - switch_case source="⟨body⟩⟨pattern⟩" + switch_case source="case ⟨pattern⟩: ⟨body⟩" pattern: identifier "someConstant" source="someConstant" body: - block source="case someConstant: ⟨stmt⟩" + block source="⟨stmt⟩" stmt: int_literal "1" source="1" - switch_case source="⟨body⟩" + switch_case source="default: ⟨body⟩" body: - block source="default: ⟨stmt⟩" + block source="⟨stmt⟩" stmt: int_literal "2" source="2" diff --git a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output index fd6057bfb1f8..7666b6d7dedb 100644 --- a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output +++ b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output @@ -44,9 +44,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "x" source="x" value: int_literal "1" source="1" - variable_declaration source="⟨modifier⟩ x = 1, ⟨pattern⟩⟨modifier⟩⟨value⟩" + variable_declaration source="⟨modifier⟩ x = 1, ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" - modifier "chained_declaration" source="y = 2" + modifier "chained_declaration" source= pattern: identifier "y" source="y" value: int_literal "2" source="2" diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 13397f03e6fd..7f9576a0c1b5 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -110,10 +110,10 @@ top_level source="⟨body⟩" pattern: identifier "x" source="x" type: identifier "Int" source="Int" value: int_literal "0" source="0" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n ⟨accessor_kind⟩⟨modifier⟩⟨body⟩" + accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source="willSet { print(newValue) }" + modifier "chained_declaration" source= name_node: identifier "x" source="x" accessor_kind: accessor_kind "willSet" source="willSet" body: @@ -124,10 +124,10 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: identifier "newValue" source="newValue" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n willSet { print(newValue) }\n ⟨accessor_kind⟩⟨modifier⟩⟨body⟩" + accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n willSet { print(newValue) }\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source="didSet { print(oldValue) }" + modifier "chained_declaration" source= name_node: identifier "x" source="x" accessor_kind: accessor_kind "didSet" source="didSet" body: diff --git a/unified/extractor/tests/location_tests.rs b/unified/extractor/tests/location_tests.rs new file mode 100644 index 000000000000..0d3850b394d5 --- /dev/null +++ b/unified/extractor/tests/location_tests.rs @@ -0,0 +1,100 @@ +use yeast::Ast; + +#[path = "../src/languages/mod.rs"] +mod languages; + +fn desugar(source: &str) -> Ast { + let lang = languages::all_language_specs() + .into_iter() + .find(|language| { + language + .file_globs + .iter() + .any(|glob| glob.contains("swift")) + }) + .expect("Swift language spec"); + let parsed = (lang.parser)(source.as_bytes()).expect("Swift should parse"); + lang.desugarer + .run_from_ast(parsed.ast) + .expect("Swift should desugar") +} + +fn spans(ast: &Ast, source: &str, kind: &str, content: Option<&str>) -> Vec { + ranges(ast, kind, content) + .into_iter() + .filter_map(|range| source.get(range).map(str::to_owned)) + .collect() +} + +fn ranges(ast: &Ast, kind: &str, content: Option<&str>) -> Vec> { + ast.reachable_node_ids() + .into_iter() + .filter_map(|id| { + let node = ast.get_node(id)?; + if node.kind_name() != kind + || content + .is_some_and(|content| node.opt_string_content().as_deref() != Some(content)) + { + return None; + } + Some(node.byte_range()) + }) + .collect() +} + +fn assert_has_span(ast: &Ast, source: &str, kind: &str, content: Option<&str>, expected: &str) { + let spans = spans(ast, source, kind, content); + assert!( + spans.iter().any(|span| span == expected), + "expected {kind} {content:?} to span {expected:?}, got {spans:?}" + ); +} + +fn assert_has_empty_span(ast: &Ast, kind: &str, content: Option<&str>, expected_offset: usize) { + let ranges = ranges(ast, kind, content); + assert!( + ranges + .iter() + .any(|range| range.start == expected_offset && range.end == expected_offset), + "expected {kind} {content:?} to have an empty span at {expected_offset}, got {ranges:?}" + ); +} + +#[test] +fn generic_type_children_have_local_ranges() { + let source = "let x = C()"; + let ast = desugar(source); + + assert_has_span(&ast, source, "generic_type_expr", None, "C"); + assert_has_span(&ast, source, "identifier", Some("C"), "C"); + assert_has_span(&ast, source, "identifier", Some("Foo"), "Foo"); +} + +#[test] +fn import_member_chain_excludes_import_keyword() { + let source = "import Foundation.Networking.URLSession"; + let ast = desugar(source); + + assert_has_span( + &ast, + source, + "member_access_expr", + None, + "Foundation.Networking", + ); + assert_has_span( + &ast, + source, + "member_access_expr", + None, + "Foundation.Networking.URLSession", + ); + assert_has_span( + &ast, + source, + "import_declaration", + None, + "import Foundation.Networking.URLSession", + ); + assert_has_empty_span(&ast, "bulk_importing_pattern", None, 0); +} From 15e4a20446214334d4698a28b83733e1b1f79ced Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 11 Sep 2026 14:40:00 +0000 Subject: [PATCH 02/14] yeast: Handle empty locations correctly The location 0..0 was being treated as "no useable location", which at the beginning of a file could cause problems. We now represent this as None instead, making Some(0..0) a valid empty location. --- shared/yeast/src/lib.rs | 88 +++++++---------------- shared/yeast/src/range.rs | 40 +++++++++++ shared/yeast/tests/test.rs | 30 ++++++++ unified/extractor/tests/location_tests.rs | 14 +--- 4 files changed, 99 insertions(+), 73 deletions(-) diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index cae721db6586..affc94c9bc88 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -144,10 +144,7 @@ impl YeastDisplay for Id { impl YeastSourceRange for Id { fn yeast_source_range(&self, ast: &Ast) -> Option { - ast.get_node(*self).and_then(|n| match &n.content { - NodeContent::Range(r) => Some(*r), - _ => n.source_range, - }) + ast.get_node(*self).and_then(Node::source_range) } } @@ -598,7 +595,7 @@ impl Ast { .union_source_range_of_children(&fields) .map_or(source_range, |child_range| { Some(match source_range { - Some(source_range) => union_source_ranges(child_range, source_range), + Some(source_range) => child_range.union(source_range), None => child_range, }) }), @@ -631,7 +628,7 @@ impl Ast { panic!("extend_source_range: cannot modify a parsed node"); } node.source_range = Some(match node.source_range { - Some(existing) => union_source_ranges(existing, source_range), + Some(existing) => existing.union(source_range), None => source_range, }); } @@ -673,35 +670,30 @@ impl Ast { let Some(child) = self.get_node(child_id) else { continue; }; - - let child_start_byte = child.start_byte(); - let child_end_byte = child.end_byte(); - - // Skip children that carry no usable location. - if child_start_byte == 0 && child_end_byte == 0 { + let Some(child_range) = child.source_range() else { continue; - } + }; match start_byte { None => { - start_byte = Some(child_start_byte); - start_point = child.start_position(); + start_byte = Some(child_range.start_byte); + start_point = child_range.start_point; } - Some(current_start) if child_start_byte < current_start => { - start_byte = Some(child_start_byte); - start_point = child.start_position(); + Some(current_start) if child_range.start_byte < current_start => { + start_byte = Some(child_range.start_byte); + start_point = child_range.start_point; } _ => {} } match end_byte { None => { - end_byte = Some(child_end_byte); - end_point = child.end_position(); + end_byte = Some(child_range.end_byte); + end_point = child_range.end_point; } - Some(current_end) if child_end_byte > current_end => { - end_byte = Some(child_end_byte); - end_point = child.end_position(); + Some(current_end) if child_range.end_byte > current_end => { + end_byte = Some(child_range.end_byte); + end_point = child_range.end_point; } _ => {} } @@ -810,25 +802,6 @@ impl Ast { } } -fn union_source_ranges(first: Range, second: Range) -> Range { - let (start_byte, start_point) = if first.start_byte <= second.start_byte { - (first.start_byte, first.start_point) - } else { - (second.start_byte, second.start_point) - }; - let (end_byte, end_point) = if first.end_byte >= second.end_byte { - (first.end_byte, first.end_point) - } else { - (second.end_byte, second.end_point) - }; - Range { - start_byte, - end_byte, - start_point, - end_point, - } -} - /// A node in our AST #[derive(PartialEq, Eq, Debug, Clone, Serialize)] pub struct Node { @@ -871,36 +844,29 @@ impl Node { Point { row: 0, column: 0 } } - pub fn start_position(&self) -> Point { + pub fn source_range(&self) -> Option { match self.content { - NodeContent::Range(range) => range.start_point, - _ => self - .source_range - .map_or_else(|| self.fake_point(), |r| r.start_point), + NodeContent::Range(range) => Some(range), + _ => self.source_range, } } + pub fn start_position(&self) -> Point { + self.source_range() + .map_or_else(|| self.fake_point(), |range| range.start_point) + } + pub fn end_position(&self) -> Point { - match self.content { - NodeContent::Range(range) => range.end_point, - _ => self - .source_range - .map_or_else(|| self.fake_point(), |r| r.end_point), - } + self.source_range() + .map_or_else(|| self.fake_point(), |range| range.end_point) } pub fn start_byte(&self) -> usize { - match self.content { - NodeContent::Range(range) => range.start_byte, - _ => self.source_range.map_or(0, |r| r.start_byte), - } + self.source_range().map_or(0, |range| range.start_byte) } pub fn end_byte(&self) -> usize { - match self.content { - NodeContent::Range(range) => range.end_byte, - _ => self.source_range.map_or(0, |r| r.end_byte), - } + self.source_range().map_or(0, |range| range.end_byte) } pub fn byte_range(&self) -> std::ops::Range { diff --git a/shared/yeast/src/range.rs b/shared/yeast/src/range.rs index e56bbcc6fb85..b9aade99ce74 100644 --- a/shared/yeast/src/range.rs +++ b/shared/yeast/src/range.rs @@ -30,3 +30,43 @@ pub struct Range { pub start_point: Point, pub end_point: Point, } + +impl Range { + /// Return the smallest range containing both ranges. + pub fn union(self, other: Self) -> Self { + let (start_byte, start_point) = if self.start_byte <= other.start_byte { + (self.start_byte, self.start_point) + } else { + (other.start_byte, other.start_point) + }; + let (end_byte, end_point) = if self.end_byte >= other.end_byte { + (self.end_byte, self.end_point) + } else { + (other.end_byte, other.end_point) + }; + Self { + start_byte, + end_byte, + start_point, + end_point, + } + } + + /// Return an empty range anchored at this range's start. + pub fn empty_at_start(self) -> Self { + Self { + end_byte: self.start_byte, + end_point: self.start_point, + ..self + } + } + + /// Return an empty range anchored at this range's end. + pub fn empty_at_end(self) -> Self { + Self { + start_byte: self.end_byte, + start_point: self.end_point, + ..self + } + } +} diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index dbaee55beb22..3d34fa69405b 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -1709,6 +1709,36 @@ fn test_nested_synthetic_node_uses_child_location() { assert_eq!(arguments.byte_range(), 0..3); } +/// An explicit empty range at byte zero is a real location, not the sentinel +/// for an absent location, and therefore contributes to parent ranges. +#[test] +fn test_empty_range_at_file_start_contributes_to_parent() { + use std::collections::BTreeMap; + + let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); + let schema = + yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); + let mut ast = Ast::with_schema(schema); + let empty = Range { + start_byte: 0, + end_byte: 0, + start_point: Point::new(0, 0), + end_point: Point::new(0, 0), + }; + let child = + ast.create_named_token_with_range("identifier", "synthetic".to_owned(), Some(empty)); + let fields = BTreeMap::from([(ast.field_id_for_name("method").unwrap(), vec![child])]); + let parent = ast.create_node_with_range( + ast.id_for_node_kind("call").unwrap(), + NodeContent::DynamicString(String::new()), + fields, + true, + None, + ); + + assert_eq!(ast.get_node(parent).unwrap().source_range(), Some(empty)); +} + /// A rule that only unwraps and returns a translated capture must not widen /// that capture to the wrapper's source range. #[test] diff --git a/unified/extractor/tests/location_tests.rs b/unified/extractor/tests/location_tests.rs index 0d3850b394d5..08cec5643244 100644 --- a/unified/extractor/tests/location_tests.rs +++ b/unified/extractor/tests/location_tests.rs @@ -37,7 +37,8 @@ fn ranges(ast: &Ast, kind: &str, content: Option<&str>) -> Vec, e ); } -fn assert_has_empty_span(ast: &Ast, kind: &str, content: Option<&str>, expected_offset: usize) { - let ranges = ranges(ast, kind, content); - assert!( - ranges - .iter() - .any(|range| range.start == expected_offset && range.end == expected_offset), - "expected {kind} {content:?} to have an empty span at {expected_offset}, got {ranges:?}" - ); -} - #[test] fn generic_type_children_have_local_ranges() { let source = "let x = C()"; @@ -96,5 +87,4 @@ fn import_member_chain_excludes_import_keyword() { None, "import Foundation.Networking.URLSession", ); - assert_has_empty_span(&ast, "bulk_importing_pattern", None, 0); } From 5ab8674e537d83b7d18e97cf367583d5de36ca09 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 17 Sep 2026 14:46:52 +0000 Subject: [PATCH 03/14] yeast: Add explicit location macros Adds two new macros, both variants of the existing `tree!` macro. First, `tree_at!` takes an extra argument, and sets the location of the root of the constructed tree to be that of the argument in question. Secondly, `tree_spanning!` does the same construction, but accepts an iterable of nodes instead. It then makes it so that the location of the root node of the constructed tree is the smallest span that contains all of the locations given by the iterable. --- shared/yeast/doc/yeast.md | 16 +++++++++ shared/yeast/src/build.rs | 28 +++++++++++++++ shared/yeast/src/lib.rs | 46 ++++++++++++++++++++++++ shared/yeast/tests/test.rs | 71 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index b4ef1905b141..16f6ddb9c937 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -256,6 +256,22 @@ elided keywords or delimiters without assigning the same broad range to every synthetic descendant. A transform that simply returns a translated capture does not widen that capture to the wrapper's range. +When the desired range belongs to another node, `tree_at!` assigns that range +to the template's root. Nested nodes still derive their own locations normally: + +```rust +let synthetic = tree_at!(ctx, source, (synthetic_node child: (nested value: {child}))); +``` + +`tree_spanning!` similarly assigns the union of several node ranges: + +```rust +let synthetic = tree_spanning!(ctx, nodes, (synthetic_node child: {child})); +``` + +For literals, `ctx.literal_at_start_of(...)` creates an empty range at another +node's start. + For reviewing locations, `DumpOptions::show_abridged_source` prints each node's source range with every direct child replaced by its field name in Unicode angle brackets. This keeps delimiters and other parent-owned syntax visible diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index 7a15f77dc524..8a840f7cc784 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -160,6 +160,16 @@ impl<'a, C> BuildCtx<'a, C> { results } + /// Assign an explicit source range to a newly-built result root. + #[doc(hidden)] + pub fn set_node_source_range(&mut self, node: Id, source_range: Option) -> Id { + if let Some(source_range) = source_range { + self.ast.set_source_range(node, source_range); + self.created_nodes.remove(&node); + } + node + } + /// Look up a capture variable, returning its node Id. pub fn capture(&self, name: &str) -> Id { self.captures @@ -183,6 +193,18 @@ impl<'a, C> BuildCtx<'a, C> { self.ast.source_text(id) } + /// Return the source range of a parsed or synthetic node. + fn source_range_of(&self, id: Id) -> Option { + self.ast.get_node(id).and_then(|node| node.source_range()) + } + + /// Return an empty range between two non-overlapping nodes. + pub fn empty_source_range_between(&self, left: Id, right: Id) -> Option { + let left = self.source_range_of(left)?; + let right = self.source_range_of(right)?; + (left.end_byte <= right.start_byte).then(|| left.empty_at_end()) + } + /// Create a named AST node with the given kind and fields. pub fn node(&mut self, kind: &str, fields: Vec<(&str, Vec)>) -> Id { let kind_id = self @@ -221,6 +243,12 @@ impl<'a, C> BuildCtx<'a, C> { self.create_named_token_with_range(kind, value.to_string(), source_range) } + /// Create a literal with an empty range at another node's start. + pub fn literal_at_start_of(&mut self, kind: &'static str, value: &str, source: Id) -> Id { + let source_range = self.source_range_of(source).map(Range::empty_at_start); + self.literal_with_source_range(kind, value, source_range) + } + /// Create a leaf node with an auto-generated unique name. pub fn fresh(&mut self, kind: &'static str, name: &str) -> Id { let generated = self.fresh.resolve(name); diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index affc94c9bc88..a71b604411c5 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -18,6 +18,40 @@ mod visitor; pub use range::{Point, Range}; pub use yeast_macros::{query, rule, rules, tree, trees}; +/// Build a single AST node whose root uses another node's source range. +/// +/// Nested nodes in the template are built normally and derive their locations +/// from their own children. +#[macro_export] +macro_rules! tree_at { + ($ctx:ident, $source:expr, ($($tree:tt)*)) => {{ + let __yeast_source: $crate::Id = $source; + let __yeast_source_range = $ctx + .ast + .get_node(__yeast_source) + .and_then(|node| node.source_range()); + let __yeast_node: $crate::Id = $crate::tree!($ctx, ($($tree)*)); + $ctx.set_node_source_range(__yeast_node, __yeast_source_range) + }}; +} + +/// Build a single AST node whose root spans a collection of nodes. +/// +/// Nested nodes in the template are built normally and derive their locations +/// from their own children. +#[macro_export] +macro_rules! tree_spanning { + ($ctx:ident, $sources:expr, ($($tree:tt)*)) => {{ + let __yeast_source_range = ::std::iter::IntoIterator::into_iter($sources) + .filter_map(|source: $crate::Id| { + $ctx.ast.get_node(source).and_then(|node| node.source_range()) + }) + .reduce($crate::Range::union); + let __yeast_node: $crate::Id = $crate::tree!($ctx, ($($tree)*)); + $ctx.set_node_source_range(__yeast_node, __yeast_source_range) + }}; +} + use captures::Captures; use query::QueryNode; @@ -633,6 +667,18 @@ impl Ast { }); } + /// Replace a synthetic node's source range. + pub(crate) fn set_source_range(&mut self, id: Id, source_range: Range) { + let node = self + .nodes + .get_mut(id.0) + .unwrap_or_else(|| panic!("set_source_range: invalid node id {}", id.0)); + if matches!(node.content, NodeContent::Range(_)) { + panic!("set_source_range: cannot modify a parsed node"); + } + node.source_range = Some(source_range); + } + /// Register a named node kind, returning its id (idempotent). Lets callers /// build an AST in a single pass, registering kinds as nodes are created /// rather than pre-populating the schema. diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 3d34fa69405b..5a6536654394 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -1799,6 +1799,77 @@ fn test_explicit_recursive_translation_keeps_nested_rule_location() { assert_eq!(identifier.byte_range(), 4..7); } +/// `tree_at!` assigns the captured node's range only to the template root. +#[test] +fn test_tree_at_assigns_capture_range_to_root_only() { + let rule: Rule = rule!( + (call + method: (identifier) @name + receiver: (identifier) @recv + ) @@source + => + call { + let arguments = tree_at!(ctx, source, (argument_list argument: (integer "0"))); + tree!((call method: {name} receiver: {recv} arguments: {arguments})) + } + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + let arguments = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "argument_list") + .expect("argument list exists"); + assert_eq!(arguments.byte_range(), 0..9); + + let integer = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "integer") + .expect("integer exists"); + assert_eq!(integer.byte_range(), 0..0); +} + +/// `tree_spanning!` assigns the union of the captured node ranges only to the +/// template root. +#[test] +fn test_tree_spanning_assigns_union_to_root_only() { + let rule: Rule = rule!( + (call + method: (identifier) @name + receiver: (identifier) @recv + ) + => + call { + let arguments = tree_spanning!( + ctx, + [recv, name], + (argument_list argument: (integer "0")) + ); + tree!((call method: {name} receiver: {recv} arguments: {arguments})) + } + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + let arguments = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "argument_list") + .expect("argument list exists"); + assert_eq!(arguments.byte_range(), 0..7); + + let integer = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "integer") + .expect("integer exists"); + assert_eq!(integer.byte_range(), 0..0); +} + /// Explicit ranges on multiple results must not be widened to the range of the /// input node matched by the rule. #[test] From c651c5f728f31a936e733c36b2ef86c944118395 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 11 Sep 2026 14:45:12 +0000 Subject: [PATCH 04/14] yeast: Add location heuristic for synthetic nodes with no location set For such nodes, we assign them the zero-length location at the beginning of the matched input node. Note: This does mean some `expr_pattern`s now appear to have a fixed `let ` prefix in their source range (when really that `let` should belong to the modifier). This will be fixed in a later commit. --- shared/yeast/doc/yeast.md | 17 ++++++----- shared/yeast/src/build.rs | 15 +++++++++- shared/yeast/tests/test.rs | 28 ++++++++++++++++++ .../empty-array-literal-with-type.output | 2 +- .../swift/control-flow/guard-let.output | 12 ++++---- .../if-let-optional-binding.output | 12 ++++---- .../switch-expression-pattern.output | 16 +++++----- ...with-deeply-nested-path-three-parts.output | 6 ++-- .../import-with-dotted-path-two-parts.output | 6 ++-- .../simple-import-with-single-name.output | 6 ++-- .../expressions/array-type-constructor.output | 12 ++++---- .../expressions/array-type-metatype.output | 6 ++-- .../expressions/unsafe-expression.output | 2 +- .../literals/string-with-interpolation.output | 18 ++++++------ .../catch-where-clauses.output | 2 +- .../optionals-and-errors/do-catch.output | 2 +- .../optionals-and-errors/force-unwrap.output | 2 +- .../optional-enum-case-binding.output | 6 ++-- .../optional-type-annotation.output | 2 +- .../try-expression-2.output | 2 +- .../try-expression.output | 2 +- .../corpus/swift/types/class-function.output | 2 +- .../swift/types/computed-property.output | 2 +- .../types/constructor-with-parameters.output | 2 +- .../types/enum-with-associated-values.output | 16 +++++----- .../corpus/swift/types/enum-with-cases.output | 8 ++--- ...separated-cases-chained-declaration.output | 14 ++++----- ...tion-type-with-convention-attribute.output | 2 +- ...nction-type-with-sendable-attribute.output | 2 +- .../property-with-getter-and-setter.output | 2 +- .../swift/types/protocol-declaration.output | 4 +-- ...nd-read-write-property-requirements.output | 2 +- .../corpus/swift/types/static-function.output | 2 +- .../multiple-bindings-on-one-line.output | 2 +- ...y-with-willset-and-didset-observers.output | 4 +-- unified/extractor/tests/location_tests.rs | 29 +++++++++++++++++++ 36 files changed, 171 insertions(+), 98 deletions(-) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index 16f6ddb9c937..fa917517f655 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -238,9 +238,10 @@ yeast::trees!(ctx, ### Source locations Captured nodes keep the locations assigned by their own translations. New -nodes in an output template derive their locations from their children. After -the transform completes, the matched input node's range is added only to -locally-created nodes returned as rule results: +nodes in an output template derive their locations from their children. A +source-less nested node receives an empty location at the start of the matched +input node. After the transform completes, the full matched range is added only +to locally-created nodes returned as rule results: ```rust rule!( @@ -251,10 +252,12 @@ rule!( ``` Here `inner` derives its range from `child`, while the returned `outer` node -also includes the full `wrapper` range. This lets replacement roots include -elided keywords or delimiters without assigning the same broad range to every -synthetic descendant. A transform that simply returns a translated capture -does not widen that capture to the wrapper's range. +also includes the full `wrapper` range. A nested node with no located children +would instead receive an empty range at the start of `wrapper`. This lets +replacement roots include elided keywords or delimiters without assigning the +same broad range to every synthetic descendant. A transform that simply +returns a translated capture does not widen that capture to the wrapper's +range. When the desired range belongs to another node, `tree_at!` assigns that range to the template's root. Nested nodes still derive their own locations normally: diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index 8a840f7cc784..6c08703ce0bf 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -37,7 +37,8 @@ pub struct BuildCtx<'a, C: 'a = ()> { /// /// The `rule!` macro applies this range to locally-created result roots /// after the transform completes. Nested synthetic nodes derive their - /// ranges from their children. + /// ranges from their children, falling back to an empty range at this + /// range's start. pub source_range: Option, /// User-supplied context, accessible directly via `ctx.field` (via Deref). pub user_ctx: &'a mut C, @@ -123,6 +124,16 @@ impl<'a, C> BuildCtx<'a, C> { let id = self .ast .create_node_with_range(kind, content, fields, is_named, source_range); + if self + .ast + .get_node(id) + .is_some_and(|node| node.source_range().is_none()) + { + if let Some(source_range) = self.source_range { + self.ast + .extend_source_range(id, source_range.empty_at_start()); + } + } if !has_explicit_source_range { self.created_nodes.insert(id); } @@ -137,6 +148,8 @@ impl<'a, C> BuildCtx<'a, C> { source_range: Option, ) -> Id { let has_explicit_source_range = source_range.is_some(); + let source_range = + source_range.or_else(|| self.source_range.map(|range| range.empty_at_start())); let id = self .ast .create_named_token_with_range(kind, content, source_range); diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 5a6536654394..a7e24a45366f 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -1709,6 +1709,34 @@ fn test_nested_synthetic_node_uses_child_location() { assert_eq!(arguments.byte_range(), 0..3); } +/// A nested node with no explicit range or located children gets an empty +/// location at the start of the rule's matched node. +#[test] +fn test_source_less_nested_node_uses_empty_match_start() { + let rule: Rule = rule!( + (call + method: (identifier) @name + receiver: (identifier) @recv + ) + => + (call + method: {name} + receiver: {recv} + arguments: (argument_list) + ) + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + let arguments = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "argument_list") + .expect("argument list exists"); + let range = arguments.source_range().unwrap(); + assert_eq!(range.start_byte..range.end_byte, 0..0); +} + /// An explicit empty range at byte zero is a real location, not the sentinel /// for an absent location, and therefore contributes to parent ranges. #[test] diff --git a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output index a8bd2282ef02..9e05ecaab626 100644 --- a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output +++ b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output @@ -46,6 +46,6 @@ top_level source="⟨body⟩" pattern: identifier "xs" source="xs" type: generic_type_expr source="[⟨type_argument⟩]" - base: identifier "Array" source= + base: identifier "Array" source="" type_argument: identifier "Int" source="Int" value: array_literal "[]" source="[]" diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index 9312e38adefc..c0140465e35e 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -42,18 +42,18 @@ top_level source="⟨body⟩" stmt: guard_if_stmt source="guard ⟨condition⟩ else ⟨else⟩" condition: - pattern_guard_expr source="let ⟨pattern⟩ = ⟨value⟩" + pattern_guard_expr source="⟨pattern⟩ = ⟨value⟩" pattern: call_expr source="⟨argument⟩" callee: - member_access_expr source= - base: identifier "Optional" source= - member_name_node: identifier "some" source= + member_access_expr source="" + base: identifier "Optional" source="" + member_name_node: identifier "some" source="" argument: argument source="⟨value⟩" value: - expr_pattern source="⟨expr⟩" - modifier: modifier "let" source= + expr_pattern source="let ⟨expr⟩" + modifier: modifier "let" source="" expr: identifier "value" source="value" value: identifier "optional" source="optional" else: diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index 09085763f268..e582bf0debd1 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -55,18 +55,18 @@ top_level source="⟨body⟩" stmt: if_expr source="if ⟨condition⟩ ⟨then⟩" condition: - pattern_guard_expr source="let ⟨pattern⟩ = ⟨value⟩" + pattern_guard_expr source="⟨pattern⟩ = ⟨value⟩" pattern: call_expr source="⟨argument⟩" callee: - member_access_expr source= - base: identifier "Optional" source= - member_name_node: identifier "some" source= + member_access_expr source="" + base: identifier "Optional" source="" + member_name_node: identifier "some" source="" argument: argument source="⟨value⟩" value: - expr_pattern source="⟨expr⟩" - modifier: modifier "let" source= + expr_pattern source="let ⟨expr⟩" + modifier: modifier "let" source="" expr: identifier "value" source="value" value: identifier "optional" source="optional" then: diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output index a0da0f15d1e6..8df5dec77cd2 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output @@ -344,29 +344,29 @@ top_level source="⟨body⟩" map_literal "[key: value]" source="[key: value]" call_expr source="⟨argument⟩?" callee: - member_access_expr source= - base: identifier "Optional" source= - member_name_node: identifier "some" source= + member_access_expr source="" + base: identifier "Optional" source="" + member_name_node: identifier "some" source="" argument: argument source="⟨value⟩" value: identifier "optional" source="optional" unary_expr source="try ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "try" source= + operator: prefix_operator "try" source="" unary_expr source="⟨operand⟩!" operand: identifier "value" source="value" - operator: postfix_operator "!" source= + operator: postfix_operator "!" source="" type_cast_expr source="⟨expr⟩ as ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "as" source= + operator: infix_operator "as" source="" type: identifier "Target" source="Target" type_test_expr source="⟨expr⟩ is ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "is" source= + operator: infix_operator "is" source="" type: identifier "Target" source="Target" unary_expr source="await ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "await" source= + operator: prefix_operator "await" source="" body: block source="⟨stmt⟩" stmt: diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index 51bb4af69e5b..2a53a68fa283 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -27,7 +27,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" + import_declaration source="⟨pattern⟩⟨imported_expr⟩" imported_expr: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: @@ -36,6 +36,6 @@ top_level source="⟨body⟩" member_name_node: identifier "Networking" source="Networking" member_name_node: identifier "URLSession" source="URLSession" pattern: - named_pattern source="⟨name_node⟩" + named_pattern source="import Foundation.Networking.⟨name_node⟩" name_node: identifier "URLSession" source="URLSession" - sub_pattern: bulk_importing_pattern source= + sub_pattern: bulk_importing_pattern source="" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index 462a807f0859..479cc68a7516 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -24,12 +24,12 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" + import_declaration source="⟨pattern⟩⟨imported_expr⟩" imported_expr: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: identifier "Foundation" source="Foundation" member_name_node: identifier "Networking" source="Networking" pattern: - named_pattern source="⟨name_node⟩" + named_pattern source="import Foundation.⟨name_node⟩" name_node: identifier "Networking" source="Networking" - sub_pattern: bulk_importing_pattern source= + sub_pattern: bulk_importing_pattern source="" diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index af9a65e04a90..9f87889dca84 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -21,9 +21,9 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - import_declaration source="import ⟨imported_expr⟩⟨pattern⟩" + import_declaration source="⟨pattern⟩⟨imported_expr⟩" imported_expr: identifier "Foundation" source="Foundation" pattern: - named_pattern source="⟨name_node⟩" + named_pattern source="import ⟨name_node⟩" name_node: identifier "Foundation" source="Foundation" - sub_pattern: bulk_importing_pattern source= + sub_pattern: bulk_importing_pattern source="" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index 06a7cb6fd7b5..15f599d3749b 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -132,10 +132,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "values" source="values" value: - call_expr source="[⟨callee⟩]()" + call_expr source="⟨callee⟩]()" callee: - generic_type_expr source="⟨type_argument⟩" - base: identifier "Array" source= + generic_type_expr source="[⟨type_argument⟩" + base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" @@ -144,10 +144,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "initialized" source="initialized" value: - call_expr source="[⟨callee⟩](⟨argument⟩) ⟨argument⟩" + call_expr source="⟨callee⟩](⟨argument⟩) ⟨argument⟩" callee: - generic_type_expr source="⟨type_argument⟩" - base: identifier "Array" source= + generic_type_expr source="[⟨type_argument⟩" + base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output index 91ec160cbf4a..066e65ccca00 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output @@ -56,10 +56,10 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "type" source="type" value: - member_access_expr source="[⟨base⟩].⟨member_name_node⟩" + member_access_expr source="⟨base⟩].⟨member_name_node⟩" base: - generic_type_expr source="⟨type_argument⟩" - base: identifier "Array" source= + generic_type_expr source="[⟨type_argument⟩" + base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" base: identifier "Result" source="Result" diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output index 2ef5fc67213e..71a5e020dc30 100644 --- a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output @@ -47,5 +47,5 @@ top_level source="⟨body⟩" stmt: function_declaration source="func ⟨name_node⟩() {}" name_node: identifier "doWork" source="doWork" - body: block source= + body: block source="" unsupported_node "unsafe doWork()" source="unsafe doWork()" diff --git a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output index 3531178c0f21..821aec63a98c 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output +++ b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output @@ -229,7 +229,7 @@ top_level source="⟨body⟩" element: string_literal "hello " source="hello " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩" value: identifier "name" source="name" @@ -238,13 +238,13 @@ top_level source="⟨body⟩" element: string_literal "hello " source="hello " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩" value: identifier "first" source="first" string_literal " " source=" " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩" value: identifier "last" source="last" @@ -253,7 +253,7 @@ top_level source="⟨body⟩" element: string_literal "result: " source="result: " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩" value: @@ -266,7 +266,7 @@ top_level source="⟨body⟩" element: string_literal "prefix " source="prefix " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩" value: identifier "value" source="value" @@ -275,7 +275,7 @@ top_level source="⟨body⟩" element: string_literal "foo " source="foo " call_expr source="\\(⟨argument⟩ ⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩," value: identifier "x" source="x" @@ -286,7 +286,7 @@ top_level source="⟨body⟩" element: string_literal "foo " source="foo " call_expr source="\\(⟨argument⟩ ⟨argument⟩ ⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨value⟩," value: identifier "x" source="x" @@ -299,7 +299,7 @@ top_level source="⟨body⟩" element: string_literal "foo " source="foo " call_expr source="\\(⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨name_node⟩: ⟨value⟩" name_node: identifier "arg" source="arg" @@ -309,7 +309,7 @@ top_level source="⟨body⟩" element: string_literal "foo " source="foo " call_expr source="\\(⟨argument⟩ ⟨argument⟩)" - callee: builtin_expr "interpolation" source= + callee: builtin_expr "interpolation" source="" argument: argument source="⟨name_node⟩: ⟨value⟩," name_node: identifier "arg" source="arg" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output index 8a7c088b4c1b..50185d37137d 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -148,7 +148,7 @@ top_level source="⟨body⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source= + operator: prefix_operator "try" source="" catch_clause: catch_clause source="catch ⟨pattern⟩ ⟨body⟩" pattern: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index cb91d71f311e..769c1c058939 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -69,7 +69,7 @@ top_level source="⟨body⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source= + operator: prefix_operator "try" source="" catch_clause: catch_clause source="catch ⟨body⟩" body: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output index 67f5fc5ee2c9..55198489b5ee 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output @@ -38,4 +38,4 @@ top_level source="⟨body⟩" value: unary_expr source="⟨operand⟩!" operand: identifier "opt" source="opt" - operator: postfix_operator "!" source= + operator: postfix_operator "!" source="" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output index 35b898deaedd..6e2b26b9678f 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-enum-case-binding.output @@ -82,9 +82,9 @@ top_level source="⟨body⟩" pattern: call_expr source="⟨argument⟩?" callee: - member_access_expr source= - base: identifier "Optional" source= - member_name_node: identifier "some" source= + member_access_expr source="" + base: identifier "Optional" source="" + member_name_node: identifier "some" source="" argument: argument source="⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output index ef0e79bc0e7d..ceb65bc91c9c 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output @@ -43,6 +43,6 @@ top_level source="⟨body⟩" pattern: identifier "x" source="x" type: generic_type_expr source="⟨type_argument⟩?" - base: identifier "Optional" source= + base: identifier "Optional" source="" type_argument: identifier "Int" source="Int" value: builtin_expr "nil" source="nil" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output index 4d7b105688c8..206923657a07 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output @@ -47,4 +47,4 @@ top_level source="⟨body⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try!" source= + operator: prefix_operator "try!" source="" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output index fdf08e347588..ef912781b16a 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output @@ -47,4 +47,4 @@ top_level source="⟨body⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try?" source= + operator: prefix_operator "try?" source="" diff --git a/unified/extractor/tests/corpus/swift/types/class-function.output b/unified/extractor/tests/corpus/swift/types/class-function.output index c161b663b50a..ab62ab362670 100644 --- a/unified/extractor/tests/corpus/swift/types/class-function.output +++ b/unified/extractor/tests/corpus/swift/types/class-function.output @@ -54,4 +54,4 @@ top_level source="⟨body⟩" function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" modifier: modifier "class" source="class" name_node: identifier "make" source="make" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index 5025163d5a2f..8c3e270e4d91 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -116,7 +116,7 @@ top_level source="⟨body⟩" accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨body⟩\n }" modifier: modifier "var" source="var" name_node: identifier "area" source="area" - accessor_kind: accessor_kind "get" source= + accessor_kind: accessor_kind "get" source="" type: identifier "Double" source="Double" body: block source="⟨stmt⟩" diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output index e6c32e55ff46..d424ddfc847d 100644 --- a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -78,4 +78,4 @@ top_level source="⟨body⟩" external_name_node: identifier "height" source="height" type: identifier "Int" source="Int" pattern: identifier "h" source="h" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index 0d80213f4eb9..18792a2b229e 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -73,23 +73,23 @@ top_level source="⟨body⟩" modifier: modifier "enum" source="enum" name_node: identifier "Shape" source="Shape" member: - class_like_declaration source="⟨name_node⟩(⟨member⟩)" - modifier: modifier "enum_case" source= + class_like_declaration source="⟨name_node⟩⟨member⟩)" + modifier: modifier "enum_case" source="" name_node: identifier "circle" source="circle" member: - constructor_declaration source="⟨parameter⟩" + constructor_declaration source="circle(⟨parameter⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" pattern: identifier "radius" source="radius" - body: block source= - class_like_declaration source="⟨name_node⟩(⟨member⟩)" - modifier: modifier "enum_case" source= + body: block source="" + class_like_declaration source="⟨name_node⟩⟨member⟩)" + modifier: modifier "enum_case" source="" name_node: identifier "square" source="square" member: - constructor_declaration source="⟨parameter⟩" + constructor_declaration source="square(⟨parameter⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" pattern: identifier "side" source="side" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output index 9fdf78ce054e..8b3fa7f85775 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output @@ -70,14 +70,14 @@ top_level source="⟨body⟩" name_node: identifier "Direction" source="Direction" member: variable_declaration source="⟨pattern⟩" - modifier: modifier "enum_case" source= + modifier: modifier "enum_case" source="" pattern: identifier "north" source="north" variable_declaration source="⟨pattern⟩" - modifier: modifier "enum_case" source= + modifier: modifier "enum_case" source="" pattern: identifier "south" source="south" variable_declaration source="⟨pattern⟩" - modifier: modifier "enum_case" source= + modifier: modifier "enum_case" source="" pattern: identifier "east" source="east" variable_declaration source="⟨pattern⟩" - modifier: modifier "enum_case" source= + modifier: modifier "enum_case" source="" pattern: identifier "west" source="west" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index cc2c30590e27..19146c2fb731 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -49,20 +49,20 @@ top_level source="⟨body⟩" name_node: identifier "Suit" source="Suit" member: variable_declaration source="⟨pattern⟩," - modifier: modifier "enum_case" source= + modifier: modifier "enum_case" source="" pattern: identifier "clubs" source="clubs" variable_declaration source="⟨pattern⟩," modifier: - modifier "chained_declaration" source= - modifier "enum_case" source= + modifier "chained_declaration" source="" + modifier "enum_case" source="" pattern: identifier "diamonds" source="diamonds" variable_declaration source="⟨pattern⟩," modifier: - modifier "chained_declaration" source= - modifier "enum_case" source= + modifier "chained_declaration" source="" + modifier "enum_case" source="" pattern: identifier "hearts" source="hearts" variable_declaration source="⟨pattern⟩" modifier: - modifier "chained_declaration" source= - modifier "enum_case" source= + modifier "chained_declaration" source="" + modifier "enum_case" source="" pattern: identifier "spades" source="spades" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output index 299c609c8022..39273b1056d0 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -68,4 +68,4 @@ top_level source="⟨body⟩" type: unsupported_node "@convention(c) () -> Void" source="@convention(c) () -> Void" value: function_expr source="{}" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output index 15eb240a8f64..9fbaf4167fd3 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -61,4 +61,4 @@ top_level source="⟨body⟩" type: unsupported_node "@Sendable () -> Void" source="@Sendable () -> Void" value: function_expr source="{}" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index f73a341020af..94d514f11cdb 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -129,7 +129,7 @@ top_level source="⟨body⟩" accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n get { return _v }\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source= + modifier "chained_declaration" source="" name_node: identifier "v" source="v" accessor_kind: accessor_kind "set" source="set" type: identifier "Int" source="Int" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output index 261e40a59f76..5f1155e278a8 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output @@ -63,8 +63,8 @@ top_level source="⟨body⟩" member: function_declaration source="func ⟨name_node⟩()" name_node: identifier "draw" source="draw" - body: block source= + body: block source="" function_declaration source="⟨modifier⟩ func ⟨name_node⟩()" modifier: modifier "static" source="static" name_node: identifier "make" source="make" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index d8efdbcc7bd0..0886939c1d94 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -119,7 +119,7 @@ top_level source="⟨body⟩" accessor_kind: accessor_kind "get" source="get" type: identifier "String" source="String" accessor_declaration source="⟨name_node⟩: ⟨type⟩ { get ⟨accessor_kind⟩" - modifier: modifier "chained_declaration" source= + modifier: modifier "chained_declaration" source="" name_node: identifier "bar" source="bar" accessor_kind: accessor_kind "set" source="set" type: identifier "String" source="String" diff --git a/unified/extractor/tests/corpus/swift/types/static-function.output b/unified/extractor/tests/corpus/swift/types/static-function.output index 0c66ba1c251b..210bb2909449 100644 --- a/unified/extractor/tests/corpus/swift/types/static-function.output +++ b/unified/extractor/tests/corpus/swift/types/static-function.output @@ -54,4 +54,4 @@ top_level source="⟨body⟩" function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" modifier: modifier "static" source="static" name_node: identifier "make" source="make" - body: block source= + body: block source="" diff --git a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output index 7666b6d7dedb..07797954fc8d 100644 --- a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output +++ b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output @@ -47,6 +47,6 @@ top_level source="⟨body⟩" variable_declaration source="⟨modifier⟩ x = 1, ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" - modifier "chained_declaration" source= + modifier "chained_declaration" source="" pattern: identifier "y" source="y" value: int_literal "2" source="2" diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 7f9576a0c1b5..4670fd83b1d5 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -113,7 +113,7 @@ top_level source="⟨body⟩" accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source= + modifier "chained_declaration" source="" name_node: identifier "x" source="x" accessor_kind: accessor_kind "willSet" source="willSet" body: @@ -127,7 +127,7 @@ top_level source="⟨body⟩" accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n willSet { print(newValue) }\n ⟨accessor_kind⟩ ⟨body⟩" modifier: modifier "var" source="var" - modifier "chained_declaration" source= + modifier "chained_declaration" source="" name_node: identifier "x" source="x" accessor_kind: accessor_kind "didSet" source="didSet" body: diff --git a/unified/extractor/tests/location_tests.rs b/unified/extractor/tests/location_tests.rs index 08cec5643244..9380ff7442e8 100644 --- a/unified/extractor/tests/location_tests.rs +++ b/unified/extractor/tests/location_tests.rs @@ -51,6 +51,16 @@ fn assert_has_span(ast: &Ast, source: &str, kind: &str, content: Option<&str>, e ); } +fn assert_has_empty_span(ast: &Ast, kind: &str, content: Option<&str>, expected_offset: usize) { + let ranges = ranges(ast, kind, content); + assert!( + ranges + .iter() + .any(|range| range.start == expected_offset && range.end == expected_offset), + "expected {kind} {content:?} to have an empty span at {expected_offset}, got {ranges:?}" + ); +} + #[test] fn generic_type_children_have_local_ranges() { let source = "let x = C()"; @@ -61,6 +71,25 @@ fn generic_type_children_have_local_ranges() { assert_has_span(&ast, source, "identifier", Some("Foo"), "Foo"); } +#[test] +fn synthetic_type_and_modifier_nodes_use_empty_scope_start_ranges() { + let source = "let array: [T]\nlet optional: T?\nenum E { case a, b }"; + let ast = desugar(source); + + assert_has_empty_span(&ast, "identifier", Some("Array"), source.find('[').unwrap()); + assert_has_empty_span( + &ast, + "identifier", + Some("Optional"), + source.find("T?").unwrap(), + ); + let case_a = source.find("a, b").unwrap(); + let case_b = case_a + "a, ".len(); + assert_has_empty_span(&ast, "modifier", Some("enum_case"), case_a); + assert_has_empty_span(&ast, "modifier", Some("enum_case"), case_b); + assert_has_empty_span(&ast, "modifier", Some("chained_declaration"), case_b); +} + #[test] fn import_member_chain_excludes_import_keyword() { let source = "import Foundation.Networking.URLSession"; From 0bf705a17faa433c416a04ab9d9a53ab5d8537ea Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 11 Sep 2026 14:58:55 +0000 Subject: [PATCH 05/14] Unified: Add locations for blocks Blocks are slightly awkward, since we destructure them (as codeBlock) in the query, and then reconstruct them (as `block`) in the rule body, meaning the location of the block is (by default) assigned to the wrong place by the heuristic. To get around this, I added a helper function that updates the location appropriately, including handling cases where we only optionally match a block. (Also, in some cases we can fix this by just not destructuring `codeBlock`s in the first place -- there's already a rule that maps `codeBlock` to `block`.) --- .../extractor/src/languages/swift/swift.rs | 46 ++++++++++++++----- .../closures/closure-with-capture-list.output | 4 +- .../closure-with-explicit-parameters.output | 4 +- .../closure-with-shorthand-parameters.output | 4 +- .../closures/multi-statement-closure.output | 4 +- .../swift/closures/trailing-closure.output | 4 +- .../swift/control-flow/defer-statement.output | 4 +- .../control-flow/discard-statement.output | 4 +- .../swift/control-flow/fallthrough.output | 4 +- .../expressions/array-type-constructor.output | 4 +- .../swift/expressions/super-expression.output | 8 ++-- .../expressions/unsafe-expression.output | 4 +- ...nction-with-default-parameter-value.output | 4 +- .../function-with-inout-parameter.output | 4 +- .../function-with-named-parameters.output | 4 +- .../function-with-no-parameters.output | 4 +- ...ion-with-parameters-and-return-type.output | 4 +- .../swift/functions/generic-function.output | 4 +- .../swift/functions/variadic-function.output | 4 +- ...solved-operator-sequence-with-casts.output | 4 +- ...lved-operator-sequence-with-ternary.output | 4 +- .../unresolved-operator-sequence.output | 4 +- .../throwing-function.output | 4 +- .../corpus/swift/types/class-function.output | 4 +- .../swift/types/class-with-initializer.output | 4 +- .../swift/types/class-with-method.output | 4 +- .../swift/types/computed-property.output | 4 +- .../types/constructor-with-parameters.output | 4 +- .../tests/corpus/swift/types/extension.output | 4 +- ...tion-type-with-convention-attribute.output | 4 +- ...nction-type-with-sendable-attribute.output | 4 +- .../corpus/swift/types/static-function.output | 4 +- unified/extractor/tests/location_tests.rs | 9 ++++ 33 files changed, 107 insertions(+), 76 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 4bcdce18595b..9105b96573f9 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,5 +1,5 @@ use codeql_extractor::extractor::desugaring; -use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree}; +use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at}; /// User context propagated from outer rules down to the inner rules that /// emit the corresponding output declarations, so that each emitted node @@ -60,6 +60,17 @@ impl SwiftContext { } } +fn block_with_anchor( + ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, + statements: Vec, + anchor: Option, +) -> yeast::Id { + match anchor { + Some(anchor) => tree_at!(ctx, anchor, (block stmt: {statements})), + None => tree!(ctx, (block stmt: {statements})), + } +} + /// Build a freshly-created `chained_declaration` modifier node if /// `ctx.is_chained`, else `None`. Used by inner declaration rules to /// emit the chained tag for non-first children of a flattening outer @@ -298,14 +309,14 @@ fn translation_rules() -> Vec> { bindings: (patternBinding pattern: (identifierPattern identifier: @@name) typeAnnotation: (typeAnnotation type: @ty) - accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body))) + accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body) @@accessor_block)) => (accessor_declaration modifier: (modifier #{spec}) name_node: (identifier #{name}) type: {ty} - accessor_kind: (accessor_kind "get") - body: (block stmt: {body})) + accessor_kind: {ctx.literal_at_start_of("accessor_kind", "get", accessor_block)} + body: {block_with_anchor(&mut ctx, body, Some(accessor_block))}) ), // A property with an explicit accessor block. swift-syntax makes both // shapes plain `accessorDecl`s, so they are told apart by the presence @@ -561,7 +572,7 @@ fn translation_rules() -> Vec> { signature: (functionSignature parameterClause: (functionParameterClause parameters: _* @params) returnClause: (returnClause type: @ret)?) - body: (codeBlock statements: _* @body)) + body: (codeBlock) @body) => (function_declaration modifier: {mods} @@ -569,7 +580,7 @@ fn translation_rules() -> Vec> { type_parameter: {type_params} parameter: {params} return_type: {ret} - body: (block stmt: {body})) + body: {body}) ), rule!( (functionDecl @@ -749,14 +760,14 @@ fn translation_rules() -> Vec> { capture: (closureCaptureClause items: _* @captures)? parameterClause: _* @params returnClause: (returnClause type: @ret)?)? - statements: _* @body) + statements: _* @body) @@closure => (function_expr modifier: {attrs} capture_declaration: {captures} parameter: {params} return_type: {ret} - body: (block stmt: {body})) + body: {block_with_anchor(&mut ctx, body, Some(closure))}) ), // A closure capture (`[weak self]`, `[x]`, `[y = expr]`). The optional // ownership specifier (`weak`/`unowned`) becomes a modifier; the @@ -1278,23 +1289,34 @@ fn translation_rules() -> Vec> { modifiers: _* @mods signature: (functionSignature parameterClause: (functionParameterClause parameters: _* @params)) - body: (codeBlock statements: _* @body_stmts)?) + body: (codeBlock) @body) => (constructor_declaration modifier: {mods} name_node: (identifier #{initK}) parameter: {params} - body: (block stmt: {body_stmts})) + body: {body}) + ), + rule!( + (initializerDecl + modifiers: _* @mods + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params))) + => + (constructor_declaration + modifier: {mods} + parameter: {params} + body: (block)) ), // Deinit declaration → destructor_declaration. Body statements optional. rule!( (deinitializerDecl modifiers: _* @mods - body: (codeBlock statements: _* @body_stmts)) + body: (codeBlock) @body) => (destructor_declaration modifier: {mods} - body: (block stmt: {body_stmts})) + body: {body}) ), // Typealias declaration rule!( diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output index a2b19c5503a7..1e28176add2b 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output @@ -68,13 +68,13 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="{ [⟨capture_declaration⟩] in ⟨body⟩ }" + function_expr source="⟨body⟩⟨capture_declaration⟩" capture_declaration: variable_declaration source="⟨modifier⟩ ⟨pattern⟩" modifier: modifier "weak" source="weak" pattern: identifier "self" source="self" body: - block source="⟨stmt⟩" + block source="{ [weak self] in ⟨stmt⟩ }" stmt: call_expr source="⟨callee⟩()" callee: diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output index 786e7d7fb4ee..a44783d172d1 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output @@ -70,14 +70,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="{ (⟨parameter⟩) -> ⟨return_type⟩ in ⟨body⟩ }" + function_expr source="⟨body⟩⟨parameter⟩⟨return_type⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩" + block source="{ (x: Int) -> Int in ⟨stmt⟩ }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output index 3e30fac78c01..6de0b9bea57c 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output @@ -47,9 +47,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="{ ⟨body⟩ }" + function_expr source="⟨body⟩" body: - block source="⟨stmt⟩" + block source="{ ⟨stmt⟩ }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "$0" source="$0" diff --git a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output index f9c054aa0b96..36649bd5ac0d 100644 --- a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output @@ -101,14 +101,14 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "f" source="f" value: - function_expr source="{ (⟨parameter⟩) -> ⟨return_type⟩ in\n ⟨body⟩\n}" + function_expr source="⟨body⟩⟨parameter⟩⟨return_type⟩" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩\n ⟨stmt⟩" + block source="{ (x: Int) -> Int in\n ⟨stmt⟩\n ⟨stmt⟩\n}" stmt: variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" diff --git a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output index c50bbde02dcc..ad76f9b9abee 100644 --- a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output @@ -51,9 +51,9 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: - function_expr source="{ ⟨body⟩ }" + function_expr source="⟨body⟩" body: - block source="⟨stmt⟩" + block source="{ ⟨stmt⟩ }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "$0" source="$0" diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output index ba856ea604f4..37d29a427dbe 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output @@ -79,10 +79,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩() ⟨body⟩" name_node: identifier "withCleanup" source="withCleanup" body: - block source="⟨stmt⟩\n ⟨stmt⟩" + block source="{\n ⟨stmt⟩\n ⟨stmt⟩\n}" stmt: unsupported_node "defer { print(\"cleanup\") }" source="defer { print(\"cleanup\") }" call_expr source="⟨callee⟩(⟨argument⟩)" diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output index 3e3a36d98330..df6bb28eb01b 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output @@ -74,9 +74,9 @@ top_level source="⟨body⟩" base_type source="⟨type⟩" type: unsupported_node "~Copyable" source="~Copyable" member: - function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {\n ⟨body⟩\n }" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() ⟨body⟩" modifier: modifier "consuming" source="consuming" name_node: identifier "close" source="close" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n }" stmt: unsupported_node "discard self" source="discard self" diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output index 03ed5d1acc38..080c3b0089d3 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output @@ -86,7 +86,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) ⟨body⟩" name_node: identifier "classify" source="classify" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -94,7 +94,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: switch_expr source="switch ⟨value⟩ {\n ⟨case⟩\n ⟨case⟩\n }" value: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index 15f599d3749b..23df62e6a6d7 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -158,14 +158,14 @@ top_level source="⟨body⟩" value: int_literal "1" source="1" argument source="⟨value⟩" value: - function_expr source="{ ⟨parameter⟩ ⟨parameter⟩ in\n\t⟨body⟩\n}" + function_expr source="⟨body⟩⟨parameter⟩⟨parameter⟩" parameter: parameter source="⟨pattern⟩," pattern: identifier "_" source="_" parameter source="⟨pattern⟩" pattern: identifier "count" source="count" body: - block source="⟨stmt⟩" + block source="{ _, count in\n\t⟨stmt⟩\n}" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "count" source="count" diff --git a/unified/extractor/tests/corpus/swift/expressions/super-expression.output b/unified/extractor/tests/corpus/swift/expressions/super-expression.output index 85aa721365cf..8b7da208df1d 100644 --- a/unified/extractor/tests/corpus/swift/expressions/super-expression.output +++ b/unified/extractor/tests/corpus/swift/expressions/super-expression.output @@ -154,9 +154,9 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "value" source="value" value: int_literal "0" source="0" - function_declaration source="func ⟨name_node⟩() {}" + function_declaration source="func ⟨name_node⟩() ⟨body⟩" name_node: identifier "update" source="update" - body: block source= + body: block "{}" source="{}" class_like_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨base_type⟩ {\n ⟨member⟩\n}" modifier: modifier "class" source="class" name_node: identifier "Derived" source="Derived" @@ -164,11 +164,11 @@ top_level source="⟨body⟩" base_type source="⟨type⟩" type: identifier "Base" source="Base" member: - function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {\n ⟨body⟩\n }" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() ⟨body⟩" modifier: modifier "override" source="override" name_node: identifier "update" source="update" body: - block source="⟨stmt⟩\n ⟨stmt⟩" + block source="{\n ⟨stmt⟩\n ⟨stmt⟩\n }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "_" source="_" diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output index 71a5e020dc30..427b4503f8ad 100644 --- a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output @@ -45,7 +45,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩\n⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩() {}" + function_declaration source="func ⟨name_node⟩() ⟨body⟩" name_node: identifier "doWork" source="doWork" - body: block source="" + body: block "{}" source="{}" unsupported_node "unsafe doWork()" source="unsafe doWork()" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index 8cc7fb0a5f81..76455bed5f27 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -65,7 +65,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) ⟨body⟩" name_node: identifier "greet" source="greet" parameter: parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩ = ⟨default⟩" @@ -74,7 +74,7 @@ top_level source="⟨body⟩" pattern: identifier "name" source="name" default: string_literal "\"world\"" source="\"world\"" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output index e44356fe9606..2cb14ccacbb2 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -61,7 +61,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) ⟨body⟩" name_node: identifier "increment" source="increment" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -69,7 +69,7 @@ top_level source="⟨body⟩" type: unsupported_node "inout Int" source="inout Int" pattern: identifier "x" source="x" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index 632da0f8efc6..878581f34212 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -56,7 +56,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) ⟨body⟩" name_node: identifier "greet" source="greet" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" @@ -64,7 +64,7 @@ top_level source="⟨body⟩" type: identifier "String" source="String" pattern: identifier "name" source="name" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output index b555273112d9..738cba0116ac 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output @@ -51,10 +51,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩() ⟨body⟩" name_node: identifier "greet" source="greet" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "print" source="print" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index 6d4d1c903a71..fcac6c8c2843 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -73,7 +73,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "add" source="add" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -86,7 +86,7 @@ top_level source="⟨body⟩" pattern: identifier "b" source="b" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index ba87c47a7b4f..5c70307c6323 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -63,7 +63,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩<⟨type_parameter⟩>(⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩<⟨type_parameter⟩>(⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "identity" source="identity" type_parameter: type_parameter source="⟨name_node⟩" @@ -75,7 +75,7 @@ top_level source="⟨body⟩" pattern: identifier "x" source="x" return_type: identifier "T" source="T" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: return_expr source="return ⟨value⟩" value: identifier "x" source="x" diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index da0c84c07d74..9b48167deb9c 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -77,7 +77,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "sum" source="sum" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩..." @@ -86,7 +86,7 @@ top_level source="⟨body⟩" pattern: identifier "values" source="values" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output index f0bb8aefa70c..92ad43c34164 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -93,7 +93,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" name_node: identifier "casts" source="casts" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -105,7 +105,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "b" source="b" body: - block source="⟨stmt⟩\n ⟨stmt⟩" + block source="{\n ⟨stmt⟩\n ⟨stmt⟩\n}" stmt: unresolved_operator_sequence source="⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩" element: diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output index 4b7d12ff3420..42f184e76b15 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -99,7 +99,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "choose" source="choose" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -120,7 +120,7 @@ top_level source="⟨body⟩" pattern: identifier "d" source="d" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output index 846ab17caac4..28953b21acc5 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -66,7 +66,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" name_node: identifier "combine" source="combine" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -78,7 +78,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "b" source="b" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: unresolved_operator_sequence source="⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩ ⟨element⟩" element: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output index 1d080dbeefa6..6e6cc3b99e18 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output @@ -55,11 +55,11 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩() throws -> ⟨return_type⟩ {\n ⟨body⟩\n}" + function_declaration source="func ⟨name_node⟩() throws -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "read" source="read" return_type: identifier "String" source="String" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n}" stmt: return_expr source="return ⟨value⟩" value: string_literal "\"\"" source="\"\"" diff --git a/unified/extractor/tests/corpus/swift/types/class-function.output b/unified/extractor/tests/corpus/swift/types/class-function.output index ab62ab362670..9b3770561a37 100644 --- a/unified/extractor/tests/corpus/swift/types/class-function.output +++ b/unified/extractor/tests/corpus/swift/types/class-function.output @@ -51,7 +51,7 @@ top_level source="⟨body⟩" modifier: modifier "class" source="class" name_node: identifier "Factory" source="Factory" member: - function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() ⟨body⟩" modifier: modifier "class" source="class" name_node: identifier "make" source="make" - body: block source="" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index c5eb62255469..b2141c5bb6e3 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -98,7 +98,7 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "x" source="x" type: identifier "Int" source="Int" - constructor_declaration source="⟨name_node⟩(⟨parameter⟩) {\n ⟨body⟩\n }" + constructor_declaration source="⟨name_node⟩(⟨parameter⟩) ⟨body⟩" name_node: identifier "init" source="init" parameter: parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩" @@ -106,7 +106,7 @@ top_level source="⟨body⟩" type: identifier "Int" source="Int" pattern: identifier "x" source="x" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index 7d181dae78d2..8752f5c37a50 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -85,10 +85,10 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "n" source="n" value: int_literal "0" source="0" - function_declaration source="func ⟨name_node⟩() {\n ⟨body⟩\n }" + function_declaration source="func ⟨name_node⟩() ⟨body⟩" name_node: identifier "bump" source="bump" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n }" stmt: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "n" source="n" diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index 8c3e270e4d91..a88f7a20956d 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -113,13 +113,13 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "h" source="h" type: identifier "Double" source="Double" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨body⟩\n }" + accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ ⟨body⟩" modifier: modifier "var" source="var" name_node: identifier "area" source="area" accessor_kind: accessor_kind "get" source="" type: identifier "Double" source="Double" body: - block source="⟨stmt⟩" + block source="{\n ⟨stmt⟩\n }" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output index d424ddfc847d..181fcef50313 100644 --- a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -67,7 +67,7 @@ top_level source="⟨body⟩" modifier: modifier "struct" source="struct" name_node: identifier "Size" source="Size" member: - constructor_declaration source="⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) {}" + constructor_declaration source="⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" name_node: identifier "init" source="init" parameter: parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," @@ -78,4 +78,4 @@ top_level source="⟨body⟩" external_name_node: identifier "height" source="height" type: identifier "Int" source="Int" pattern: identifier "h" source="h" - body: block source="" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/corpus/swift/types/extension.output b/unified/extractor/tests/corpus/swift/types/extension.output index d1358e2f2f17..2830565acf9a 100644 --- a/unified/extractor/tests/corpus/swift/types/extension.output +++ b/unified/extractor/tests/corpus/swift/types/extension.output @@ -72,11 +72,11 @@ top_level source="⟨body⟩" modifier: modifier "extension" source="extension" extension_target: identifier "Int" source="Int" member: - function_declaration source="func ⟨name_node⟩() -> ⟨return_type⟩ { ⟨body⟩ }" + function_declaration source="func ⟨name_node⟩() -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "squared" source="squared" return_type: identifier "Int" source="Int" body: - block source="⟨stmt⟩" + block source="{ ⟨stmt⟩ }" stmt: return_expr source="return ⟨value⟩" value: diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output index 39273b1056d0..e26e022261f4 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -67,5 +67,5 @@ top_level source="⟨body⟩" pattern: identifier "callback" source="callback" type: unsupported_node "@convention(c) () -> Void" source="@convention(c) () -> Void" value: - function_expr source="{}" - body: block source="" + function_expr source="⟨body⟩" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output index 9fbaf4167fd3..3d4a80ebea18 100644 --- a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -60,5 +60,5 @@ top_level source="⟨body⟩" pattern: identifier "handler" source="handler" type: unsupported_node "@Sendable () -> Void" source="@Sendable () -> Void" value: - function_expr source="{}" - body: block source="" + function_expr source="⟨body⟩" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/corpus/swift/types/static-function.output b/unified/extractor/tests/corpus/swift/types/static-function.output index 210bb2909449..0f27333bac05 100644 --- a/unified/extractor/tests/corpus/swift/types/static-function.output +++ b/unified/extractor/tests/corpus/swift/types/static-function.output @@ -51,7 +51,7 @@ top_level source="⟨body⟩" modifier: modifier "class" source="class" name_node: identifier "Factory" source="Factory" member: - function_declaration source="⟨modifier⟩ func ⟨name_node⟩() {}" + function_declaration source="⟨modifier⟩ func ⟨name_node⟩() ⟨body⟩" modifier: modifier "static" source="static" name_node: identifier "make" source="make" - body: block source="" + body: block "{}" source="{}" diff --git a/unified/extractor/tests/location_tests.rs b/unified/extractor/tests/location_tests.rs index 9380ff7442e8..ffa6062a46d9 100644 --- a/unified/extractor/tests/location_tests.rs +++ b/unified/extractor/tests/location_tests.rs @@ -71,6 +71,15 @@ fn generic_type_children_have_local_ranges() { assert_has_span(&ast, source, "identifier", Some("Foo"), "Foo"); } +#[test] +fn declaration_and_operator_tokens_keep_precise_ranges() { + let source = "func f() { return x }"; + let ast = desugar(source); + + assert_has_span(&ast, source, "block", None, "{ return x }"); + assert_has_span(&ast, source, "return_expr", None, "return x"); +} + #[test] fn synthetic_type_and_modifier_nodes_use_empty_scope_start_ranges() { let source = "let array: [T]\nlet optional: T?\nenum E { case a, b }"; From c953ebd3b84a317f16c737f8038e367a331cacef Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 11 Sep 2026 15:30:46 +0000 Subject: [PATCH 06/14] Unified: Fix locations of various tokens Handles things like `try!` (which is represented as two separate tokens -- we explicitly union their ranges) and "let" binding modifiers (where we reuse the bindingSpecifier, getting its location and string value for free). --- .../extractor/src/languages/swift/swift.rs | 97 ++++++++++++++----- .../swift/control-flow/guard-let.output | 4 +- .../if-let-optional-binding.output | 4 +- .../nested-enum-case-pattern.output | 4 +- .../switch-expression-pattern.output | 20 ++-- ...with-deeply-nested-path-three-parts.output | 4 +- .../import-with-dotted-path-two-parts.output | 4 +- .../simple-import-with-single-name.output | 4 +- .../catch-where-clauses.output | 4 +- .../optionals-and-errors/do-catch.output | 4 +- .../optionals-and-errors/force-unwrap.output | 4 +- .../try-expression-2.output | 4 +- .../try-expression.output | 4 +- .../types/enum-with-associated-values.output | 8 +- unified/extractor/tests/location_tests.rs | 52 +++++++++- 15 files changed, 158 insertions(+), 63 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 9105b96573f9..f310cc5802f4 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,5 +1,7 @@ use codeql_extractor::extractor::desugaring; -use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at}; +use yeast::{ + ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree, tree_at, tree_spanning, +}; /// User context propagated from outer rules down to the inner rules that /// emit the corresponding output declarations, so that each emitted node @@ -97,7 +99,9 @@ fn and_chain( conds .into_iter() .reduce(|acc, elem| { - tree!((binary_expr operator: (infix_operator "&&") left: {acc} right: {elem})) + let operator_range = ctx.empty_source_range_between(acc, elem); + let operator = ctx.literal_with_source_range("infix_operator", "&&", operator_range); + tree!((binary_expr operator: {operator} left: {acc} right: {elem})) }) .expect("control-flow statement must have at least one condition") } @@ -474,14 +478,24 @@ fn translation_rules() -> Vec> { // `enumCaseDecl` rule below) and are tagged `enum_case`, after any // `chained_declaration` tag. rule!( - (enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params)) - => - (class_like_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - modifier: (modifier "enum_case") - name_node: (identifier #{name}) - member: (constructor_declaration parameter: {params} body: (block))) + (enumCaseElement + name: @name + parameterClause: (enumCaseParameterClause parameters: _* @params)) @@element + => + class_like_declaration { + let body = tree!((block)); + let constructor = tree_at!( + ctx, + element, + (constructor_declaration parameter: {params} body: {body}) + ); + tree!((class_like_declaration + modifier: {ctx.outer_modifiers.clone()} + modifier: {chained_modifier(&mut ctx)} + modifier: (modifier "enum_case") + name_node: (identifier #{name}) + member: {constructor})) + } ), rule!( (enumCaseElement name: @name rawValue: (initializerClause value: @val)) @@ -686,12 +700,17 @@ fn translation_rules() -> Vec> { label: _? @@lbl expression: (functionCallExpr calledExpression: @constructor - arguments: _* @elements)) + arguments: _* @elements) @@call) => argument { + let value = tree_at!( + ctx, + call, + (call_expr callee: {constructor} argument: {elements}) + ); tree!((argument name_node: (identifier #{lbl})? - value: (call_expr callee: {constructor} argument: {elements}))) + value: {value})) } ), rule!( @@ -864,6 +883,7 @@ fn translation_rules() -> Vec> { // form is matched first. rule!( (optionalBindingCondition + bindingSpecifier: @@spec pattern: (identifierPattern identifier: @name) initializer: (initializerClause value: @val)) => @@ -872,18 +892,20 @@ fn translation_rules() -> Vec> { pattern: (call_expr callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some")) argument: (argument value: (expr_pattern - modifier: (modifier "let") + modifier: (modifier #{spec}) expr: (identifier #{name}))))) ), rule!( - (optionalBindingCondition pattern: (identifierPattern identifier: @name)) + (optionalBindingCondition + bindingSpecifier: @@spec + pattern: (identifierPattern identifier: @name)) => (pattern_guard_expr value: (identifier #{name}) pattern: (call_expr callee: (member_access_expr base: (identifier "Optional") member_name_node: (identifier "some")) argument: (argument value: (expr_pattern - modifier: (modifier "let") + modifier: (modifier #{spec}) expr: (identifier #{name}))))) ), // A single condition in an `if`/`while`/`guard` condition list unwraps to @@ -967,11 +989,19 @@ fn translation_rules() -> Vec> { }), // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!" rule!( - (tryExpr questionOrExclamationMark: _? @@m expression: @e) + (tryExpr + tryKeyword: @@keyword + questionOrExclamationMark: _? @@m + expression: @e) => expr { let op = format!("try{}", m.map(|m| ctx.source_text(m)).unwrap_or_default()); - tree!((unary_expr operator: (prefix_operator #{op}) operand: {e})) + let operator = tree_spanning!( + ctx, + std::iter::once(keyword).chain(m), + (prefix_operator #{op}) + ); + tree!((unary_expr operator: {operator} operand: {e})) } ), // Do-catch → try_expr @@ -1005,17 +1035,29 @@ fn translation_rules() -> Vec> { // Catch block without error binding rule!((catchClause body: @body) => (catch_clause body: {body})), // As expression (type cast) — as?, as! - rule!((asExpr expression: @val questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr { + rule!((asExpr expression: @val asKeyword: @@keyword questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr { let op = format!("as{}", mark.map(|m| ctx.source_text(m)).unwrap_or_default()); - tree!((type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})) + let operator = tree_spanning!( + ctx, + std::iter::once(keyword).chain(mark), + (infix_operator #{op}) + ); + tree!((type_cast_expr expr: {val} operator: {operator} type: {ty})) }), // Check expression (`x is T`) → type_test_expr - rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})), + rule!((isExpr expression: @val isKeyword: @@keyword type: @ty) => (type_test_expr + expr: {val} + operator: {tree_at!(ctx, keyword, (infix_operator "is"))} + type: {ty})), // Await expression → unary_expr with operator "await" - rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), + rule!((awaitExpr awaitKeyword: @@keyword expression: @val) => (unary_expr + operator: {tree_at!(ctx, keyword, (prefix_operator "await"))} + operand: {val})), // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated // `forceUnwrapExpr` node. - rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})), + rule!((forceUnwrapExpr expression: @e exclamationMark: @@mark) => (unary_expr + operator: {tree_at!(ctx, mark, (postfix_operator "!"))} + operand: {e})), // ---- Imports ---- // An import declaration. The dotted path (a list of // `importPathComponent`s) becomes a `name_node`/`member_access_expr` @@ -1030,14 +1072,17 @@ fn translation_rules() -> Vec> { attributes: _* @attrs modifiers: _* @mods importKindSpecifier: _? @@kind - path: (importPathComponent name: @@parts)*) + path: (importPathComponent name: @@parts)*) @@decl => import_declaration { let last = *parts.last().ok_or("import has no path")?; let pattern = match kind { - None => tree!((named_pattern - name_node: (identifier #{last}) - sub_pattern: (bulk_importing_pattern))), + None => { + let bulk = tree_at!(ctx, decl, (bulk_importing_pattern)); + tree!((named_pattern + name_node: (identifier #{last}) + sub_pattern: {bulk})) + } Some(_) => tree!((identifier #{last})), }; tree!((import_declaration diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index c0140465e35e..5d12fd0a7ea4 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -52,8 +52,8 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: - expr_pattern source="let ⟨expr⟩" - modifier: modifier "let" source="" + expr_pattern source="⟨modifier⟩ ⟨expr⟩" + modifier: modifier "let" source="let" expr: identifier "value" source="value" value: identifier "optional" source="optional" else: diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index e582bf0debd1..097e721e5d40 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -65,8 +65,8 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: - expr_pattern source="let ⟨expr⟩" - modifier: modifier "let" source="" + expr_pattern source="⟨modifier⟩ ⟨expr⟩" + modifier: modifier "let" source="let" expr: identifier "value" source="value" value: identifier "optional" source="optional" then: diff --git a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output index d8cea8bdf335..4a6c67739d9d 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output @@ -173,9 +173,9 @@ top_level source="⟨body⟩" base: inferred_type_expr "." source="." member_name_node: identifier "received" source="received" argument: - argument source="⟨value⟩)," + argument source="⟨value⟩," value: - call_expr source="⟨callee⟩(⟨argument⟩" + call_expr source="⟨callee⟩(⟨argument⟩)" callee: member_access_expr source="⟨base⟩⟨member_name_node⟩" base: inferred_type_expr "." source="." diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output index 8df5dec77cd2..6ff524b63160 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output @@ -350,23 +350,23 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: identifier "optional" source="optional" - unary_expr source="try ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "try" source="" - unary_expr source="⟨operand⟩!" + operator: prefix_operator "try" source="try" + unary_expr source="⟨operand⟩⟨operator⟩" operand: identifier "value" source="value" - operator: postfix_operator "!" source="" - type_cast_expr source="⟨expr⟩ as ⟨type⟩" + operator: postfix_operator "!" source="!" + type_cast_expr source="⟨expr⟩ ⟨operator⟩ ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "as" source="" + operator: infix_operator "as" source="as" type: identifier "Target" source="Target" - type_test_expr source="⟨expr⟩ is ⟨type⟩" + type_test_expr source="⟨expr⟩ ⟨operator⟩ ⟨type⟩" expr: identifier "value" source="value" - operator: infix_operator "is" source="" + operator: infix_operator "is" source="is" type: identifier "Target" source="Target" - unary_expr source="await ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: identifier "value" source="value" - operator: prefix_operator "await" source="" + operator: prefix_operator "await" source="await" body: block source="⟨stmt⟩" stmt: diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index 2a53a68fa283..a35890d96301 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -36,6 +36,6 @@ top_level source="⟨body⟩" member_name_node: identifier "Networking" source="Networking" member_name_node: identifier "URLSession" source="URLSession" pattern: - named_pattern source="import Foundation.Networking.⟨name_node⟩" + named_pattern source="⟨sub_pattern⟩⟨name_node⟩" name_node: identifier "URLSession" source="URLSession" - sub_pattern: bulk_importing_pattern source="" + sub_pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" source="import Foundation.Networking.URLSession" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index 479cc68a7516..3f069a347481 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -30,6 +30,6 @@ top_level source="⟨body⟩" base: identifier "Foundation" source="Foundation" member_name_node: identifier "Networking" source="Networking" pattern: - named_pattern source="import Foundation.⟨name_node⟩" + named_pattern source="⟨sub_pattern⟩⟨name_node⟩" name_node: identifier "Networking" source="Networking" - sub_pattern: bulk_importing_pattern source="" + sub_pattern: bulk_importing_pattern "import Foundation.Networking" source="import Foundation.Networking" diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index 9f87889dca84..d52673da8dda 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -24,6 +24,6 @@ top_level source="⟨body⟩" import_declaration source="⟨pattern⟩⟨imported_expr⟩" imported_expr: identifier "Foundation" source="Foundation" pattern: - named_pattern source="import ⟨name_node⟩" + named_pattern source="⟨sub_pattern⟩⟨name_node⟩" name_node: identifier "Foundation" source="Foundation" - sub_pattern: bulk_importing_pattern source="" + sub_pattern: bulk_importing_pattern "import Foundation" source="import Foundation" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output index 50185d37137d..d83a29460e61 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -144,11 +144,11 @@ top_level source="⟨body⟩" body: block source="{\n ⟨stmt⟩\n}" stmt: - unary_expr source="try ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source="" + operator: prefix_operator "try" source="try" catch_clause: catch_clause source="catch ⟨pattern⟩ ⟨body⟩" pattern: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index 769c1c058939..b97772cd71a4 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -65,11 +65,11 @@ top_level source="⟨body⟩" body: block source="{\n ⟨stmt⟩\n}" stmt: - unary_expr source="try ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try" source="" + operator: prefix_operator "try" source="try" catch_clause: catch_clause source="catch ⟨body⟩" body: diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output index 55198489b5ee..8ed940058d75 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output @@ -36,6 +36,6 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "n" source="n" value: - unary_expr source="⟨operand⟩!" + unary_expr source="⟨operand⟩⟨operator⟩" operand: identifier "opt" source="opt" - operator: postfix_operator "!" source="" + operator: postfix_operator "!" source="!" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output index 206923657a07..0949c7553141 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output @@ -43,8 +43,8 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "result" source="result" value: - unary_expr source="try! ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try!" source="" + operator: prefix_operator "try!" source="try!" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output index ef912781b16a..a5169c10141c 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output @@ -43,8 +43,8 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "result" source="result" value: - unary_expr source="try? ⟨operand⟩" + unary_expr source="⟨operator⟩ ⟨operand⟩" operand: call_expr source="⟨callee⟩()" callee: identifier "foo" source="foo" - operator: prefix_operator "try?" source="" + operator: prefix_operator "try?" source="try?" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index 18792a2b229e..2d0432557fe5 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -73,21 +73,21 @@ top_level source="⟨body⟩" modifier: modifier "enum" source="enum" name_node: identifier "Shape" source="Shape" member: - class_like_declaration source="⟨name_node⟩⟨member⟩)" + class_like_declaration source="⟨name_node⟩⟨member⟩" modifier: modifier "enum_case" source="" name_node: identifier "circle" source="circle" member: - constructor_declaration source="circle(⟨parameter⟩" + constructor_declaration source="circle(⟨parameter⟩)" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" pattern: identifier "radius" source="radius" body: block source="" - class_like_declaration source="⟨name_node⟩⟨member⟩)" + class_like_declaration source="⟨name_node⟩⟨member⟩" modifier: modifier "enum_case" source="" name_node: identifier "square" source="square" member: - constructor_declaration source="square(⟨parameter⟩" + constructor_declaration source="square(⟨parameter⟩)" parameter: parameter source="⟨pattern⟩: ⟨type⟩" type: identifier "Double" source="Double" diff --git a/unified/extractor/tests/location_tests.rs b/unified/extractor/tests/location_tests.rs index ffa6062a46d9..30ace4016f80 100644 --- a/unified/extractor/tests/location_tests.rs +++ b/unified/extractor/tests/location_tests.rs @@ -71,13 +71,63 @@ fn generic_type_children_have_local_ranges() { assert_has_span(&ast, source, "identifier", Some("Foo"), "Foo"); } +#[test] +fn nested_calls_include_their_delimiters() { + let source = r#"sink(source("first"), source("second"))"#; + let ast = desugar(source); + + assert_has_span(&ast, source, "call_expr", None, r#"source("first")"#); + assert_has_span(&ast, source, "call_expr", None, r#"source("second")"#); +} + +#[test] +fn enum_case_constructors_include_their_parameter_clause() { + let source = "enum Result { case success(T) }"; + let ast = desugar(source); + + assert_has_span(&ast, source, "constructor_declaration", None, "success(T)"); +} + +#[test] +fn synthesized_condition_and_switch_nodes_use_child_ranges() { + let source = "if a, b { c }\nswitch x { case a, b: c }"; + let ast = desugar(source); + + assert_has_span(&ast, source, "binary_expr", None, "a, b"); + assert_has_empty_span( + &ast, + "infix_operator", + Some("&&"), + source.find(',').unwrap(), + ); + assert_has_span(&ast, source, "or_pattern", None, "a, b"); + assert_has_span(&ast, source, "block", None, "c"); +} + #[test] fn declaration_and_operator_tokens_keep_precise_ranges() { - let source = "func f() { return x }"; + let source = "func f() { return x }\nlet y = try? await value! as? T\nlet z = value is T"; let ast = desugar(source); assert_has_span(&ast, source, "block", None, "{ return x }"); assert_has_span(&ast, source, "return_expr", None, "return x"); + assert_has_span(&ast, source, "prefix_operator", Some("try?"), "try?"); + assert_has_span(&ast, source, "prefix_operator", Some("await"), "await"); + assert_has_span(&ast, source, "postfix_operator", Some("!"), "!"); + assert_has_span(&ast, source, "infix_operator", Some("as?"), "as?"); + assert_has_span(&ast, source, "infix_operator", Some("is"), "is"); +} + +#[test] +fn synthetic_optional_binding_nodes_anchor_to_binding_keyword() { + let source = "if let value = optional {}"; + let ast = desugar(source); + let binding_start = source.find("let").unwrap(); + + assert_has_empty_span(&ast, "member_access_expr", None, binding_start); + assert_has_empty_span(&ast, "identifier", Some("Optional"), binding_start); + assert_has_empty_span(&ast, "identifier", Some("some"), binding_start); + assert_has_span(&ast, source, "modifier", Some("let"), "let"); } #[test] From 3843b4a173b8a5ee7cc4179713e8b0d3675da94e Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 22 Sep 2026 11:27:21 +0000 Subject: [PATCH 07/14] Unified: Fix locations of synthesized array types Anchor synthesized generic type expressions for Swift array syntax to the original array node. This keeps the closing bracket in the type range without leaking it into surrounding calls or member accesses. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 52 +++++++++++++------ .../expressions/array-type-constructor.output | 8 +-- .../expressions/array-type-metatype.output | 4 +- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index f310cc5802f4..290fb4721ec1 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -648,27 +648,41 @@ fn translation_rules() -> Vec> { // `Array` generic type constructor instead. rule!( (functionCallExpr - calledExpression: (arrayExpr elements: (arrayElement expression: (genericSpecializationExpr) @element)) + calledExpression: (arrayExpr + elements: (arrayElement expression: (genericSpecializationExpr) @element)) @@array arguments: _* @args trailingClosure: @tc) => - (call_expr - callee: (generic_type_expr + call_expr { + let callee = tree_at!( + ctx, + array, + (generic_type_expr base: (identifier "Array") type_argument: {element}) - argument: {args} - argument: (argument value: {tc})) + ); + tree!((call_expr + callee: {callee} + argument: {args} + argument: (argument value: {tc}))) + } ), rule!( (functionCallExpr - calledExpression: (arrayExpr elements: (arrayElement expression: (genericSpecializationExpr) @element)) + calledExpression: (arrayExpr + elements: (arrayElement expression: (genericSpecializationExpr) @element)) @@array arguments: _* @args) => - (call_expr - callee: (generic_type_expr + call_expr { + let callee = tree_at!( + ctx, + array, + (generic_type_expr base: (identifier "Array") type_argument: {element}) - argument: {args}) + ); + tree!((call_expr callee: {callee} argument: {args})) + } ), // A function/method call (`foo(1, 2)`). `calledExpression` is the callee // and `arguments` is an (elided) list of `labeledExpr`, each translated @@ -739,14 +753,22 @@ fn translation_rules() -> Vec> { // meaning as `Array` rather than an array literal. rule!( (memberAccessExpr - base: (arrayExpr elements: (arrayElement expression: (genericSpecializationExpr) @element)) + base: (arrayExpr + elements: (arrayElement expression: (genericSpecializationExpr) @element)) @@array declName: (declReferenceExpr baseName: @member)) => - (member_access_expr - base: (generic_type_expr - base: (identifier "Array") - type_argument: {element}) - member_name_node: (identifier #{member})) + member_access_expr { + let base = tree_at!( + ctx, + array, + (generic_type_expr + base: (identifier "Array") + type_argument: {element}) + ); + tree!((member_access_expr + base: {base} + member_name_node: (identifier #{member}))) + } ), rule!( (memberAccessExpr base: @base declName: (declReferenceExpr baseName: @member)) diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index 23df62e6a6d7..4dbc46136a72 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -132,9 +132,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "values" source="values" value: - call_expr source="⟨callee⟩]()" + call_expr source="⟨callee⟩()" callee: - generic_type_expr source="[⟨type_argument⟩" + generic_type_expr source="[⟨type_argument⟩]" base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" @@ -144,9 +144,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "initialized" source="initialized" value: - call_expr source="⟨callee⟩](⟨argument⟩) ⟨argument⟩" + call_expr source="⟨callee⟩(⟨argument⟩) ⟨argument⟩" callee: - generic_type_expr source="[⟨type_argument⟩" + generic_type_expr source="[⟨type_argument⟩]" base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output index 066e65ccca00..8d0f690b12c6 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-metatype.output @@ -56,9 +56,9 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "type" source="type" value: - member_access_expr source="⟨base⟩].⟨member_name_node⟩" + member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: - generic_type_expr source="[⟨type_argument⟩" + generic_type_expr source="[⟨type_argument⟩]" base: identifier "Array" source="" type_argument: generic_type_expr source="⟨base⟩<⟨type_argument⟩>" From 04a6768d554b992749027317fea3ea3569e40c20 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 22 Sep 2026 11:29:35 +0000 Subject: [PATCH 08/14] Unified: Format Swift translation rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- unified/extractor/src/languages/swift/swift.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 290fb4721ec1..6fcdc9cd166e 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -890,7 +890,13 @@ fn translation_rules() -> Vec> { (switch_case body: (block stmt: {body})) ), // A single case item unwraps to its pattern, possibly boxed in conditional_pattern - rule!((switchCaseItem pattern: @p whereClause: (whereClause condition: @cond)) => (conditional_pattern pattern: { p } condition: {cond})), + rule!( + (switchCaseItem + pattern: @p + whereClause: (whereClause condition: @cond)) + => + (conditional_pattern pattern: {p} condition: {cond}) + ), rule!((switchCaseItem pattern: @p) => pattern { p }), // A pattern-matching condition (`if case let x = e`, `if case .foo(let x) // = e`) becomes a `pattern_guard_expr`: the matched pattern and the @@ -1035,7 +1041,9 @@ fn translation_rules() -> Vec> { catch_clause: {catches}) ), rule!( - (catchItem pattern: @pattern whereClause: (whereClause condition: @guard)) + (catchItem + pattern: @pattern + whereClause: (whereClause condition: @guard)) => (conditional_pattern pattern: {pattern} condition: {guard}) ), @@ -1198,7 +1206,9 @@ fn translation_rules() -> Vec> { } ), rule!( - (tupleTypeElement firstName: _? @@name type: @ty) + (tupleTypeElement + firstName: _? @@name + type: @ty) => argument { if ctx.in_function_type { From 3edeab08ee6dd44e327ccb6283b33e24d86c19d3 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 18 Sep 2026 12:56:55 +0000 Subject: [PATCH 09/14] Unified: Exclude trailing commas from locations Trailing commas appear in a lot of places in the swift-syntax AST, and are all attached to the individual values separated by said commas, not the parent node. This means that the default heuristics thinks a call like `foo(1, 2)` has arguments `1,` and `2`, which is undesirable. Since this applies uniformly for a lot of different comma-separated lists, I decided that adding a generic mechanism for ignoring certain fields was the least invasive change. Thus, we now add `trailingComma` to that list, and this means it's automatically excluded from the location calculations, without need a bunch of specific changes to the existing rules. --- shared/yeast/doc/yeast.md | 6 ++ shared/yeast/src/lib.rs | 56 +++++++++++++++++-- shared/yeast/src/range.rs | 27 +++++++++ shared/yeast/tests/test.rs | 24 ++++++++ .../extractor/src/languages/swift/swift.rs | 7 ++- .../swift/collections/tuple-literal.output | 6 +- .../nested-enum-case-pattern.output | 8 +-- .../switch-case-item-where-clauses.output | 4 +- .../switch-expression-pattern.output | 4 +- ...with-labeled-case-pattern-arguments.output | 4 +- .../expressions/array-type-constructor.output | 2 +- .../functions/call-with-inout-argument.output | 4 +- .../swift/functions/function-call.output | 4 +- ...ion-with-parameters-and-return-type.output | 4 +- .../swift/functions/generic-type-alias.output | 4 +- .../functions/nested-function-type.output | 8 +-- .../swift/functions/variadic-function.output | 4 +- .../literals/string-with-interpolation.output | 14 ++--- ...solved-operator-sequence-with-casts.output | 4 +- ...lved-operator-sequence-with-ternary.output | 8 +-- .../unresolved-operator-sequence.output | 4 +- .../catch-where-clauses.output | 4 +- .../types/constructor-with-parameters.output | 4 +- ...separated-cases-chained-declaration.output | 8 +-- ...ic-class-parameters-and-constraints.output | 6 +- .../multiple-bindings-on-one-line.output | 2 +- .../tuple-destructuring-binding.output | 4 +- .../controlflow/basicblock-slices.expected | 4 +- 28 files changed, 171 insertions(+), 67 deletions(-) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index fa917517f655..9916aad1bebb 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -272,6 +272,12 @@ let synthetic = tree_at!(ctx, source, (synthetic_node child: (nested value: {chi let synthetic = tree_spanning!(ctx, nodes, (synthetic_node child: {child})); ``` +For input fields whose leading or trailing syntax should never belong to rule +results, configure them once with +`DesugaringConfig::with_ignored_location_fields(...)`. For example, ignoring +`trailingComma` retains the rest of each matched list element without requiring +every rule to capture or handle the comma. + For literals, `ctx.literal_at_start_of(...)` creates an empty range at another node's start. diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index a71b604411c5..45f57fb70c94 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -597,6 +597,25 @@ impl Ast { self.nodes.get(id.0) } + fn source_range_ignoring_fields( + &self, + id: Id, + ignored_fields: &[&str], + ) -> Option { + let node = self.get_node(id)?; + let source_range = node.source_range()?; + let ignored_ranges = node + .fields + .iter() + .filter(|(field_id, _)| { + self.field_name_for_id(**field_id) + .is_some_and(|name| ignored_fields.contains(&name)) + }) + .flat_map(|(_, children)| children) + .filter_map(|child| self.get_node(*child).and_then(Node::source_range)); + Some(source_range.ignoring_boundary_ranges(ignored_ranges)) + } + pub fn print(&self, source: &str, root_id: Id) -> Value { let root = &self.nodes()[root_id.0]; self.print_node(root, source) @@ -1100,6 +1119,7 @@ pub struct Rule { query: QueryNode, guard: Option>, transform: Transform, + ignored_location_fields: Vec<&'static str>, /// If true, after this rule fires on a node the engine will try to /// re-apply this same rule on the result root. Defaults to false: /// each rule fires at most once on a given node, which prevents @@ -1114,6 +1134,7 @@ impl Rule { query, guard: None, transform, + ignored_location_fields: Vec::new(), repeated: false, } } @@ -1125,6 +1146,7 @@ impl Rule { query, guard: Some(guard), transform, + ignored_location_fields: Vec::new(), repeated: false, } } @@ -1138,6 +1160,10 @@ impl Rule { self } + fn set_ignored_location_fields(&mut self, fields: &[&'static str]) { + self.ignored_location_fields = fields.to_vec(); + } + /// Attempt to match this rule's query against `node`, returning the raw /// captures on success. Does not evaluate the guard or invoke the /// transform. @@ -1176,10 +1202,8 @@ impl Rule { translator: TranslatorHandle<'_, C>, ) -> Result, String> { fresh.next_scope(); - let source_range = ast.get_node(node).and_then(|n| match n.content { - NodeContent::Range(r) => Some(r), - _ => n.source_range, - }); + let source_range = + ast.source_range_ignoring_fields(node, &self.ignored_location_fields); (self.transform)(ast, captures, fresh, source_range, user_ctx, translator) } } @@ -1465,6 +1489,9 @@ pub struct DesugaringConfig { /// node types are used (i.e. the desugared AST has the same node types /// as the tree-sitter grammar). pub output_node_types_yaml: Option<&'static str>, + /// Input field names whose boundary ranges are excluded from rule-result + /// locations. + pub ignored_location_fields: Vec<&'static str>, } // Manual `Default` impl so users with a custom `C` that doesn't implement @@ -1474,6 +1501,7 @@ impl Default for DesugaringConfig { Self { phases: Vec::new(), output_node_types_yaml: None, + ignored_location_fields: Vec::new(), } } } @@ -1490,12 +1518,30 @@ impl DesugaringConfig { mut self, name: impl Into, kind: PhaseKind, - rules: Vec>, + mut rules: Vec>, ) -> Self { + for rule in &mut rules { + rule.set_ignored_location_fields(&self.ignored_location_fields); + } self.phases.push(Phase::new(name, kind, rules)); self } + /// Ignore boundary syntax stored under any of these input field names when + /// calculating matched locations for rule results. + pub fn with_ignored_location_fields( + mut self, + fields: impl IntoIterator, + ) -> Self { + self.ignored_location_fields = fields.into_iter().collect(); + for phase in &mut self.phases { + for rule in &mut phase.rules { + rule.set_ignored_location_fields(&self.ignored_location_fields); + } + } + self + } + pub fn with_output_node_types_yaml(mut self, yaml: &'static str) -> Self { self.output_node_types_yaml = Some(yaml); self diff --git a/shared/yeast/src/range.rs b/shared/yeast/src/range.rs index b9aade99ce74..0daa631d24e0 100644 --- a/shared/yeast/src/range.rs +++ b/shared/yeast/src/range.rs @@ -69,4 +69,31 @@ impl Range { ..self } } + + pub(crate) fn ignoring_boundary_ranges( + mut self, + ignored: impl IntoIterator, + ) -> Self { + let ignored: Vec<_> = ignored.into_iter().collect(); + loop { + let previous = self; + for range in &ignored { + if *range == self { + self = self.empty_at_start(); + continue; + } + if range.start_byte == self.start_byte && range.end_byte > range.start_byte { + self.start_byte = range.end_byte; + self.start_point = range.end_point; + } + if range.end_byte == self.end_byte && range.end_byte > range.start_byte { + self.end_byte = range.start_byte; + self.end_point = range.start_point; + } + } + if self == previous { + return self; + } + } + } } diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index a7e24a45366f..b0c707ea8b26 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -1787,6 +1787,30 @@ fn test_returned_capture_keeps_its_location() { assert_eq!(identifier.byte_range(), 4..7); } +#[test] +fn test_ignored_location_field_is_excluded_from_rule_result_location() { + let rule: Rule = rule!( + (assignment + left: (identifier) @left) + => + (call method: {left}) + ); + + let language: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); + let config = DesugaringConfig::new() + .with_ignored_location_fields(["right"]) + .add_phase("test", PhaseKind::Repeating, vec![rule]); + let runner: Runner = Runner::from_config(language, &config).unwrap(); + let ast = runner.run("x = 1").unwrap(); + let call = ast + .reachable_node_ids() + .into_iter() + .filter_map(|id| ast.get_node(id)) + .find(|node| node.kind_name() == "call") + .expect("call exists"); + assert_eq!(call.byte_range(), 0..4); +} + /// Nodes allocated by an explicit recursive translation belong to that nested /// rule invocation, even when the outer rule returns one directly. #[test] diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 6fcdc9cd166e..1c4aa79ddbc0 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -480,13 +480,13 @@ fn translation_rules() -> Vec> { rule!( (enumCaseElement name: @name - parameterClause: (enumCaseParameterClause parameters: _* @params)) @@element + parameterClause: (enumCaseParameterClause parameters: _* @params) @@clause) => class_like_declaration { let body = tree!((block)); - let constructor = tree_at!( + let constructor = tree_spanning!( ctx, - element, + [name, clause], (constructor_declaration parameter: {params} body: {body}) ); tree!((class_like_declaration @@ -1439,6 +1439,7 @@ fn translation_rules() -> Vec> { pub fn language_spec(desugared_ast_schema: &'static str) -> desugaring::LanguageSpec { let config = DesugaringConfig::::new() + .with_ignored_location_fields(["trailingComma"]) .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); let desugarer = diff --git a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output index 653bce662689..51088efb6750 100644 --- a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output @@ -53,11 +53,11 @@ top_level source="⟨body⟩" modifier: modifier "let" source="let" pattern: identifier "t" source="t" value: - tuple_expr source="(⟨element⟩ ⟨element⟩ ⟨element⟩)" + tuple_expr source="(⟨element⟩, ⟨element⟩, ⟨element⟩)" element: - argument source="⟨value⟩," + argument source="⟨value⟩" value: int_literal "1" source="1" - argument source="⟨value⟩," + argument source="⟨value⟩" value: string_literal "\"two\"" source="\"two\"" argument source="⟨value⟩" value: float_literal "3.0" source="3.0" diff --git a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output index 4a6c67739d9d..95d0a5585dcc 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/nested-enum-case-pattern.output @@ -167,13 +167,13 @@ top_level source="⟨body⟩" expr_pattern source="⟨modifier⟩ ⟨expr⟩" modifier: modifier "let" source="let" expr: - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: member_access_expr source="⟨base⟩⟨member_name_node⟩" base: inferred_type_expr "." source="." member_name_node: identifier "received" source="received" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: call_expr source="⟨callee⟩(⟨argument⟩)" callee: @@ -188,10 +188,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: identifier "print" source="print" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "value" source="value" argument source="⟨value⟩" value: identifier "timestamp" source="timestamp" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output index a60324f47a3d..ddd959679201 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output @@ -179,9 +179,9 @@ top_level source="⟨body⟩" value: string_literal "\"positive\"" source="\"positive\"" switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: - or_pattern source="⟨pattern⟩ ⟨pattern⟩" + or_pattern source="⟨pattern⟩, ⟨pattern⟩" pattern: - conditional_pattern source="⟨pattern⟩ where ⟨condition⟩," + conditional_pattern source="⟨pattern⟩ where ⟨condition⟩" condition: binary_expr source="⟨left⟩ ⟨operator⟩ ⟨right⟩" left: identifier "y" source="y" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output index 6ff524b63160..0ecefc622b94 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-expression-pattern.output @@ -333,9 +333,9 @@ top_level source="⟨body⟩" member_access_expr source="⟨base⟩⟨member_name_node⟩" base: inferred_type_expr "." source="." member_name_node: identifier "inferred" source="inferred" - tuple_expr source="(⟨element⟩ ⟨element⟩)" + tuple_expr source="(⟨element⟩, ⟨element⟩)" element: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "value" source="value" argument source="⟨value⟩" value: identifier "offset" source="offset" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output index 889e155ae46b..f700495a6c91 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output @@ -151,13 +151,13 @@ top_level source="⟨body⟩" value: string_literal "\"yes\"" source="\"yes\"" switch_case source="case ⟨pattern⟩:\n ⟨body⟩" pattern: - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: member_access_expr source="⟨base⟩⟨member_name_node⟩" base: inferred_type_expr "." source="." member_name_node: identifier "thread" source="thread" argument: - argument source="⟨name_node⟩: ⟨value⟩," + argument source="⟨name_node⟩: ⟨value⟩" name_node: identifier "threadRowId" source="threadRowId" value: identifier "_" source="_" argument source="⟨value⟩" diff --git a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output index 4dbc46136a72..0dde851d7b0d 100644 --- a/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output +++ b/unified/extractor/tests/corpus/swift/expressions/array-type-constructor.output @@ -160,7 +160,7 @@ top_level source="⟨body⟩" value: function_expr source="⟨body⟩⟨parameter⟩⟨parameter⟩" parameter: - parameter source="⟨pattern⟩," + parameter source="⟨pattern⟩" pattern: identifier "_" source="_" parameter source="⟨pattern⟩" pattern: identifier "count" source="count" diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output index 6899013425de..588f6aafbd6b 100644 --- a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output +++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output @@ -81,10 +81,10 @@ top_level source="⟨body⟩" modifier: modifier "var" source="var" pattern: identifier "b" source="b" value: int_literal "2" source="2" - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: identifier "swap" source="swap" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: unsupported_node "&a" source="&a" argument source="⟨value⟩" value: unsupported_node "&b" source="&b" diff --git a/unified/extractor/tests/corpus/swift/functions/function-call.output b/unified/extractor/tests/corpus/swift/functions/function-call.output index 6f25208b0189..19f1d7cf988f 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call.output @@ -31,10 +31,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: identifier "foo" source="foo" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: int_literal "1" source="1" argument source="⟨value⟩" value: int_literal "2" source="2" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index fcac6c8c2843..1a5eb6bddd7c 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -73,10 +73,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩, ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "add" source="add" parameter: - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Int" source="Int" pattern: identifier "a" source="a" diff --git a/unified/extractor/tests/corpus/swift/functions/generic-type-alias.output b/unified/extractor/tests/corpus/swift/functions/generic-type-alias.output index 5f06367b306b..4a7bb5d7b787 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-type-alias.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-type-alias.output @@ -55,10 +55,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - type_alias_declaration source="typealias ⟨name_node⟩<⟨type_parameter⟩ ⟨type_parameter⟩> = ⟨type⟩" + type_alias_declaration source="typealias ⟨name_node⟩<⟨type_parameter⟩, ⟨type_parameter⟩> = ⟨type⟩" name_node: identifier "Box" source="Box" type_parameter: - type_parameter source="⟨name_node⟩: ⟨bound⟩," + type_parameter source="⟨name_node⟩: ⟨bound⟩" name_node: identifier "T" source="T" bound: identifier "Equatable" source="Equatable" type_parameter source="⟨name_node⟩" diff --git a/unified/extractor/tests/corpus/swift/functions/nested-function-type.output b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output index d78d47dbbbb4..f4bdf2845df7 100644 --- a/unified/extractor/tests/corpus/swift/functions/nested-function-type.output +++ b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output @@ -120,9 +120,9 @@ top_level source="⟨body⟩" type_alias_declaration source="typealias ⟨name_node⟩ = ⟨type⟩" name_node: identifier "MixedParametersAndTuples" source="MixedParametersAndTuples" type: - function_expr source="(⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩" + function_expr source="(⟨parameter⟩, ⟨parameter⟩) -> ⟨return_type⟩" parameter: - parameter source="⟨type⟩," + parameter source="⟨type⟩" type: function_expr source="(⟨parameter⟩) -> ⟨return_type⟩" parameter: @@ -132,9 +132,9 @@ top_level source="⟨body⟩" parameter source="⟨type⟩" type: identifier "String" source="String" return_type: - tuple_expr source="(⟨element⟩ ⟨element⟩)" + tuple_expr source="(⟨element⟩, ⟨element⟩)" element: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "Bool" source="Bool" argument source="⟨value⟩" value: identifier "Int" source="Int" diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index 9b48167deb9c..9d5d1a6e5b95 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -90,13 +90,13 @@ top_level source="⟨body⟩" stmt: return_expr source="return ⟨value⟩" value: - call_expr source="⟨callee⟩(⟨argument⟩ ⟨argument⟩)" + call_expr source="⟨callee⟩(⟨argument⟩, ⟨argument⟩)" callee: member_access_expr source="⟨base⟩.⟨member_name_node⟩" base: identifier "values" source="values" member_name_node: identifier "reduce" source="reduce" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: int_literal "0" source="0" argument source="⟨value⟩" value: identifier "+" source="+" diff --git a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output index 821aec63a98c..fab3a3eb38ed 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output +++ b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output @@ -274,10 +274,10 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="\\(⟨argument⟩ ⟨argument⟩)" + call_expr source="\\(⟨argument⟩, ⟨argument⟩)" callee: builtin_expr "interpolation" source="" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "x" source="x" argument source="⟨value⟩" value: identifier "y" source="y" @@ -285,12 +285,12 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="\\(⟨argument⟩ ⟨argument⟩ ⟨argument⟩)" + call_expr source="\\(⟨argument⟩, ⟨argument⟩, ⟨argument⟩)" callee: builtin_expr "interpolation" source="" argument: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "x" source="x" - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "y" source="y" argument source="⟨value⟩" value: identifier "z" source="z" @@ -308,10 +308,10 @@ top_level source="⟨body⟩" string_interpolation_expr source="\"⟨element⟩⟨element⟩\"" element: string_literal "foo " source="foo " - call_expr source="\\(⟨argument⟩ ⟨argument⟩)" + call_expr source="\\(⟨argument⟩, ⟨argument⟩)" callee: builtin_expr "interpolation" source="" argument: - argument source="⟨name_node⟩: ⟨value⟩," + argument source="⟨name_node⟩: ⟨value⟩" name_node: identifier "arg" source="arg" value: identifier "x" source="x" argument source="⟨name_node⟩: ⟨value⟩" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output index 92ad43c34164..9349b1f231dc 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -93,10 +93,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩, ⟨parameter⟩) ⟨body⟩" name_node: identifier "casts" source="casts" parameter: - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Any" source="Any" pattern: identifier "a" source="a" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output index 42f184e76b15..c4a869673049 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -99,18 +99,18 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩ ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩, ⟨parameter⟩, ⟨parameter⟩, ⟨parameter⟩) -> ⟨return_type⟩ ⟨body⟩" name_node: identifier "choose" source="choose" parameter: - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Bool" source="Bool" pattern: identifier "c" source="c" - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Int" source="Int" pattern: identifier "a" source="a" - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Int" source="Int" pattern: identifier "b" source="b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output index 28953b21acc5..8e0f15b58b0e 100644 --- a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -66,10 +66,10 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - function_declaration source="func ⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" + function_declaration source="func ⟨name_node⟩(⟨parameter⟩, ⟨parameter⟩) ⟨body⟩" name_node: identifier "combine" source="combine" parameter: - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "_" source="_" type: identifier "Int" source="Int" pattern: identifier "a" source="a" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output index d83a29460e61..5506b163346f 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -152,9 +152,9 @@ top_level source="⟨body⟩" catch_clause: catch_clause source="catch ⟨pattern⟩ ⟨body⟩" pattern: - or_pattern source="⟨pattern⟩ ⟨pattern⟩" + or_pattern source="⟨pattern⟩, ⟨pattern⟩" pattern: - conditional_pattern source="⟨pattern⟩ where ⟨condition⟩," + conditional_pattern source="⟨pattern⟩ where ⟨condition⟩" condition: call_expr source="⟨callee⟩(⟨argument⟩)" callee: identifier "isNetworkError" source="isNetworkError" diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output index 181fcef50313..aaaef2029829 100644 --- a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -67,10 +67,10 @@ top_level source="⟨body⟩" modifier: modifier "struct" source="struct" name_node: identifier "Size" source="Size" member: - constructor_declaration source="⟨name_node⟩(⟨parameter⟩ ⟨parameter⟩) ⟨body⟩" + constructor_declaration source="⟨name_node⟩(⟨parameter⟩, ⟨parameter⟩) ⟨body⟩" name_node: identifier "init" source="init" parameter: - parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩," + parameter source="⟨external_name_node⟩ ⟨pattern⟩: ⟨type⟩" external_name_node: identifier "width" source="width" type: identifier "Int" source="Int" pattern: identifier "w" source="w" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index 19146c2fb731..8325b84b5bef 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -44,19 +44,19 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n case ⟨member⟩ ⟨member⟩ ⟨member⟩ ⟨member⟩\n}" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n case ⟨member⟩, ⟨member⟩, ⟨member⟩, ⟨member⟩\n}" modifier: modifier "enum" source="enum" name_node: identifier "Suit" source="Suit" member: - variable_declaration source="⟨pattern⟩," + variable_declaration source="⟨pattern⟩" modifier: modifier "enum_case" source="" pattern: identifier "clubs" source="clubs" - variable_declaration source="⟨pattern⟩," + variable_declaration source="⟨pattern⟩" modifier: modifier "chained_declaration" source="" modifier "enum_case" source="" pattern: identifier "diamonds" source="diamonds" - variable_declaration source="⟨pattern⟩," + variable_declaration source="⟨pattern⟩" modifier: modifier "chained_declaration" source="" modifier "enum_case" source="" diff --git a/unified/extractor/tests/corpus/swift/types/generic-class-parameters-and-constraints.output b/unified/extractor/tests/corpus/swift/types/generic-class-parameters-and-constraints.output index 8e057dfae084..dd8eebf431b1 100644 --- a/unified/extractor/tests/corpus/swift/types/generic-class-parameters-and-constraints.output +++ b/unified/extractor/tests/corpus/swift/types/generic-class-parameters-and-constraints.output @@ -66,17 +66,17 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩ ⟨name_node⟩<⟨type_parameter⟩ ⟨type_parameter⟩> where ⟨type_constraint⟩ ⟨type_constraint⟩ {\n}" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩<⟨type_parameter⟩, ⟨type_parameter⟩> where ⟨type_constraint⟩, ⟨type_constraint⟩ {\n}" modifier: modifier "class" source="class" name_node: identifier "Box" source="Box" type_parameter: - type_parameter source="⟨name_node⟩: ⟨bound⟩," + type_parameter source="⟨name_node⟩: ⟨bound⟩" name_node: identifier "T" source="T" bound: identifier "Equatable" source="Equatable" type_parameter source="⟨name_node⟩" name_node: identifier "U" source="U" type_constraint: - bound_type_constraint source="⟨type⟩: ⟨bound⟩," + bound_type_constraint source="⟨type⟩: ⟨bound⟩" type: identifier "U" source="U" bound: identifier "Equatable" source="Equatable" equality_type_constraint source="⟨left⟩ == ⟨right⟩" diff --git a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output index 07797954fc8d..5a4907fed714 100644 --- a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output +++ b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output @@ -40,7 +40,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩⟨stmt⟩" stmt: - variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩," + variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: identifier "x" source="x" value: int_literal "1" source="1" diff --git a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output index 794c3e5054ec..54f978c8c25b 100644 --- a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output @@ -43,9 +43,9 @@ top_level source="⟨body⟩" variable_declaration source="⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩" modifier: modifier "let" source="let" pattern: - tuple_expr source="(⟨element⟩ ⟨element⟩)" + tuple_expr source="(⟨element⟩, ⟨element⟩)" element: - argument source="⟨value⟩," + argument source="⟨value⟩" value: identifier "a" source="a" argument source="⟨value⟩" value: identifier "b" source="b" diff --git a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected index 90d7959906ce..91043b8dbc10 100644 --- a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected +++ b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected @@ -6,7 +6,7 @@ | 7 | cfg.swift:7:1:7:10 | returnZero | 'returnZero -^ returnZero(...)' | | 8 | cfg.swift:8:1:8:6 | Double | 'Double -> Argument -V topLevelDecl -^ Double(...)' | | 10 | cfg.swift:10:1:13:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' | -| 11 | cfg.swift:11:10:11:16 | VariableDeclaration | 'VariableDeclaration -V error1 -> VariableDeclaration -V error2' | +| 11 | cfg.swift:11:10:11:15 | VariableDeclaration | 'VariableDeclaration -V error1 -> VariableDeclaration -V error2' | | 12 | cfg.swift:12:10:12:31 | ClassLikeDeclaration | 'ClassLikeDeclaration -V error3 -^ ConstructorDeclaration' | | 12 | cfg.swift:12:17:12:25 | withParam | 'withParam -^ Block' | | 15 | cfg.swift:15:1:17:1 | FunctionDeclaration | 'FunctionDeclaration' | @@ -315,7 +315,7 @@ | 380 | cfg.swift:380:1:384:1 | FunctionDeclaration | 'FunctionDeclaration' | | 380 | cfg.swift:380:18:380:18 | x | 'x -> y -^ Block' | | 381 | cfg.swift:381:10:383:3 | Block | 'Block' | -| 381 | cfg.swift:381:13:381:22 | VariableDeclaration | 'VariableDeclaration -V z -> x -> y -^ ... + ... -> VariableDeclaration -V t -> "literal" -^ FunctionExpr -^ ReturnExpr' | +| 381 | cfg.swift:381:13:381:21 | VariableDeclaration | 'VariableDeclaration -V z -> x -> y -^ ... + ... -> VariableDeclaration -V t -> "literal" -^ FunctionExpr -^ ReturnExpr' | | 382 | cfg.swift:382:12:382:12 | z | 'z -^ ReturnExpr' | | 386 | cfg.swift:386:1:388:1 | FunctionDeclaration | 'FunctionDeclaration' | | 386 | cfg.swift:386:23:386:23 | t | 't -^ Block' | From c8d36085d252d5265a4348ffbf63a7bd408c7f5d Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 18 Sep 2026 14:26:02 +0000 Subject: [PATCH 10/14] yeast: Annotate children outside parent source ranges In some cases (I'm looking at you, access_declaration) we link up things like the modifier of an accessor to a node that lives _outside_ of the declaration itself. Previously this was treated as an error (and the "fix" was to extend the source ranges), but this lead to some weird source skeletons in the output. Instead, we now allow the source of a node to be anywhere (within reason -- it has to be inside the file, and properly UTF-8 aligned), and simply add a trailing ` (external)` to the source annotation. Thus, the fields containing these values do not appear in the source skeleton for the node in question. --- shared/yeast/doc/yeast.md | 11 +++++++ shared/yeast/src/dump.rs | 63 +++++++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index 9916aad1bebb..f9f0100f2fa6 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -292,6 +292,17 @@ return_expr source="return ⟨value⟩" call_expr source="⟨callee⟩(⟨argument⟩)" ``` +Children outside the node's source range retain their own locations and are +annotated where they are printed rather than being treated as errors: + +```text +accessor_declaration source="⟨accessor_kind⟩" + name_node: identifier "value" source="value" (external) +``` + +Node and child ranges are still validated against the source text and UTF-8 +boundaries. + ### Optional fields (`?`) A `?` on a field's value makes that field fallible. If a `#{expr}` anywhere diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index ddcf3ae12b4e..b2d89b587889 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -51,7 +51,7 @@ pub fn dump_ast(ast: &Ast, root: Id, source: &str) -> String { pub fn dump_ast_with_options(ast: &Ast, root: Id, source: &str, options: &DumpOptions) -> String { let mut out = String::new(); - dump_node(ast, root, source, options, 0, None, &mut out); + dump_node(ast, root, source, options, 0, None, false, &mut out); out } @@ -86,6 +86,7 @@ pub fn dump_ast_with_type_errors_and_options( expected: None, parent_field: None, }), + false, &mut out, ); out @@ -195,6 +196,7 @@ fn dump_node( options: &DumpOptions, indent: usize, type_check: Option>, + external_to_parent: bool, out: &mut String, ) { let node = match ast.get_node(id) { @@ -232,6 +234,9 @@ fn dump_node( if options.show_abridged_source { write_source_skeleton(ast, node, source, out); + if external_to_parent { + write!(out, " (external)").unwrap(); + } } if let Some(context) = type_check { @@ -300,9 +305,18 @@ fn dump_node( write!(out, "{prefix} {field_name}:").unwrap(); // Inline single child let child = ast.get_node(children[0]); + let external = child.is_some_and(|child| is_external_child(node, child)); if child.is_some_and(is_leaf) { write!(out, " ").unwrap(); - dump_node_inline(ast, children[0], source, options, child_type_check, out); + dump_node_inline( + ast, + children[0], + source, + options, + child_type_check, + external, + out, + ); } else { writeln!(out).unwrap(); dump_node( @@ -312,12 +326,16 @@ fn dump_node( options, indent + 2, child_type_check, + external, out, ); } } else { writeln!(out, "{prefix} {field_name}:").unwrap(); for &child_id in children { + let external = ast + .get_node(child_id) + .is_some_and(|child| is_external_child(node, child)); dump_node( ast, child_id, @@ -325,6 +343,7 @@ fn dump_node( options, indent + 2, child_type_check, + external, out, ); } @@ -365,6 +384,7 @@ fn dump_node( for &child_id in children { if let Some(child) = ast.get_node(child_id) { if child.is_named() { + let external = is_external_child(node, child); dump_node( ast, child_id, @@ -372,6 +392,7 @@ fn dump_node( options, indent + 1, child_type_check, + external, out, ); } @@ -387,6 +408,7 @@ fn dump_node_inline( source: &str, options: &DumpOptions, type_check: Option>, + external_to_parent: bool, out: &mut String, ) { let node = match ast.get_node(id) { @@ -419,6 +441,9 @@ fn dump_node_inline( if options.show_abridged_source { write_source_skeleton(ast, node, source, out); + if external_to_parent { + write!(out, " (external)").unwrap(); + } } if let Some(context) = type_check { @@ -457,6 +482,13 @@ fn node_source_range(node: &Node) -> Option { } } +fn is_external_child(parent: &Node, child: &Node) -> bool { + let (Some(parent), Some(child)) = (node_source_range(parent), node_source_range(child)) else { + return false; + }; + child.start_byte < parent.start_byte || child.end_byte > parent.end_byte +} + fn source_skeleton(ast: &Ast, node: &Node, source: &str) -> SourceSkeleton { let Some(parent) = node_source_range(node) else { return SourceSkeleton::Missing; @@ -494,10 +526,7 @@ fn source_skeleton(ast: &Ast, node: &Node, source: &str) -> SourceSkeleton { )); } if child.start < parent.start || child.end > parent.end { - return SourceSkeleton::Invalid(format!( - "child range {}..{} is outside node range {}..{}", - child.start, child.end, parent.start, parent.end - )); + continue; } if child.start == child.end { continue; @@ -613,12 +642,6 @@ mod tests { #[test] fn source_skeleton_validates_empty_child_ranges() { let cases = [ - ( - "abcdef", - range(0, 3), - range(4, 4), - "child range 4..4 is outside node range 0..3", - ), ( "abcdef", range(0, 6), @@ -640,6 +663,13 @@ mod tests { "unexpected dump: {dump}" ); } + + let dump = dump_with_children("abcdef", range(0, 3), &[("marker", range(4, 4))]); + assert!(dump.starts_with("parent source=\"abc\"\n")); + assert!( + dump.contains("marker: child source=\"\" (external)\n"), + "unexpected dump: {dump}" + ); } #[test] @@ -667,12 +697,15 @@ mod tests { } #[test] - fn source_skeleton_reports_children_outside_the_parent() { + fn source_skeleton_marks_children_outside_the_parent() { let source = "abcdefghi"; let dump = dump_with_children(source, range(0, 6), &[("child", range(7, 9))]); - assert!(dump - .starts_with("parent source=\n")); + assert!(dump.starts_with("parent source=\"abcdef\"\n")); + assert!( + dump.contains(" child source=\"hi\" (external)\n"), + "unexpected dump: {dump}" + ); } } From a6ffe1fcc9818308dede181fbd0ffac23a1d83a1 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 18 Sep 2026 14:26:23 +0000 Subject: [PATCH 11/14] Unified: Give accessors their own source ranges Keep inherited property metadata at its original source while limiting each accessor declaration to its own keyword and optional body. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extractor/src/languages/swift/swift.rs | 4 ++- ...er-does-not-leak-into-accessor-body.output | 10 +++---- .../property-with-getter-and-setter.output | 18 ++++++------- ...nd-read-write-property-requirements.output | 26 +++++++++---------- ...y-with-willset-and-didset-observers.output | 12 ++++----- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 1c4aa79ddbc0..e1c78c59af6b 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -405,7 +405,9 @@ fn translation_rules() -> Vec> { } None => None, }; - tree!( + tree_spanning!( + ctx, + std::iter::once(spec).chain(body), (accessor_declaration modifier: {binding} modifier: {chained} diff --git a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output index 17004c0c8959..88674d76efbd 100644 --- a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output +++ b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output @@ -92,15 +92,15 @@ sourceFile --- -top_level source="⟨body⟩\n}" +top_level source="var p: Int {\n ⟨body⟩\n}" body: block source="⟨stmt⟩" stmt: - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨accessor_kind⟩ ⟨body⟩" - modifier: modifier "var" source="var" - name_node: identifier "p" source="p" + accessor_declaration source="⟨accessor_kind⟩ ⟨body⟩" + modifier: modifier "var" source="var" (external) + name_node: identifier "p" source="p" (external) accessor_kind: accessor_kind "get" source="get" - type: identifier "Int" source="Int" + type: identifier "Int" source="Int" (external) body: block source="{\n ⟨stmt⟩\n }" stmt: diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index 94d514f11cdb..00e111bf77ad 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -106,7 +106,7 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n ⟨member⟩\n ⟨member⟩⟨member⟩\n }\n}" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n ⟨member⟩\n var v: Int {\n ⟨member⟩\n ⟨member⟩\n }\n}" modifier: modifier "class" source="class" name_node: identifier "Box" source="Box" member: @@ -116,23 +116,23 @@ top_level source="⟨body⟩" modifier "private" source="private" pattern: identifier "_v" source="_v" value: int_literal "0" source="0" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n ⟨accessor_kind⟩ ⟨body⟩" - modifier: modifier "var" source="var" - name_node: identifier "v" source="v" + accessor_declaration source="⟨accessor_kind⟩ ⟨body⟩" + modifier: modifier "var" source="var" (external) + name_node: identifier "v" source="v" (external) accessor_kind: accessor_kind "get" source="get" - type: identifier "Int" source="Int" + type: identifier "Int" source="Int" (external) body: block source="{ ⟨stmt⟩ }" stmt: return_expr source="return ⟨value⟩" value: identifier "_v" source="_v" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: ⟨type⟩ {\n get { return _v }\n ⟨accessor_kind⟩ ⟨body⟩" + accessor_declaration source="⟨accessor_kind⟩ ⟨body⟩" modifier: - modifier "var" source="var" + modifier "var" source="var" (external) modifier "chained_declaration" source="" - name_node: identifier "v" source="v" + name_node: identifier "v" source="v" (external) accessor_kind: accessor_kind "set" source="set" - type: identifier "Int" source="Int" + type: identifier "Int" source="Int" (external) body: block source="{ ⟨stmt⟩ }" stmt: diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index 0886939c1d94..8a43a3c70588 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -106,24 +106,24 @@ top_level source="⟨body⟩" body: block source="⟨stmt⟩" stmt: - class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n var ⟨member⟩ }\n var ⟨member⟩⟨member⟩ }\n var ⟨member⟩ }\n}" + class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n var foo: Int { ⟨member⟩ }\n var bar: String { ⟨member⟩ ⟨member⟩ }\n var count: Int { ⟨member⟩ }\n}" modifier: modifier "protocol" source="protocol" name_node: identifier "P" source="P" member: - accessor_declaration source="⟨name_node⟩: ⟨type⟩ { ⟨accessor_kind⟩" - name_node: identifier "foo" source="foo" + accessor_declaration source="⟨accessor_kind⟩" + name_node: identifier "foo" source="foo" (external) accessor_kind: accessor_kind "get" source="get" - type: identifier "Int" source="Int" - accessor_declaration source="⟨name_node⟩: ⟨type⟩ { ⟨accessor_kind⟩" - name_node: identifier "bar" source="bar" + type: identifier "Int" source="Int" (external) + accessor_declaration source="⟨accessor_kind⟩" + name_node: identifier "bar" source="bar" (external) accessor_kind: accessor_kind "get" source="get" - type: identifier "String" source="String" - accessor_declaration source="⟨name_node⟩: ⟨type⟩ { get ⟨accessor_kind⟩" + type: identifier "String" source="String" (external) + accessor_declaration source="⟨accessor_kind⟩" modifier: modifier "chained_declaration" source="" - name_node: identifier "bar" source="bar" + name_node: identifier "bar" source="bar" (external) accessor_kind: accessor_kind "set" source="set" - type: identifier "String" source="String" - accessor_declaration source="⟨name_node⟩: ⟨type⟩ { ⟨accessor_kind⟩" - name_node: identifier "count" source="count" + type: identifier "String" source="String" (external) + accessor_declaration source="⟨accessor_kind⟩" + name_node: identifier "count" source="count" (external) accessor_kind: accessor_kind "get" source="get" - type: identifier "Int" source="Int" + type: identifier "Int" source="Int" (external) diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 4670fd83b1d5..1f2ff4a67244 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -110,11 +110,11 @@ top_level source="⟨body⟩" pattern: identifier "x" source="x" type: identifier "Int" source="Int" value: int_literal "0" source="0" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n ⟨accessor_kind⟩ ⟨body⟩" + accessor_declaration source="⟨accessor_kind⟩ ⟨body⟩" modifier: - modifier "var" source="var" + modifier "var" source="var" (external) modifier "chained_declaration" source="" - name_node: identifier "x" source="x" + name_node: identifier "x" source="x" (external) accessor_kind: accessor_kind "willSet" source="willSet" body: block source="{ ⟨stmt⟩ }" @@ -124,11 +124,11 @@ top_level source="⟨body⟩" argument: argument source="⟨value⟩" value: identifier "newValue" source="newValue" - accessor_declaration source="⟨modifier⟩ ⟨name_node⟩: Int = 0 {\n willSet { print(newValue) }\n ⟨accessor_kind⟩ ⟨body⟩" + accessor_declaration source="⟨accessor_kind⟩ ⟨body⟩" modifier: - modifier "var" source="var" + modifier "var" source="var" (external) modifier "chained_declaration" source="" - name_node: identifier "x" source="x" + name_node: identifier "x" source="x" (external) accessor_kind: accessor_kind "didSet" source="didSet" body: block source="{ ⟨stmt⟩ }" From 364d59c74a43d6ddb34f9c304cd9a3da963c13d7 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 17 Sep 2026 15:30:11 +0000 Subject: [PATCH 12/14] Unified: Update location test expectations Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../library-tests/BasicTest/test.expected | 14 +- .../controlflow/basicblock-slices.expected | 168 +++++++++--------- .../library-tests/controlflow/cfg.expected | 20 +-- .../test/library-tests/controlflow/cfg.swift | 14 +- .../test/library-tests/dataflow/test.expected | 48 ++--- 5 files changed, 129 insertions(+), 135 deletions(-) diff --git a/unified/ql/test/library-tests/BasicTest/test.expected b/unified/ql/test/library-tests/BasicTest/test.expected index 0b5b75967b3b..95d54935f8ee 100644 --- a/unified/ql/test/library-tests/BasicTest/test.expected +++ b/unified/ql/test/library-tests/BasicTest/test.expected @@ -12,7 +12,7 @@ identifier | test.swift:4:18:4:18 | T | T | | test.swift:4:21:4:29 | Equatable | Equatable | | test.swift:5:9:5:13 | items | items | -| test.swift:5:16:5:18 | Array | Array | +| test.swift:5:16:5:15 | Array | Array | | test.swift:5:17:5:17 | T | T | | test.swift:7:19:7:21 | add | add | | test.swift:7:23:7:23 | _ | _ | @@ -37,8 +37,8 @@ identifier | test.swift:20:15:20:16 | at | at | | test.swift:20:18:20:22 | index | index | | test.swift:20:25:20:27 | Int | Int | +| test.swift:20:33:20:32 | Optional | Optional | | test.swift:20:33:20:39 | Element | Element | -| test.swift:20:33:20:40 | Optional | Optional | | test.swift:24:6:24:10 | merge | merge | | test.swift:24:12:24:12 | T | T | | test.swift:24:15:24:24 | Collection | Collection | @@ -48,7 +48,7 @@ identifier | test.swift:24:39:24:39 | _ | _ | | test.swift:24:41:24:46 | second | second | | test.swift:24:49:24:49 | T | T | -| test.swift:24:55:24:65 | Array | Array | +| test.swift:24:55:24:54 | Array | Array | | test.swift:24:56:24:56 | T | T | | test.swift:24:58:24:64 | Element | Element | | test.swift:25:9:25:14 | result | result | @@ -69,7 +69,7 @@ identifier | test.swift:36:15:36:21 | Element | Element | | test.swift:36:25:36:25 | T | T | | test.swift:37:17:37:20 | data | data | -| test.swift:37:23:37:25 | Array | Array | +| test.swift:37:23:37:22 | Array | Array | | test.swift:37:24:37:24 | T | T | | test.swift:39:9:39:13 | count | count | | test.swift:39:16:39:18 | Int | Int | @@ -83,8 +83,8 @@ identifier | test.swift:47:15:47:16 | at | at | | test.swift:47:18:47:22 | index | index | | test.swift:47:25:47:27 | Int | Int | +| test.swift:47:33:47:32 | Optional | Optional | | test.swift:47:33:47:33 | T | T | -| test.swift:47:33:47:34 | Optional | Optional | | test.swift:48:15:48:19 | index | index | | test.swift:48:29:48:33 | index | index | | test.swift:48:37:48:40 | data | data | @@ -138,15 +138,15 @@ identifier | test.swift:85:14:85:14 | T | T | | test.swift:85:17:85:17 | _ | _ | | test.swift:85:19:85:24 | values | values | -| test.swift:85:27:85:29 | Array | Array | +| test.swift:85:27:85:26 | Array | Array | | test.swift:85:28:85:28 | T | T | | test.swift:85:32:85:40 | transform | transform | | test.swift:85:32:85:40 | transform | transform | | test.swift:85:44:85:44 | T | T | | test.swift:85:47:85:47 | T | T | | test.swift:85:53:85:53 | T | T | +| test.swift:85:59:85:58 | Optional | Optional | | test.swift:85:59:85:59 | T | T | -| test.swift:85:59:85:60 | Optional | Optional | | test.swift:86:12:86:17 | values | values | | test.swift:86:19:86:25 | isEmpty | isEmpty | | test.swift:87:12:87:17 | values | values | diff --git a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected index 91043b8dbc10..7cb2cc89e5ca 100644 --- a/unified/ql/test/library-tests/controlflow/basicblock-slices.expected +++ b/unified/ql/test/library-tests/controlflow/basicblock-slices.expected @@ -1,19 +1,19 @@ -| 1 | cfg.swift:1:1:604:2 | Block | 'Block -V VariableDeclaration -V topLevelDecl -> Int -> 0' | +| 1 | cfg.swift:1:1:604:1 | Block | 'Block -V VariableDeclaration -V topLevelDecl -> Int -> 0' | | 2 | cfg.swift:2:1:2:1 | 0 | '0' | | 3 | cfg.swift:3:1:3:12 | topLevelDecl | 'topLevelDecl -> 1 -^ ... + ...' | -| 5 | cfg.swift:5:1:5:37 | Block | 'Block -V 0 -^ ReturnExpr' | | 5 | cfg.swift:5:1:5:37 | FunctionDeclaration | 'FunctionDeclaration' | +| 5 | cfg.swift:5:26:5:37 | Block | 'Block -V 0 -^ ReturnExpr' | | 7 | cfg.swift:7:1:7:10 | returnZero | 'returnZero -^ returnZero(...)' | | 8 | cfg.swift:8:1:8:6 | Double | 'Double -> Argument -V topLevelDecl -^ Double(...)' | -| 10 | cfg.swift:10:1:13:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' | +| 10 | cfg.swift:10:1:13:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -> BaseType -V Error' | | 11 | cfg.swift:11:10:11:15 | VariableDeclaration | 'VariableDeclaration -V error1 -> VariableDeclaration -V error2' | | 12 | cfg.swift:12:10:12:31 | ClassLikeDeclaration | 'ClassLikeDeclaration -V error3 -^ ConstructorDeclaration' | -| 12 | cfg.swift:12:17:12:25 | withParam | 'withParam -^ Block' | +| 12 | cfg.swift:12:17:12:25 | withParam | 'withParam -? Block' | | 15 | cfg.swift:15:1:17:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 15 | cfg.swift:15:13:15:13 | x | 'x -^ Block' | +| 15 | cfg.swift:15:13:15:13 | x | 'x -> Block' | | 16 | cfg.swift:16:10:16:10 | x | 'x -> 0 -^ ... == ... -^ ReturnExpr' | | 19 | cfg.swift:19:1:26:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 19 | cfg.swift:19:17:19:17 | x | 'x -^ Block' | +| 19 | cfg.swift:19:17:19:17 | x | 'x -> Block' | | 20 | cfg.swift:20:3:22:3 | GuardIfStmt | 'GuardIfStmt -V x -> 0 -^ ... >= ...' | | 20 | cfg.swift:20:21:22:3 | Block | 'Block' | | 21 | cfg.swift:21:11:21:17 | MyError | 'MyError -^ ... .error1 -^ ThrowExpr' | @@ -21,7 +21,7 @@ | 23 | cfg.swift:23:21:25:3 | Block | 'Block' | | 24 | cfg.swift:24:11:24:17 | MyError | 'MyError -^ ... .error3 -> Argument -V x -> 1 -^ ... + ... -^ ... .error3(...) -^ ThrowExpr' | | 28 | cfg.swift:28:1:45:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 28 | cfg.swift:28:15:28:15 | x | 'x -^ Block' | +| 28 | cfg.swift:28:15:28:15 | x | 'x -> Block' | | 29 | cfg.swift:29:3:43:3 | TryExpr | 'TryExpr -V Block' | | 30 | cfg.swift:30:5:30:24 | try ... | 'try ...' | | 30 | cfg.swift:30:9:30:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ mightThrow(...)' | @@ -38,62 +38,62 @@ | 39 | cfg.swift:39:22:41:3 | Block | 'Block' | | 40 | cfg.swift:40:5:40:9 | print | 'print -> Argument -V "MyError" -^ print(...)' | | 41 | cfg.swift:41:5:43:3 | CatchClause | 'CatchClause -V Block' | -| 42 | cfg.swift:42:5:42:9 | print | 'print -> Argument -V Unknown error -> interpolation -V Argument -V error -^ interpolation(...) -> -^ StringInterpolationExpr -^ print(...)' | +| 42 | cfg.swift:42:5:42:9 | print | 'print -> Argument -V Unknown error -> interpolation -> Argument -V error -^ interpolation(...) -> -^ StringInterpolationExpr -^ print(...)' | | 44 | cfg.swift:44:10:44:10 | 0 | '0 -^ ReturnExpr' | | 47 | cfg.swift:47:1:51:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 47 | cfg.swift:47:21:47:21 | s | 's -^ Block' | +| 47 | cfg.swift:47:21:47:21 | s | 's -> Block' | | 48 | cfg.swift:48:10:50:3 | Block | 'Block' | | 48 | cfg.swift:48:10:50:3 | FunctionExpr | 'FunctionExpr -^ ReturnExpr' | | 49 | cfg.swift:49:12:49:12 | s | 's -> "" -^ ... + ... -^ ReturnExpr' | | 53 | cfg.swift:53:1:58:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 53 | cfg.swift:53:21:53:21 | x | 'x -^ Block' | +| 53 | cfg.swift:53:21:53:21 | x | 'x -> Block' | | 54 | cfg.swift:54:3:56:3 | FunctionDeclaration | 'FunctionDeclaration' | -| 54 | cfg.swift:54:10:54:10 | y | 'y -^ Block' | +| 54 | cfg.swift:54:10:54:10 | y | 'y -> Block' | | 55 | cfg.swift:55:12:55:12 | x | 'x -> y -^ ... + ... -^ ReturnExpr' | | 57 | cfg.swift:57:10:57:10 | f | 'f -^ ReturnExpr' | | 60 | cfg.swift:60:1:64:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 60 | cfg.swift:60:21:60:21 | x | 'x -^ Block' | +| 60 | cfg.swift:60:21:60:21 | x | 'x -> Block' | | 61 | cfg.swift:61:10:63:3 | Block | 'Block' | | 61 | cfg.swift:61:10:63:3 | FunctionExpr | 'FunctionExpr -^ ReturnExpr' | | 62 | cfg.swift:62:6:62:6 | y | 'y' | | 62 | cfg.swift:62:19:62:19 | x | 'x -> y -^ ... + ...' | -| 66 | cfg.swift:66:1:70:1 | Block | 'Block' | | 66 | cfg.swift:66:1:70:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 66 | cfg.swift:66:21:70:1 | Block | 'Block' | | 67 | cfg.swift:67:3:67:34 | VariableDeclaration | 'VariableDeclaration -V x1 -> createClosure1 -> Argument -V "" -^ createClosure1(...) -^ ...(...)' | | 68 | cfg.swift:68:3:68:35 | VariableDeclaration | 'VariableDeclaration -V x2 -> createClosure2 -> Argument -V 0 -^ createClosure2(...) -> Argument -V 10 -^ ...(...)' | | 69 | cfg.swift:69:3:69:35 | VariableDeclaration | 'VariableDeclaration -V x3 -> createClosure3 -> Argument -V 0 -^ createClosure3(...) -> Argument -V 10 -^ ...(...)' | | 72 | cfg.swift:72:1:75:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 72 | cfg.swift:72:20:72:20 | s | 's -^ Block' | -| 73 | cfg.swift:73:3:73:23 | VariableDeclaration | 'VariableDeclaration -V n -> Optional -V Int -^ GenericTypeExpr -> Int -> Argument -V s -^ Int(...)' | +| 72 | cfg.swift:72:20:72:20 | s | 's -> Block' | +| 73 | cfg.swift:73:3:73:23 | VariableDeclaration | 'VariableDeclaration -V n -> Optional -> Int -^ GenericTypeExpr -> Int -> Argument -V s -^ Int(...)' | | 74 | cfg.swift:74:10:74:10 | n | 'n -^ ReturnExpr' | -| 77 | cfg.swift:77:1:81:1 | Block | 'Block' | | 77 | cfg.swift:77:1:81:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 77 | cfg.swift:77:39:81:1 | Block | 'Block' | | 78 | cfg.swift:78:3:78:36 | VariableDeclaration | 'VariableDeclaration -V nBang -> maybeParseInt -> Argument -V "42" -^ maybeParseInt(...) -^ ... !' | | 79 | cfg.swift:79:3:79:31 | VariableDeclaration | 'VariableDeclaration -V n -> maybeParseInt -> Argument -V "42" -^ maybeParseInt(...)' | | 80 | cfg.swift:80:10:80:14 | nBang | 'nBang -> n -^ ... ! -^ ... + ... -^ ReturnExpr' | -| 83 | cfg.swift:83:1:98:1 | Block | 'Block' | | 83 | cfg.swift:83:1:98:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 83 | cfg.swift:83:25:98:1 | Block | 'Block' | | 84 | cfg.swift:84:3:84:15 | VariableDeclaration | 'VariableDeclaration -V temp -> 10' | | 86 | cfg.swift:86:3:88:3 | FunctionDeclaration | 'FunctionDeclaration' | -| 86 | cfg.swift:86:12:86:12 | a | 'a -^ Block' | +| 86 | cfg.swift:86:12:86:12 | a | 'a -> Block' | | 87 | cfg.swift:87:5:87:5 | a | 'a -> a -> 1 -^ ... + ... -^ ... = ...' | | 90 | cfg.swift:90:3:92:3 | FunctionDeclaration | 'FunctionDeclaration' | -| 90 | cfg.swift:90:20:90:20 | a | 'a -^ Block' | +| 90 | cfg.swift:90:20:90:20 | a | 'a -> Block' | | 91 | cfg.swift:91:5:91:5 | a | 'a -> nil -^ ... = ...' | | 94 | cfg.swift:94:3:94:5 | add | 'add -> Argument -V -^ add(...)' | -| 95 | cfg.swift:95:3:95:30 | VariableDeclaration | 'VariableDeclaration -V tempOptional -> Optional -V Int -^ GenericTypeExpr -> 10' | +| 95 | cfg.swift:95:3:95:30 | VariableDeclaration | 'VariableDeclaration -V tempOptional -> Optional -> Int -^ GenericTypeExpr -> 10' | | 96 | cfg.swift:96:3:96:13 | addOptional | 'addOptional -> Argument -V -^ addOptional(...)' | | 97 | cfg.swift:97:10:97:13 | temp | 'temp -> tempOptional -^ ... ! -^ ... + ... -^ ReturnExpr' | | 100 | cfg.swift:100:1:109:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V C' | | 101 | cfg.swift:101:3:101:16 | VariableDeclaration | 'VariableDeclaration -V myInt -> Int' | | 102 | cfg.swift:102:3:104:3 | ConstructorDeclaration | 'ConstructorDeclaration' | -| 102 | cfg.swift:102:8:102:8 | n | 'n -^ Block' | +| 102 | cfg.swift:102:8:102:8 | n | 'n -> Block' | | 103 | cfg.swift:103:5:103:9 | myInt | 'myInt -> n -^ ... = ...' | -| 106 | cfg.swift:106:3:108:3 | Block | 'Block' | | 106 | cfg.swift:106:3:108:3 | FunctionDeclaration | 'FunctionDeclaration' | +| 106 | cfg.swift:106:26:108:3 | Block | 'Block' | | 107 | cfg.swift:107:12:107:16 | myInt | 'myInt -^ ReturnExpr' | | 111 | cfg.swift:111:1:137:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 111 | cfg.swift:111:20:111:24 | param | 'param -> inoutParam -> opt -^ Block' | +| 111 | cfg.swift:111:20:111:24 | param | 'param -> inoutParam -> opt -> Block' | | 112 | cfg.swift:112:3:112:18 | VariableDeclaration | 'VariableDeclaration -V c -> C -> Argument -V 42 -^ C(...)' | | 113 | cfg.swift:113:3:113:18 | VariableDeclaration | 'VariableDeclaration -V n1 -> c -^ ... .myInt' | | 114 | cfg.swift:114:3:114:23 | VariableDeclaration | 'VariableDeclaration -V n2 -> c -^ ... .self -^ ... .myInt' | @@ -116,29 +116,27 @@ | 135 | cfg.swift:135:3:135:27 | VariableDeclaration | 'VariableDeclaration -V n19 -> opt -^ ... .getMyInt -^ ... .getMyInt(...)' | | 136 | cfg.swift:136:3:136:32 | VariableDeclaration | 'VariableDeclaration -V n20 -> opt -^ ... .self -^ ... .getMyInt -^ ... .getMyInt(...)' | | 139 | cfg.swift:139:1:166:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 139 | cfg.swift:139:15:139:15 | x | 'x -^ Block' | +| 139 | cfg.swift:139:15:139:15 | x | 'x -> Block' | | 140 | cfg.swift:140:3:141:12 | ForEachStmt | 'ForEachStmt -V 0 -> 10 -^ ... ... ...' | | 140 | cfg.swift:140:7:140:7 | _ | '_' | | 141 | cfg.swift:141:9:141:12 | Block | 'Block' | | 143 | cfg.swift:143:3:153:3 | SwitchExpr | 'SwitchExpr -V x' | -| 144 | cfg.swift:144:5:146:17 | Block | 'Block' | | 144 | cfg.swift:144:5:146:17 | SwitchCase | 'SwitchCase -V 0 -> 1 -^ OrPattern' | -| 145 | cfg.swift:145:14:145:17 | true | 'true -^ ReturnExpr' | -| 147 | cfg.swift:147:5:150:17 | Block | 'Block' | +| 145 | cfg.swift:145:7:146:17 | Block | 'Block -V true -^ ReturnExpr' | | 147 | cfg.swift:147:5:150:17 | SwitchCase | 'SwitchCase' | | 147 | cfg.swift:147:10:147:10 | x | 'x -^ ConditionalPattern' | | 148 | cfg.swift:148:9:149:17 | ... && ... | '... && ... -V x -> 2 -^ ... >= ...' | | 149 | cfg.swift:149:13:149:13 | x | 'x -> 5 -^ ... < ...' | -| 150 | cfg.swift:150:14:150:17 | true | 'true -^ ReturnExpr' | -| 151 | cfg.swift:151:5:152:18 | SwitchCase | 'SwitchCase -V Block' | -| 152 | cfg.swift:152:14:152:18 | false | 'false -^ ReturnExpr' | +| 150 | cfg.swift:150:7:150:17 | Block | 'Block -V true -^ ReturnExpr' | +| 151 | cfg.swift:151:5:152:18 | SwitchCase | 'SwitchCase' | +| 152 | cfg.swift:152:7:152:18 | Block | 'Block -V false -^ ReturnExpr' | | 168 | cfg.swift:168:1:184:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 168 | cfg.swift:168:16:168:16 | x | 'x -^ Block' | +| 168 | cfg.swift:168:16:168:16 | x | 'x -> Block' | | 170 | cfg.swift:170:3:172:3 | | '' | | 174 | cfg.swift:174:3:176:3 | | '' | | 178 | cfg.swift:178:3:183:3 | | '' | | 186 | cfg.swift:186:1:198:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 186 | cfg.swift:186:9:186:9 | x | 'x -^ Block' | +| 186 | cfg.swift:186:9:186:9 | x | 'x -> Block' | | 187 | cfg.swift:187:3:197:3 | IfExpr | 'IfExpr -V x -> 2 -^ ... > ...' | | 187 | cfg.swift:187:12:189:3 | Block | 'Block' | | 188 | cfg.swift:188:5:188:9 | print | 'print -> Argument -V "x is greater than 2" -^ print(...)' | @@ -150,13 +148,13 @@ | 195 | cfg.swift:195:8:197:3 | Block | 'Block' | | 196 | cfg.swift:196:5:196:9 | print | 'print -> Argument -V "I can't guess the number" -^ print(...)' | | 200 | cfg.swift:200:1:205:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 200 | cfg.swift:200:9:200:9 | b | 'b -^ Block' | +| 200 | cfg.swift:200:9:200:9 | b | 'b -> Block' | | 201 | cfg.swift:201:3:203:3 | IfExpr | 'IfExpr -V b' | | 201 | cfg.swift:201:8:203:3 | Block | 'Block' | | 202 | cfg.swift:202:12:202:12 | 0 | '0 -^ ReturnExpr' | | 204 | cfg.swift:204:10:204:10 | 1 | '1 -^ ReturnExpr' | | 207 | cfg.swift:207:1:215:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 207 | cfg.swift:207:9:207:9 | x | 'x -^ Block' | +| 207 | cfg.swift:207:9:207:9 | x | 'x -> Block' | | 208 | cfg.swift:208:3:213:3 | IfExpr | 'IfExpr -V x -> 0 -^ ... < ...' | | 208 | cfg.swift:208:12:213:3 | Block | 'Block' | | 209 | cfg.swift:209:5:209:5 | x | 'x -> x -^ - ... -^ ... = ...' | @@ -165,7 +163,7 @@ | 211 | cfg.swift:211:7:211:7 | x | 'x -> x -> 1 -^ ... - ... -^ ... = ...' | | 214 | cfg.swift:214:10:214:10 | x | 'x -^ ReturnExpr' | | 217 | cfg.swift:217:1:223:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 217 | cfg.swift:217:10:217:11 | b1 | 'b1 -> b2 -> b3 -^ Block' | +| 217 | cfg.swift:217:10:217:11 | b1 | 'b1 -> b2 -> b3 -> Block' | | 218 | cfg.swift:218:3:222:20 | ReturnExpr | 'ReturnExpr' | | 218 | cfg.swift:218:10:222:20 | IfExpr | 'IfExpr -V IfExpr -V b1' | | 219 | cfg.swift:219:13:219:14 | b2 | 'b2' | @@ -173,7 +171,7 @@ | 221 | cfg.swift:221:9:221:18 | "b2 \|\| b3" | '"b2 \|\| b3"' | | 222 | cfg.swift:222:9:222:20 | "!b2 \|\| !b3" | '"!b2 \|\| !b3"' | | 225 | cfg.swift:225:1:234:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 225 | cfg.swift:225:31:225:31 | b | 'b -^ Block' | +| 225 | cfg.swift:225:31:225:31 | b | 'b -> Block' | | 226 | cfg.swift:226:3:233:3 | IfExpr | 'IfExpr -V IfExpr -V b' | | 227 | cfg.swift:227:8:227:11 | true | 'true' | | 228 | cfg.swift:228:7:228:10 | Bool | 'Bool -> Argument -V false -^ Bool(...)' | @@ -181,24 +179,24 @@ | 229 | cfg.swift:229:12:229:14 | "b" | '"b" -^ ReturnExpr' | | 231 | cfg.swift:231:8:233:3 | Block | 'Block' | | 232 | cfg.swift:232:12:232:15 | "!b" | '"!b" -^ ReturnExpr' | -| 236 | cfg.swift:236:1:240:1 | Block | 'Block' | | 236 | cfg.swift:236:1:240:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 236 | cfg.swift:236:27:240:1 | Block | 'Block' | | 237 | cfg.swift:237:3:239:3 | IfExpr | 'IfExpr -V ! ... -V true' | | 242 | cfg.swift:242:1:248:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 242 | cfg.swift:242:17:242:17 | b | 'b -^ Block' | +| 242 | cfg.swift:242:17:242:17 | b | 'b -> Block' | | 243 | cfg.swift:243:3:246:9 | IfExpr | 'IfExpr -V b' | | 243 | cfg.swift:243:8:245:3 | Block | 'Block' | | 244 | cfg.swift:244:5:244:9 | print | 'print -> Argument -V "true" -^ print(...)' | | 246 | cfg.swift:246:8:246:9 | Block | 'Block' | | 247 | cfg.swift:247:3:247:7 | print | 'print -> Argument -V "done" -^ print(...)' | | 250 | cfg.swift:250:1:254:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 250 | cfg.swift:250:16:250:17 | b1 | 'b1 -> b2 -^ Block' | +| 250 | cfg.swift:250:16:250:17 | b1 | 'b1 -> b2 -> Block' | | 251 | cfg.swift:251:3:253:3 | IfExpr | 'IfExpr -V ... \|\| ... -V b1' | | 251 | cfg.swift:251:13:251:14 | b2 | 'b2' | | 251 | cfg.swift:251:17:253:3 | Block | 'Block' | | 252 | cfg.swift:252:5:252:9 | print | 'print -> Argument -V "b1 or b2" -^ print(...)' | | 256 | cfg.swift:256:1:273:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 256 | cfg.swift:256:18:256:18 | a | 'a -> b -^ Block' | +| 256 | cfg.swift:256:18:256:18 | a | 'a -> b -> Block' | | 257 | cfg.swift:257:3:257:15 | VariableDeclaration | 'VariableDeclaration -V c -> a -> b -^ ... + ...' | | 258 | cfg.swift:258:3:258:15 | VariableDeclaration | 'VariableDeclaration -V d -> a -> b -^ ... - ...' | | 259 | cfg.swift:259:3:259:15 | VariableDeclaration | 'VariableDeclaration -V e -> a -> b -^ ... * ...' | @@ -216,10 +214,10 @@ | 271 | cfg.swift:271:3:271:15 | VariableDeclaration | 'VariableDeclaration -V s -> a -> b -^ ... > ...' | | 272 | cfg.swift:272:3:272:16 | VariableDeclaration | 'VariableDeclaration -V t -> a -> b -^ ... >= ...' | | 275 | cfg.swift:275:1:277:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 275 | cfg.swift:275:25:275:25 | x | 'x -> y -^ Block' | -| 276 | cfg.swift:276:11:276:10 | | ' -> interpolation -V Argument -V x -^ interpolation(...) -> + -> interpolation -V Argument -V y -^ interpolation(...) -> is equal to -> interpolation -V Argument -V x -> y -^ ... + ... -^ interpolation(...) -> and here is a zero: -> interpolation -V Argument -V returnZero -^ returnZero(...) -^ interpolation(...) -> -^ StringInterpolationExpr -^ ReturnExpr' | -| 279 | cfg.swift:279:1:310:1 | Block | 'Block' | +| 275 | cfg.swift:275:25:275:25 | x | 'x -> y -> Block' | +| 276 | cfg.swift:276:11:276:10 | | ' -> interpolation -> Argument -V x -^ interpolation(...) -> + -> interpolation -> Argument -V y -^ interpolation(...) -> is equal to -> interpolation -> Argument -V x -> y -^ ... + ... -^ interpolation(...) -> and here is a zero: -> interpolation -> Argument -V returnZero -^ returnZero(...) -^ interpolation(...) -> -^ StringInterpolationExpr -^ ReturnExpr' | | 279 | cfg.swift:279:1:310:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 279 | cfg.swift:279:55:310:1 | Block | 'Block' | | 280 | cfg.swift:280:3:280:44 | VariableDeclaration | 'VariableDeclaration -V a -> 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -^ ArrayLiteral' | | 281 | cfg.swift:281:3:281:3 | a | 'a -> Argument -V 0 -^ a(...) -> 0 -^ ... = ...' | | 282 | cfg.swift:282:3:282:3 | a | 'a -> Argument -V 1 -^ a(...) -> 1 -^ ... += ...' | @@ -246,16 +244,16 @@ | 305 | cfg.swift:305:3:305:3 | b | 'b -> Argument -V 9 -^ b(...) -> b -> Argument -V 8 -^ b(...) -> 1 -^ ... << ... -^ ... = ...' | | 306 | cfg.swift:306:3:306:3 | b | 'b -> Argument -V 10 -^ b(...) -> b -> Argument -V 9 -^ b(...) -> 1 -^ ... >> ... -^ ... = ...' | | 308 | cfg.swift:308:3:308:39 | VariableDeclaration | 'VariableDeclaration -V Argument -V a1 -> Argument -V a2 -> Argument -V a3 -> Argument -V a4 -> Argument -V a5 -^ TupleExpr -> tupleWithA' | -| 309 | cfg.swift:309:11:309:20 | Argument | 'Argument -V a1 -> b -> Argument -V 0 -^ b(...) -^ ... + ... -> Argument -V a2 -> b -> Argument -V 1 -^ b(...) -^ ... + ... -> Argument -V a3 -> b -> Argument -V 2 -^ b(...) -^ ... + ... -> Argument -V a4 -> b -> Argument -V 3 -^ b(...) -^ ... + ... -> Argument -V a5 -> b -> Argument -V 4 -^ b(...) -^ ... + ... -^ TupleExpr -^ ReturnExpr' | +| 309 | cfg.swift:309:11:309:19 | Argument | 'Argument -V a1 -> b -> Argument -V 0 -^ b(...) -^ ... + ... -> Argument -V a2 -> b -> Argument -V 1 -^ b(...) -^ ... + ... -> Argument -V a3 -> b -> Argument -V 2 -^ b(...) -^ ... + ... -> Argument -V a4 -> b -> Argument -V 3 -^ b(...) -^ ... + ... -> Argument -V a5 -> b -> Argument -V 4 -^ b(...) -^ ... + ... -^ TupleExpr -^ ReturnExpr' | | 312 | cfg.swift:312:1:317:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 312 | cfg.swift:312:12:312:12 | x | 'x -^ Block' | +| 312 | cfg.swift:312:12:312:12 | x | 'x -> Block' | | 313 | cfg.swift:313:3:316:3 | WhileStmt | 'WhileStmt' | | 313 | cfg.swift:313:9:313:9 | x | 'x -> 0 -^ ... >= ...' | | 313 | cfg.swift:313:16:316:3 | Block | 'Block' | | 314 | cfg.swift:314:5:314:9 | print | 'print -> Argument -V x -^ print(...)' | | 315 | cfg.swift:315:5:315:5 | x | 'x -> 1 -^ ... -= ...' | | 319 | cfg.swift:319:1:332:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 319 | cfg.swift:319:12:319:12 | x | 'x -^ Block' | +| 319 | cfg.swift:319:12:319:12 | x | 'x -> Block' | | 320 | cfg.swift:320:3:330:3 | WhileStmt | 'WhileStmt' | | 320 | cfg.swift:320:9:320:9 | x | 'x -> 0 -^ ... >= ...' | | 320 | cfg.swift:320:16:330:3 | Block | 'Block' | @@ -270,7 +268,7 @@ | 329 | cfg.swift:329:5:329:9 | print | 'print -> Argument -V "Iter" -^ print(...)' | | 331 | cfg.swift:331:3:331:7 | print | 'print -> Argument -V "Done" -^ print(...)' | | 334 | cfg.swift:334:1:349:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 334 | cfg.swift:334:18:334:18 | x | 'x -^ Block' | +| 334 | cfg.swift:334:18:334:18 | x | 'x -> Block' | | 335 | cfg.swift:335:3:348:3 | LabeledStmt | 'LabeledStmt -V WhileStmt' | | 335 | cfg.swift:335:16:335:16 | x | 'x -> 0 -^ ... >= ...' | | 335 | cfg.swift:335:23:348:3 | Block | 'Block' | @@ -288,44 +286,44 @@ | 345 | cfg.swift:345:7:345:11 | print | 'print -> Argument -V "Iter" -^ print(...)' | | 347 | cfg.swift:347:5:347:9 | print | 'print -> Argument -V "Done" -^ print(...)' | | 351 | cfg.swift:351:1:356:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 351 | cfg.swift:351:17:351:17 | x | 'x -^ Block' | +| 351 | cfg.swift:351:17:351:17 | x | 'x -> Block' | | 352 | cfg.swift:352:3:355:16 | DoWhileStmt | 'DoWhileStmt' | | 352 | cfg.swift:352:10:355:3 | Block | 'Block' | | 353 | cfg.swift:353:5:353:9 | print | 'print -> Argument -V x -^ print(...)' | | 354 | cfg.swift:354:5:354:5 | x | 'x -> 1 -^ ... -= ...' | | 355 | cfg.swift:355:11:355:11 | x | 'x -> 0 -^ ... >= ...' | -| 358 | cfg.swift:358:1:363:1 | Block | 'Block' | | 358 | cfg.swift:358:1:363:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 358 | cfg.swift:358:32:363:1 | Block | 'Block' | | 359 | cfg.swift:359:3:359:11 | VariableDeclaration | 'VariableDeclaration -V x -> 0' | | 360 | cfg.swift:360:3:362:3 | WhileStmt | 'WhileStmt' | | 360 | cfg.swift:360:9:360:9 | x | 'x -> 10 -^ ... < ...' | | 360 | cfg.swift:360:17:362:3 | Block | 'Block' | | 361 | cfg.swift:361:5:361:5 | x | 'x -> 1 -^ ... += ...' | | 365 | cfg.swift:365:1:374:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V OptionalC' | -| 366 | cfg.swift:366:3:366:11 | VariableDeclaration | 'VariableDeclaration -V c -> Optional -V C -^ GenericTypeExpr' | +| 366 | cfg.swift:366:3:366:11 | VariableDeclaration | 'VariableDeclaration -V c -> Optional -> C -^ GenericTypeExpr' | | 367 | cfg.swift:367:3:369:3 | ConstructorDeclaration | 'ConstructorDeclaration' | -| 367 | cfg.swift:367:8:367:10 | arg | 'arg -^ Block' | +| 367 | cfg.swift:367:8:367:10 | arg | 'arg -> Block' | | 368 | cfg.swift:368:5:368:5 | c | 'c -> arg -^ ... = ...' | -| 371 | cfg.swift:371:3:373:3 | Block | 'Block' | | 371 | cfg.swift:371:3:373:3 | FunctionDeclaration | 'FunctionDeclaration' | +| 371 | cfg.swift:371:28:373:3 | Block | 'Block' | | 372 | cfg.swift:372:12:372:12 | c | 'c -^ ReturnExpr' | | 376 | cfg.swift:376:1:378:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 376 | cfg.swift:376:19:376:19 | c | 'c -^ Block' | +| 376 | cfg.swift:376:19:376:19 | c | 'c -> Block' | | 377 | cfg.swift:377:10:377:10 | c | 'c -^ ... .getOptional -^ ... .getOptional(...) -^ ... .getMyInt -^ ... .getMyInt(...) -^ ReturnExpr' | | 380 | cfg.swift:380:1:384:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 380 | cfg.swift:380:18:380:18 | x | 'x -> y -^ Block' | +| 380 | cfg.swift:380:18:380:18 | x | 'x -> y -> Block' | | 381 | cfg.swift:381:10:383:3 | Block | 'Block' | | 381 | cfg.swift:381:13:381:21 | VariableDeclaration | 'VariableDeclaration -V z -> x -> y -^ ... + ... -> VariableDeclaration -V t -> "literal" -^ FunctionExpr -^ ReturnExpr' | | 382 | cfg.swift:382:12:382:12 | z | 'z -^ ReturnExpr' | | 386 | cfg.swift:386:1:388:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 386 | cfg.swift:386:23:386:23 | t | 't -^ Block' | +| 386 | cfg.swift:386:23:386:23 | t | 't -> Block' | | 387 | cfg.swift:387:10:387:10 | t | 't -^ ... .a -> t -^ ... .1 -^ ... + ... -> t -^ ... .c -^ ... + ... -> Argument -V 1 -> Argument -V 2 -> Argument -V 3 -^ TupleExpr -^ ... .0 -^ ... + ... -^ ReturnExpr' | -| 390 | cfg.swift:390:1:394:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -^ BaseType -V C' | -| 391 | cfg.swift:391:3:393:3 | Block | 'Block' | +| 390 | cfg.swift:390:1:394:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -> BaseType -V C' | | 391 | cfg.swift:391:3:393:3 | ConstructorDeclaration | 'ConstructorDeclaration' | +| 391 | cfg.swift:391:10:393:3 | Block | 'Block' | | 392 | cfg.swift:392:5:392:9 | super | 'super -^ ... .init -> Argument -V 0 -^ ... .init(...)' | | 396 | cfg.swift:396:1:404:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 396 | cfg.swift:396:21:396:21 | x | 'x -^ Block' | +| 396 | cfg.swift:396:21:396:21 | x | 'x -> Block' | | 397 | cfg.swift:397:3:402:3 | TryExpr | 'TryExpr -V Block' | | 398 | cfg.swift:398:5:398:24 | try ... | 'try ...' | | 398 | cfg.swift:398:9:398:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ mightThrow(...)' | @@ -335,26 +333,26 @@ | 403 | cfg.swift:403:10:403:10 | 0 | '0 -^ ReturnExpr' | | 406 | cfg.swift:406:1:415:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Structors' | | 407 | cfg.swift:407:3:407:16 | VariableDeclaration | 'VariableDeclaration -V field -> Int' | -| 408 | cfg.swift:408:3:410:3 | Block | 'Block' | | 408 | cfg.swift:408:3:410:3 | ConstructorDeclaration | 'ConstructorDeclaration' | +| 408 | cfg.swift:408:10:410:3 | Block | 'Block' | | 409 | cfg.swift:409:5:409:9 | field | 'field -> 10 -^ ... = ...' | -| 412 | cfg.swift:412:3:414:3 | Block | 'Block' | | 412 | cfg.swift:412:3:414:3 | DestructorDeclaration | 'DestructorDeclaration' | +| 412 | cfg.swift:412:10:414:3 | Block | 'Block' | | 413 | cfg.swift:413:5:413:9 | field | 'field -> 0 -^ ... = ...' | | 417 | cfg.swift:417:1:419:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 417 | cfg.swift:417:24:417:24 | x | 'x -> y -^ Block' | +| 417 | cfg.swift:417:24:417:24 | x | 'x -> y -> Block' | | 418 | cfg.swift:418:10:418:25 | MapLiteral | 'MapLiteral -^ ReturnExpr' | -| 421 | cfg.swift:421:1:444:1 | Block | 'Block' | | 421 | cfg.swift:421:1:444:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 421 | cfg.swift:421:33:444:1 | Block | 'Block' | | 422 | cfg.swift:422:3:427:3 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyLocalClass' | | 423 | cfg.swift:423:5:423:14 | VariableDeclaration | 'VariableDeclaration -V x -> Int' | -| 424 | cfg.swift:424:5:426:5 | Block | 'Block' | | 424 | cfg.swift:424:5:426:5 | ConstructorDeclaration | 'ConstructorDeclaration' | +| 424 | cfg.swift:424:12:426:5 | Block | 'Block' | | 425 | cfg.swift:425:7:425:7 | x | 'x -> 10 -^ ... = ...' | | 429 | cfg.swift:429:3:434:3 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyLocalStruct' | | 430 | cfg.swift:430:5:430:14 | VariableDeclaration | 'VariableDeclaration -V x -> Int' | -| 431 | cfg.swift:431:5:433:5 | Block | 'Block' | | 431 | cfg.swift:431:5:433:5 | ConstructorDeclaration | 'ConstructorDeclaration' | +| 431 | cfg.swift:431:12:433:5 | Block | 'Block' | | 432 | cfg.swift:432:7:432:7 | x | 'x -> 10 -^ ... = ...' | | 436 | cfg.swift:436:3:439:3 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyLocalEnum' | | 437 | cfg.swift:437:10:437:10 | VariableDeclaration | 'VariableDeclaration -V A' | @@ -365,10 +363,10 @@ | 447 | cfg.swift:447:3:447:13 | VariableDeclaration | 'VariableDeclaration -V x -> Int' | | 450 | cfg.swift:450:1:454:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V A' | | 451 | cfg.swift:451:3:451:11 | VariableDeclaration | 'VariableDeclaration -V b -> B' | -| 452 | cfg.swift:452:3:452:14 | VariableDeclaration | 'VariableDeclaration -V bs -> Array -V B -^ GenericTypeExpr' | -| 453 | cfg.swift:453:3:453:15 | VariableDeclaration | 'VariableDeclaration -V mayB -> Optional -V B -^ GenericTypeExpr' | +| 452 | cfg.swift:452:3:452:14 | VariableDeclaration | 'VariableDeclaration -V bs -> Array -> B -^ GenericTypeExpr' | +| 453 | cfg.swift:453:3:453:15 | VariableDeclaration | 'VariableDeclaration -V mayB -> Optional -> B -^ GenericTypeExpr' | | 456 | cfg.swift:456:1:466:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 456 | cfg.swift:456:11:456:11 | a | 'a -^ Block' | +| 456 | cfg.swift:456:11:456:11 | a | 'a -> Block' | | 457 | cfg.swift:457:3:457:24 | VariableDeclaration | 'VariableDeclaration -V kpGet_b_x -> ' | | 458 | cfg.swift:458:3:458:31 | VariableDeclaration | 'VariableDeclaration -V kpGet_bs_0_x -> ' | | 459 | cfg.swift:459:3:459:37 | VariableDeclaration | 'VariableDeclaration -V kpGet_mayB_force_x -> ' | @@ -377,16 +375,16 @@ | 463 | cfg.swift:463:3:463:51 | VariableDeclaration | 'VariableDeclaration -V apply_kpGet_bs_0_x -> a -> Argument -V kpGet_bs_0_x -^ a(...)' | | 464 | cfg.swift:464:3:464:63 | VariableDeclaration | 'VariableDeclaration -V apply_kpGet_mayB_force_x -> a -> Argument -V kpGet_mayB_force_x -^ a(...)' | | 465 | cfg.swift:465:3:465:51 | VariableDeclaration | 'VariableDeclaration -V apply_kpGet_mayB_x -> a -> Argument -V kpGet_mayB_x -^ a(...)' | -| 468 | cfg.swift:468:1:495:1 | Block | 'Block' | | 468 | cfg.swift:468:1:495:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 468 | cfg.swift:468:21:495:1 | Block | 'Block' | | 469 | cfg.swift:469:1:475:6 | | '' | | 477 | cfg.swift:477:3:477:3 | 5 | '5' | | 479 | cfg.swift:479:1:482:6 | | '' | | 484 | cfg.swift:484:3:484:3 | 8 | '8' | | 486 | cfg.swift:486:1:492:6 | | '' | | 494 | cfg.swift:494:3:494:4 | 13 | '13' | -| 497 | cfg.swift:497:1:522:1 | Block | 'Block' | | 497 | cfg.swift:497:1:522:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 497 | cfg.swift:497:29:522:1 | Block | 'Block' | | 498 | cfg.swift:498:3:498:11 | VariableDeclaration | 'VariableDeclaration -V x -> 0' | | 500 | cfg.swift:500:3:502:3 | IfExpr | 'IfExpr -V ' | | 500 | cfg.swift:500:30:502:3 | Block | 'Block' | @@ -405,12 +403,12 @@ | 517 | cfg.swift:517:29:519:3 | Block | 'Block' | | 518 | cfg.swift:518:5:518:5 | x | 'x -> 1 -^ ... += ...' | | 521 | cfg.swift:521:10:521:10 | x | 'x -^ ReturnExpr' | -| 524 | cfg.swift:524:1:538:1 | Block | 'Block' | | 524 | cfg.swift:524:1:538:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 524 | cfg.swift:524:28:538:1 | Block | 'Block' | | 525 | cfg.swift:525:5:533:6 | VariableDeclaration | 'VariableDeclaration -V stream -> AsyncStream -> Argument -V Int -^ ... .self -> Argument -V . -^ ... .bufferingNewest -> Argument -V 5 -^ ... .bufferingNewest(...) -> Argument -V FunctionExpr -^ AsyncStream(...)' | | 525 | cfg.swift:525:78:533:5 | Block | 'Block' | | 526 | cfg.swift:526:9:526:20 | continuation | 'continuation' | -| 527 | cfg.swift:527:13:527:16 | Task | 'Task -^ ... .detached -^ Argument -V FunctionExpr -^ ... .detached(...)' | +| 527 | cfg.swift:527:13:527:16 | Task | 'Task -^ ... .detached -> Argument -V FunctionExpr -^ ... .detached(...)' | | 527 | cfg.swift:527:27:532:13 | Block | 'Block' | | 528 | cfg.swift:528:17:530:17 | ForEachStmt | 'ForEachStmt -V 1 -> 100 -^ ... ... ...' | | 528 | cfg.swift:528:21:528:21 | i | 'i -> Block' | @@ -420,12 +418,12 @@ | 535 | cfg.swift:535:19:535:19 | i | 'i -> Block' | | 536 | cfg.swift:536:9:536:13 | print | 'print -> Argument -V i -^ print(...)' | | 540 | cfg.swift:540:1:544:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 540 | cfg.swift:540:24:540:24 | x | 'x -^ Block' | +| 540 | cfg.swift:540:24:540:24 | x | 'x -> Block' | | 541 | cfg.swift:541:3:543:9 | ReturnExpr | 'ReturnExpr' | | 542 | cfg.swift:542:5:543:9 | ... ?? ... | '... ?? ... -V x' | | 543 | cfg.swift:543:9:543:9 | 0 | '0' | | 546 | cfg.swift:546:1:553:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 546 | cfg.swift:546:25:546:25 | x | 'x -^ Block' | +| 546 | cfg.swift:546:25:546:25 | x | 'x -> Block' | | 547 | cfg.swift:547:3:552:3 | IfExpr | 'IfExpr -V ... ?? ... -V x' | | 548 | cfg.swift:548:7:548:11 | false | 'false' | | 548 | cfg.swift:548:13:550:3 | Block | 'Block' | @@ -433,34 +431,34 @@ | 550 | cfg.swift:550:10:552:3 | Block | 'Block' | | 551 | cfg.swift:551:12:551:12 | 0 | '0 -^ ReturnExpr' | | 555 | cfg.swift:555:1:557:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 555 | cfg.swift:555:24:555:27 | expr | 'expr -^ Block' | +| 555 | cfg.swift:555:24:555:27 | expr | 'expr -> Block' | | 556 | cfg.swift:556:10:556:13 | expr | 'expr -^ expr(...) -^ ReturnExpr' | -| 559 | cfg.swift:559:1:561:1 | Block | 'Block' | | 559 | cfg.swift:559:1:561:1 | FunctionDeclaration | 'FunctionDeclaration' | +| 559 | cfg.swift:559:24:561:1 | Block | 'Block' | | 560 | cfg.swift:560:3:560:17 | usesAutoclosure | 'usesAutoclosure -> Argument -V 1 -^ usesAutoclosure(...)' | | 565 | cfg.swift:565:1:567:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyProtocol' | -| 566 | cfg.swift:566:2:566:21 | Block | 'Block' | +| 566 | cfg.swift:566:2:566:1 | Block | 'Block' | | 566 | cfg.swift:566:2:566:21 | FunctionDeclaration | 'FunctionDeclaration' | -| 569 | cfg.swift:569:1:571:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyProcotolImpl -^ BaseType -V MyProtocol' | -| 570 | cfg.swift:570:2:570:34 | Block | 'Block -V 0 -^ ReturnExpr' | +| 569 | cfg.swift:569:1:571:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyProcotolImpl -> BaseType -V MyProtocol' | | 570 | cfg.swift:570:2:570:34 | FunctionDeclaration | 'FunctionDeclaration' | -| 573 | cfg.swift:573:1:573:62 | Block | 'Block -V MyProcotolImpl -^ MyProcotolImpl(...) -^ ReturnExpr' | +| 570 | cfg.swift:570:23:570:34 | Block | 'Block -V 0 -^ ReturnExpr' | | 573 | cfg.swift:573:1:573:62 | FunctionDeclaration | 'FunctionDeclaration' | -| 574 | cfg.swift:574:1:574:70 | Block | 'Block -V MyProcotolImpl -^ MyProcotolImpl(...) -^ ReturnExpr' | +| 573 | cfg.swift:573:36:573:62 | Block | 'Block -V MyProcotolImpl -^ MyProcotolImpl(...) -^ ReturnExpr' | | 574 | cfg.swift:574:1:574:70 | FunctionDeclaration | 'FunctionDeclaration' | +| 574 | cfg.swift:574:44:574:70 | Block | 'Block -V MyProcotolImpl -^ MyProcotolImpl(...) -^ ReturnExpr' | | 576 | cfg.swift:576:1:576:23 | FunctionDeclaration | 'FunctionDeclaration' | -| 576 | cfg.swift:576:11:576:13 | arg | 'arg -^ Block' | +| 576 | cfg.swift:576:11:576:13 | arg | 'arg -> Block' | | 578 | cfg.swift:578:1:583:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 578 | cfg.swift:578:30:578:30 | x | 'x -> y -^ Block' | +| 578 | cfg.swift:578:30:578:30 | x | 'x -> y -> Block' | | 579 | cfg.swift:579:2:579:5 | sink | 'sink -> Argument -V x -^ ... .source -^ ... .source(...) -^ sink(...)' | | 580 | cfg.swift:580:2:580:5 | sink | 'sink -> Argument -V y -^ ... .source -^ ... .source(...) -^ sink(...)' | | 581 | cfg.swift:581:2:581:5 | sink | 'sink -> Argument -V getMyProtocol -^ getMyProtocol(...) -^ ... .source -^ ... .source(...) -^ sink(...)' | | 582 | cfg.swift:582:2:582:5 | sink | 'sink -> Argument -V getMyProtocolImpl -^ getMyProtocolImpl(...) -^ ... .source -^ ... .source(...) -^ sink(...)' | | 585 | cfg.swift:585:1:593:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 585 | cfg.swift:585:23:585:23 | x | 'x -^ Block' | +| 585 | cfg.swift:585:23:585:23 | x | 'x -> Block' | | 586 | cfg.swift:586:3:589:3 | VariableDeclaration | 'VariableDeclaration -V a -> SwitchExpr -V x' | -| 587 | cfg.swift:587:5:587:17 | Block | 'Block -V 1' | | 587 | cfg.swift:587:5:587:17 | SwitchCase | 'SwitchCase -V 0 -> 5 -^ ... ..< ...' | +| 587 | cfg.swift:587:17:587:17 | Block | 'Block -V 1' | | 588 | cfg.swift:588:5:588:14 | SwitchCase | 'SwitchCase -V Block -V 2' | | 590 | cfg.swift:590:3:592:18 | VariableDeclaration | 'VariableDeclaration -V b' | | 591 | cfg.swift:591:9:592:18 | IfExpr | 'IfExpr -V x -> 42 -^ ... < ...' | @@ -469,7 +467,7 @@ | 596 | cfg.swift:596:1:598:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V ValueGenericsStruct -> TypeParameter -V N -> Int' | | 597 | cfg.swift:597:5:597:13 | VariableDeclaration | 'VariableDeclaration -V x -> N' | | 600 | cfg.swift:600:1:604:1 | FunctionDeclaration | 'FunctionDeclaration' | -| 600 | cfg.swift:600:36:600:40 | value | 'value -^ Block' | +| 600 | cfg.swift:600:36:600:40 | value | 'value -> Block' | | 601 | cfg.swift:601:5:601:13 | VariableDeclaration | 'VariableDeclaration -V x -> N' | | 602 | cfg.swift:602:5:602:9 | print | 'print -> Argument -V x -^ print(...)' | | 603 | cfg.swift:603:5:603:5 | _ | '_ -> value -^ ... = ...' | diff --git a/unified/ql/test/library-tests/controlflow/cfg.expected b/unified/ql/test/library-tests/controlflow/cfg.expected index 4024690a7111..36cf5e6d224b 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.expected +++ b/unified/ql/test/library-tests/controlflow/cfg.expected @@ -1,6 +1,8 @@ +nonSimple +| cfg.swift:12:17:12:25 | withParam | 'withParam -? Block' | +| cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ ... .error1 -> isZero -> Argument -V x -^ isZero(...) -? MyError -^ ... .error2 -^ ConditionalPattern -^ OrPattern' | bbContinues | cfg.swift:62:6:62:6 | y | 'y goto Block(-1)' | -| cfg.swift:147:5:147:5 | Block | 'Block goto true(+3)' | | cfg.swift:525:78:525:78 | Block | 'Block goto Task(+2)' | | cfg.swift:526:9:526:20 | continuation | 'continuation goto Block(-1)' | bbStep @@ -10,8 +12,8 @@ bbStep | cfg.swift:30:9:30:24 | mightThrow(...) | 'mightThrow(...) : exception -> CatchClause(+5)' | | cfg.swift:30:9:30:24 | mightThrow(...) | 'mightThrow(...) : successor -> try ...(+0)' | | cfg.swift:33:5:33:33 | print(...) | 'print(...) : successor -> 0(+11)' | -| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : match -> Block(+0)' | -| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : no-match -> CatchClause(+2)' | +| cfg.swift:35:11:35:60 | OrPattern | 'OrPattern : match -> Block(+0)' | +| cfg.swift:35:11:35:60 | OrPattern | 'OrPattern : no-match -> CatchClause(+2)' | | cfg.swift:37:11:37:39 | ... .error3(...) | '... .error3(...) : match -> Block(+0)' | | cfg.swift:37:11:37:39 | ... .error3(...) | '... .error3(...) : no-match -> CatchClause(+2)' | | cfg.swift:39:11:39:20 | | ' : match -> Block(+0)' | @@ -22,9 +24,9 @@ bbStep | cfg.swift:140:12:140:17 | ... ... ... | '... ... ... : non-empty -> _(+0)' | | cfg.swift:141:9:141:12 | Block | 'Block : successor -> SwitchExpr(+2)' | | cfg.swift:141:9:141:12 | Block | 'Block : successor -> _(-1)' | -| cfg.swift:144:5:144:5 | OrPattern | 'OrPattern : match -> Block(+0)' | -| cfg.swift:144:5:144:5 | OrPattern | 'OrPattern : no-match -> SwitchCase(+3)' | -| cfg.swift:147:10:147:10 | ConditionalPattern | 'ConditionalPattern : match -> Block(+0)' | +| cfg.swift:144:10:144:13 | OrPattern | 'OrPattern : match -> Block(+1)' | +| cfg.swift:144:10:144:13 | OrPattern | 'OrPattern : no-match -> SwitchCase(+3)' | +| cfg.swift:147:10:147:10 | ConditionalPattern | 'ConditionalPattern : match -> Block(+3)' | | cfg.swift:147:10:147:10 | ConditionalPattern | 'ConditionalPattern : no-match -> SwitchCase(+4)' | | cfg.swift:148:10:148:15 | ... >= ... | '... >= ... : false -> x(-1)' | | cfg.swift:148:10:148:15 | ... >= ... | '... >= ... : true -> x(+1)' | @@ -162,9 +164,3 @@ noCfg | cfg.swift:497:6:497:18 | testAvailable | | cfg.swift:524:6:524:17 | testAsyncFor | | cfg.swift:559:6:559:20 | autoclosureTest | -nonSimple -| cfg.swift:10:1:10:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' | -| cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ ... .error1 -> isZero -> Argument -V x -^ isZero(...) -? MyError -^ ... .error2 -^ ConditionalPattern -^ OrPattern' | -| cfg.swift:390:1:390:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -^ BaseType -V C' | -| cfg.swift:527:13:527:16 | Task | 'Task -^ ... .detached -^ Argument -V FunctionExpr -^ ... .detached(...)' | -| cfg.swift:569:1:569:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyProcotolImpl -^ BaseType -V MyProtocol' | diff --git a/unified/ql/test/library-tests/controlflow/cfg.swift b/unified/ql/test/library-tests/controlflow/cfg.swift index e0b598f74fe9..ef4c3ab8b6ae 100644 --- a/unified/ql/test/library-tests/controlflow/cfg.swift +++ b/unified/ql/test/library-tests/controlflow/cfg.swift @@ -7,9 +7,9 @@ func returnZero() -> Int { return 0 } returnZero() Double(topLevelDecl) -enum MyError: Error { // $ nonSimple='ClassLikeDeclaration -V MyError -^ BaseType -V Error' +enum MyError: Error { case error1, error2 - case error3(withParam: Int) + case error3(withParam: Int) // $ nonSimple='withParam -? Block' } func isZero(x : Int) -> Bool { @@ -141,10 +141,10 @@ func patterns(x : Int) -> Bool { { } // $ bbStep='Block : successor -> _(-1)' bbStep='Block : successor -> SwitchExpr(+2)' switch x { - case 0, 1: // $ bbStep='OrPattern : match -> Block(+0)' bbStep='OrPattern : no-match -> SwitchCase(+3)' + case 0, 1: // $ bbStep='OrPattern : match -> Block(+1)' bbStep='OrPattern : no-match -> SwitchCase(+3)' return true return true // $ noCfg - case x where // $ bbContinues='Block goto true(+3)' bbStep='ConditionalPattern : match -> Block(+0)' bbStep='ConditionalPattern : no-match -> SwitchCase(+4)' + case x where // $ bbStep='ConditionalPattern : match -> Block(+3)' bbStep='ConditionalPattern : no-match -> SwitchCase(+4)' (x >= 2) && // $ bbStep='... >= ... : false -> x(-1)' bbStep='... >= ... : true -> x(+1)' x < 5: // $ bbStep='... < ... : successor -> x(-2)' return true @@ -387,7 +387,7 @@ func testTupleElement(t : (a: Int, Int, c: Int)) -> Int { return t.a + t.1 + t.c + (1, 2, 3).0 } -class Derived : C { // $ nonSimple='ClassLikeDeclaration -V Derived -^ BaseType -V C' +class Derived : C { init() { // $ noCfg super.init(n: 0) } @@ -524,7 +524,7 @@ func testAvailable() -> Int { // $ noCfg func testAsyncFor () async { // $ noCfg var stream = AsyncStream(Int.self, bufferingPolicy: .bufferingNewest(5), { // $ bbContinues='Block goto Task(+2)' continuation in // $ bbContinues='continuation goto Block(-1)' - Task.detached { // $ nonSimple='Task -^ ... .detached -^ Argument -V FunctionExpr -^ ... .detached(...)' + Task.detached { for i in 1...100 { // $ bbStep='... ... ... : empty -> continuation(+3)' bbStep='... ... ... : non-empty -> i(+0)' continuation.yield(i) // $ bbStep='... .yield(...) : successor -> continuation(+2)' bbStep='... .yield(...) : successor -> i(-1)' } @@ -566,7 +566,7 @@ protocol MyProtocol { func source() -> Int } -class MyProcotolImpl : MyProtocol { // $ nonSimple='ClassLikeDeclaration -V MyProcotolImpl -^ BaseType -V MyProtocol' +class MyProcotolImpl : MyProtocol { func source() -> Int { return 0 } } diff --git a/unified/ql/test/library-tests/dataflow/test.expected b/unified/ql/test/library-tests/dataflow/test.expected index 09bfb86d7540..33b52e1af3f4 100644 --- a/unified/ql/test/library-tests/dataflow/test.expected +++ b/unified/ql/test/library-tests/dataflow/test.expected @@ -4,7 +4,7 @@ edges | calls.swift:10:12:10:25 | source(...) | calls.swift:7:19:7:19 | x | provenance | | | calls.swift:15:16:15:29 | source(...) | calls.swift:17:10:17:17 | target(...) | provenance | | | calls.swift:21:17:21:17 | x | calls.swift:22:14:22:14 | x | provenance | | -| calls.swift:24:12:24:28 | source(...) | calls.swift:21:17:21:17 | x | provenance | | +| calls.swift:24:15:24:28 | source(...) | calls.swift:21:17:21:17 | x | provenance | | | calls.swift:28:19:28:19 | x | calls.swift:29:16:29:16 | x | provenance | | | calls.swift:29:16:29:16 | x | calls.swift:29:16:29:24 | ... + ... | provenance | | | calls.swift:31:17:31:30 | source(...) | calls.swift:28:19:28:19 | x | provenance | | @@ -12,12 +12,12 @@ edges | calls.swift:32:17:32:30 | source(...) | calls.swift:28:19:28:19 | x | provenance | | | calls.swift:32:17:32:30 | source(...) | calls.swift:32:10:32:31 | target(...) | provenance | | | calls.swift:37:23:37:23 | x | calls.swift:38:14:38:14 | x | provenance | | -| calls.swift:40:13:40:32 | source(...) | calls.swift:37:23:37:23 | x | provenance | | +| calls.swift:40:19:40:32 | source(...) | calls.swift:37:23:37:23 | x | provenance | | | calls.swift:42:18:42:21 | name | calls.swift:43:14:43:17 | name | provenance | | -| calls.swift:45:13:45:32 | source(...) | calls.swift:42:18:42:21 | name | provenance | | +| calls.swift:45:19:45:32 | source(...) | calls.swift:42:18:42:21 | name | provenance | | | calls.swift:49:19:49:19 | x | calls.swift:50:14:50:14 | x | provenance | | | calls.swift:49:32:49:32 | y | calls.swift:51:14:51:14 | y | provenance | | -| calls.swift:53:12:53:26 | source(...) | calls.swift:49:19:49:19 | x | provenance | | +| calls.swift:53:12:53:25 | source(...) | calls.swift:49:19:49:19 | x | provenance | | | calls.swift:53:28:53:41 | source(...) | calls.swift:49:32:49:32 | y | provenance | | | calls.swift:61:19:61:19 | x [Return] [field] | calls.swift:66:12:66:12 | [post] b [field] | provenance | | | calls.swift:62:9:62:9 | [post] x [field] | calls.swift:61:19:61:19 | x [Return] [field] | provenance | | @@ -88,7 +88,7 @@ edges | test.swift:21:18:21:31 | source(...) | test.swift:21:10:21:33 | StringInterpolationExpr | provenance | | | test.swift:22:18:22:31 | source(...) | test.swift:22:10:22:38 | StringInterpolationExpr | provenance | | | test.swift:27:10:27:33 | TupleExpr [0] | test.swift:27:10:27:35 | ... .0 | provenance | | -| test.swift:27:11:27:25 | source(...) | test.swift:27:10:27:33 | TupleExpr [0] | provenance | | +| test.swift:27:11:27:24 | source(...) | test.swift:27:10:27:33 | TupleExpr [0] | provenance | | | test.swift:30:10:30:33 | TupleExpr [1] | test.swift:30:10:30:35 | ... .1 | provenance | | | test.swift:30:19:30:32 | source(...) | test.swift:30:10:30:33 | TupleExpr [1] | provenance | | | test.swift:34:9:34:9 | a | test.swift:35:10:35:10 | a | provenance | | @@ -96,7 +96,7 @@ edges | test.swift:39:9:39:14 | TupleExpr [0] | test.swift:39:10:39:10 | a | provenance | | | test.swift:39:10:39:10 | a | test.swift:40:10:40:10 | a | provenance | | | test.swift:39:18:39:41 | TupleExpr [0] | test.swift:39:9:39:14 | TupleExpr [0] | provenance | | -| test.swift:39:19:39:33 | source(...) | test.swift:39:18:39:41 | TupleExpr [0] | provenance | | +| test.swift:39:19:39:32 | source(...) | test.swift:39:18:39:41 | TupleExpr [0] | provenance | | | test.swift:43:9:43:14 | TupleExpr [1] | test.swift:43:13:43:13 | d | provenance | | | test.swift:43:13:43:13 | d | test.swift:45:10:45:10 | d | provenance | | | test.swift:43:18:43:41 | TupleExpr [1] | test.swift:43:9:43:14 | TupleExpr [1] | provenance | | @@ -117,7 +117,7 @@ edges | test.swift:75:6:75:10 | [post] tuple [1] | test.swift:77:10:77:14 | tuple [1] | provenance | | | test.swift:75:6:75:12 | ... .1 | test.swift:75:6:75:10 | [post] tuple [1] | provenance | | | test.swift:75:20:75:51 | TupleExpr [0] | test.swift:75:5:75:16 | TupleExpr [0] | provenance | | -| test.swift:75:21:75:35 | source(...) | test.swift:75:20:75:51 | TupleExpr [0] | provenance | | +| test.swift:75:21:75:34 | source(...) | test.swift:75:20:75:51 | TupleExpr [0] | provenance | | | test.swift:77:10:77:14 | tuple [1] | test.swift:77:10:77:16 | ... .1 | provenance | | | test.swift:85:5:85:9 | [post] tuple [0] | test.swift:86:10:86:14 | tuple [0] | provenance | | | test.swift:85:5:85:11 | ... .0 | test.swift:85:5:85:9 | [post] tuple [0] | provenance | | @@ -137,7 +137,7 @@ edges | test.swift:128:9:128:13 | tuple [1] | test.swift:131:18:131:22 | tuple [1] | provenance | | | test.swift:128:17:128:50 | TupleExpr [0] | test.swift:128:9:128:13 | tuple [0] | provenance | | | test.swift:128:17:128:50 | TupleExpr [1] | test.swift:128:9:128:13 | tuple [1] | provenance | | -| test.swift:128:18:128:33 | source(...) | test.swift:128:17:128:50 | TupleExpr [0] | provenance | | +| test.swift:128:18:128:32 | source(...) | test.swift:128:17:128:50 | TupleExpr [0] | provenance | | | test.swift:128:35:128:49 | source(...) | test.swift:128:17:128:50 | TupleExpr [1] | provenance | | | test.swift:131:9:131:14 | TupleExpr [0] | test.swift:131:10:131:10 | a | provenance | | | test.swift:131:9:131:14 | TupleExpr [1] | test.swift:131:13:131:13 | b | provenance | | @@ -180,7 +180,7 @@ nodes | calls.swift:17:10:17:17 | target(...) | semmle.label | target(...) | | calls.swift:21:17:21:17 | x | semmle.label | x | | calls.swift:22:14:22:14 | x | semmle.label | x | -| calls.swift:24:12:24:28 | source(...) | semmle.label | source(...) | +| calls.swift:24:15:24:28 | source(...) | semmle.label | source(...) | | calls.swift:28:19:28:19 | x | semmle.label | x | | calls.swift:29:16:29:16 | x | semmle.label | x | | calls.swift:29:16:29:24 | ... + ... | semmle.label | ... + ... | @@ -190,15 +190,15 @@ nodes | calls.swift:32:17:32:30 | source(...) | semmle.label | source(...) | | calls.swift:37:23:37:23 | x | semmle.label | x | | calls.swift:38:14:38:14 | x | semmle.label | x | -| calls.swift:40:13:40:32 | source(...) | semmle.label | source(...) | +| calls.swift:40:19:40:32 | source(...) | semmle.label | source(...) | | calls.swift:42:18:42:21 | name | semmle.label | name | | calls.swift:43:14:43:17 | name | semmle.label | name | -| calls.swift:45:13:45:32 | source(...) | semmle.label | source(...) | +| calls.swift:45:19:45:32 | source(...) | semmle.label | source(...) | | calls.swift:49:19:49:19 | x | semmle.label | x | | calls.swift:49:32:49:32 | y | semmle.label | y | | calls.swift:50:14:50:14 | x | semmle.label | x | | calls.swift:51:14:51:14 | y | semmle.label | y | -| calls.swift:53:12:53:26 | source(...) | semmle.label | source(...) | +| calls.swift:53:12:53:25 | source(...) | semmle.label | source(...) | | calls.swift:53:28:53:41 | source(...) | semmle.label | source(...) | | calls.swift:61:19:61:19 | x [Return] [field] | semmle.label | x [Return] [field] | | calls.swift:62:9:62:9 | [post] x [field] | semmle.label | [post] x [field] | @@ -290,7 +290,7 @@ nodes | test.swift:22:18:22:31 | source(...) | semmle.label | source(...) | | test.swift:27:10:27:33 | TupleExpr [0] | semmle.label | TupleExpr [0] | | test.swift:27:10:27:35 | ... .0 | semmle.label | ... .0 | -| test.swift:27:11:27:25 | source(...) | semmle.label | source(...) | +| test.swift:27:11:27:24 | source(...) | semmle.label | source(...) | | test.swift:30:10:30:33 | TupleExpr [1] | semmle.label | TupleExpr [1] | | test.swift:30:10:30:35 | ... .1 | semmle.label | ... .1 | | test.swift:30:19:30:32 | source(...) | semmle.label | source(...) | @@ -300,7 +300,7 @@ nodes | test.swift:39:9:39:14 | TupleExpr [0] | semmle.label | TupleExpr [0] | | test.swift:39:10:39:10 | a | semmle.label | a | | test.swift:39:18:39:41 | TupleExpr [0] | semmle.label | TupleExpr [0] | -| test.swift:39:19:39:33 | source(...) | semmle.label | source(...) | +| test.swift:39:19:39:32 | source(...) | semmle.label | source(...) | | test.swift:40:10:40:10 | a | semmle.label | a | | test.swift:43:9:43:14 | TupleExpr [1] | semmle.label | TupleExpr [1] | | test.swift:43:13:43:13 | d | semmle.label | d | @@ -326,7 +326,7 @@ nodes | test.swift:75:6:75:10 | [post] tuple [1] | semmle.label | [post] tuple [1] | | test.swift:75:6:75:12 | ... .1 | semmle.label | ... .1 | | test.swift:75:20:75:51 | TupleExpr [0] | semmle.label | TupleExpr [0] | -| test.swift:75:21:75:35 | source(...) | semmle.label | source(...) | +| test.swift:75:21:75:34 | source(...) | semmle.label | source(...) | | test.swift:77:10:77:14 | tuple [1] | semmle.label | tuple [1] | | test.swift:77:10:77:16 | ... .1 | semmle.label | ... .1 | | test.swift:85:5:85:9 | [post] tuple [0] | semmle.label | [post] tuple [0] | @@ -351,7 +351,7 @@ nodes | test.swift:128:9:128:13 | tuple [1] | semmle.label | tuple [1] | | test.swift:128:17:128:50 | TupleExpr [0] | semmle.label | TupleExpr [0] | | test.swift:128:17:128:50 | TupleExpr [1] | semmle.label | TupleExpr [1] | -| test.swift:128:18:128:33 | source(...) | semmle.label | source(...) | +| test.swift:128:18:128:32 | source(...) | semmle.label | source(...) | | test.swift:128:35:128:49 | source(...) | semmle.label | source(...) | | test.swift:131:9:131:14 | TupleExpr [0] | semmle.label | TupleExpr [0] | | test.swift:131:9:131:14 | TupleExpr [1] | semmle.label | TupleExpr [1] | @@ -402,12 +402,12 @@ testFailures #select | calls.swift:8:14:8:14 | x | calls.swift:10:12:10:25 | source(...) | calls.swift:8:14:8:14 | x | $@ | calls.swift:10:12:10:25 | source(...) | source(...) | | calls.swift:17:10:17:17 | target(...) | calls.swift:15:16:15:29 | source(...) | calls.swift:17:10:17:17 | target(...) | $@ | calls.swift:15:16:15:29 | source(...) | source(...) | -| calls.swift:22:14:22:14 | x | calls.swift:24:12:24:28 | source(...) | calls.swift:22:14:22:14 | x | $@ | calls.swift:24:12:24:28 | source(...) | source(...) | +| calls.swift:22:14:22:14 | x | calls.swift:24:15:24:28 | source(...) | calls.swift:22:14:22:14 | x | $@ | calls.swift:24:15:24:28 | source(...) | source(...) | | calls.swift:31:10:31:31 | target(...) | calls.swift:31:17:31:30 | source(...) | calls.swift:31:10:31:31 | target(...) | $@ | calls.swift:31:17:31:30 | source(...) | source(...) | | calls.swift:32:10:32:31 | target(...) | calls.swift:32:17:32:30 | source(...) | calls.swift:32:10:32:31 | target(...) | $@ | calls.swift:32:17:32:30 | source(...) | source(...) | -| calls.swift:38:14:38:14 | x | calls.swift:40:13:40:32 | source(...) | calls.swift:38:14:38:14 | x | $@ | calls.swift:40:13:40:32 | source(...) | source(...) | -| calls.swift:43:14:43:17 | name | calls.swift:45:13:45:32 | source(...) | calls.swift:43:14:43:17 | name | $@ | calls.swift:45:13:45:32 | source(...) | source(...) | -| calls.swift:50:14:50:14 | x | calls.swift:53:12:53:26 | source(...) | calls.swift:50:14:50:14 | x | $@ | calls.swift:53:12:53:26 | source(...) | source(...) | +| calls.swift:38:14:38:14 | x | calls.swift:40:19:40:32 | source(...) | calls.swift:38:14:38:14 | x | $@ | calls.swift:40:19:40:32 | source(...) | source(...) | +| calls.swift:43:14:43:17 | name | calls.swift:45:19:45:32 | source(...) | calls.swift:43:14:43:17 | name | $@ | calls.swift:45:19:45:32 | source(...) | source(...) | +| calls.swift:50:14:50:14 | x | calls.swift:53:12:53:25 | source(...) | calls.swift:50:14:50:14 | x | $@ | calls.swift:53:12:53:25 | source(...) | source(...) | | calls.swift:51:14:51:14 | y | calls.swift:53:28:53:41 | source(...) | calls.swift:51:14:51:14 | y | $@ | calls.swift:53:28:53:41 | source(...) | source(...) | | calls.swift:67:10:67:16 | ... .field | calls.swift:62:19:62:32 | source(...) | calls.swift:67:10:67:16 | ... .field | $@ | calls.swift:62:19:62:32 | source(...) | source(...) | | calls.swift:81:18:81:22 | field | calls.swift:75:21:75:34 | source(...) | calls.swift:81:18:81:22 | field | $@ | calls.swift:75:21:75:34 | source(...) | source(...) | @@ -436,22 +436,22 @@ testFailures | test.swift:20:10:20:33 | StringInterpolationExpr | test.swift:20:13:20:26 | source(...) | test.swift:20:10:20:33 | StringInterpolationExpr | $@ | test.swift:20:13:20:26 | source(...) | source(...) | | test.swift:21:10:21:33 | StringInterpolationExpr | test.swift:21:18:21:31 | source(...) | test.swift:21:10:21:33 | StringInterpolationExpr | $@ | test.swift:21:18:21:31 | source(...) | source(...) | | test.swift:22:10:22:38 | StringInterpolationExpr | test.swift:22:18:22:31 | source(...) | test.swift:22:10:22:38 | StringInterpolationExpr | $@ | test.swift:22:18:22:31 | source(...) | source(...) | -| test.swift:27:10:27:35 | ... .0 | test.swift:27:11:27:25 | source(...) | test.swift:27:10:27:35 | ... .0 | $@ | test.swift:27:11:27:25 | source(...) | source(...) | +| test.swift:27:10:27:35 | ... .0 | test.swift:27:11:27:24 | source(...) | test.swift:27:10:27:35 | ... .0 | $@ | test.swift:27:11:27:24 | source(...) | source(...) | | test.swift:30:10:30:35 | ... .1 | test.swift:30:19:30:32 | source(...) | test.swift:30:10:30:35 | ... .1 | $@ | test.swift:30:19:30:32 | source(...) | source(...) | | test.swift:35:10:35:10 | a | test.swift:34:13:34:26 | source(...) | test.swift:35:10:35:10 | a | $@ | test.swift:34:13:34:26 | source(...) | source(...) | -| test.swift:40:10:40:10 | a | test.swift:39:19:39:33 | source(...) | test.swift:40:10:40:10 | a | $@ | test.swift:39:19:39:33 | source(...) | source(...) | +| test.swift:40:10:40:10 | a | test.swift:39:19:39:32 | source(...) | test.swift:40:10:40:10 | a | $@ | test.swift:39:19:39:32 | source(...) | source(...) | | test.swift:45:10:45:10 | d | test.swift:43:27:43:40 | source(...) | test.swift:45:10:45:10 | d | $@ | test.swift:43:27:43:40 | source(...) | source(...) | | test.swift:50:10:50:10 | a | test.swift:49:13:49:26 | source(...) | test.swift:50:10:50:10 | a | $@ | test.swift:49:13:49:26 | source(...) | source(...) | | test.swift:58:10:58:16 | ... .0 | test.swift:57:15:57:28 | source(...) | test.swift:58:10:58:16 | ... .0 | $@ | test.swift:57:15:57:28 | source(...) | source(...) | | test.swift:69:10:69:23 | ... .0 | test.swift:64:22:64:35 | source(...) | test.swift:69:10:69:23 | ... .0 | $@ | test.swift:64:22:64:35 | source(...) | source(...) | -| test.swift:77:10:77:16 | ... .1 | test.swift:75:21:75:35 | source(...) | test.swift:77:10:77:16 | ... .1 | $@ | test.swift:75:21:75:35 | source(...) | source(...) | +| test.swift:77:10:77:16 | ... .1 | test.swift:75:21:75:34 | source(...) | test.swift:77:10:77:16 | ... .1 | $@ | test.swift:75:21:75:34 | source(...) | source(...) | | test.swift:86:10:86:16 | ... .0 | test.swift:85:15:85:29 | source(...) | test.swift:86:10:86:16 | ... .0 | $@ | test.swift:85:15:85:29 | source(...) | source(...) | | test.swift:101:10:101:10 | x | test.swift:97:13:97:27 | source(...) | test.swift:101:10:101:10 | x | $@ | test.swift:97:13:97:27 | source(...) | source(...) | | test.swift:107:10:107:10 | y | test.swift:105:13:105:27 | source(...) | test.swift:107:10:107:10 | y | $@ | test.swift:105:13:105:27 | source(...) | source(...) | | test.swift:110:14:110:14 | x | test.swift:97:13:97:27 | source(...) | test.swift:110:14:110:14 | x | $@ | test.swift:97:13:97:27 | source(...) | source(...) | | test.swift:111:14:111:14 | y | test.swift:105:13:105:27 | source(...) | test.swift:111:14:111:14 | y | $@ | test.swift:105:13:105:27 | source(...) | source(...) | | test.swift:123:10:123:16 | ... .0 | test.swift:118:19:118:33 | source(...) | test.swift:123:10:123:16 | ... .0 | $@ | test.swift:118:19:118:33 | source(...) | source(...) | -| test.swift:136:10:136:10 | a | test.swift:128:18:128:33 | source(...) | test.swift:136:10:136:10 | a | $@ | test.swift:128:18:128:33 | source(...) | source(...) | +| test.swift:136:10:136:10 | a | test.swift:128:18:128:32 | source(...) | test.swift:136:10:136:10 | a | $@ | test.swift:128:18:128:32 | source(...) | source(...) | | test.swift:137:10:137:10 | b | test.swift:128:35:128:49 | source(...) | test.swift:137:10:137:10 | b | $@ | test.swift:128:35:128:49 | source(...) | source(...) | | test.swift:143:10:143:10 | a | test.swift:142:19:142:33 | source(...) | test.swift:143:10:143:10 | a | $@ | test.swift:142:19:142:33 | source(...) | source(...) | | test.swift:149:10:149:10 | a | test.swift:148:10:148:24 | source(...) | test.swift:149:10:149:10 | a | $@ | test.swift:148:10:148:24 | source(...) | source(...) | From d9211f76c08e5281f98e004e8831f2fa5fd7985e Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 22 Sep 2026 16:05:53 +0200 Subject: [PATCH 13/14] yeast: Fix condition to return empty_at_start for range match Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- shared/yeast/src/range.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/yeast/src/range.rs b/shared/yeast/src/range.rs index 0daa631d24e0..c2d311610b83 100644 --- a/shared/yeast/src/range.rs +++ b/shared/yeast/src/range.rs @@ -78,9 +78,8 @@ impl Range { loop { let previous = self; for range in &ignored { - if *range == self { - self = self.empty_at_start(); - continue; +if *range == self { + return self.empty_at_start(); } if range.start_byte == self.start_byte && range.end_byte > range.start_byte { self.start_byte = range.end_byte; From 624cdfefc05aaffb1c46b59b2d9532df466ce1e1 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 22 Sep 2026 16:08:39 +0200 Subject: [PATCH 14/14] Unified: Update Swift initializer declaration rule Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- unified/extractor/src/languages/swift/swift.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index e1c78c59af6b..81a4137331d7 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1378,12 +1378,14 @@ fn translation_rules() -> Vec> { ), rule!( (initializerDecl + initKeyword: @initK modifiers: _* @mods signature: (functionSignature parameterClause: (functionParameterClause parameters: _* @params))) => (constructor_declaration modifier: {mods} + name_node: (identifier #{initK}) parameter: {params} body: (block)) ),