Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions internal/postprocess/collapsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ func suppressInlineParentRedundancy(
}
}

// suppressCoextensiveWrappers climbs single-line parents and suppresses wrapper actions
// that are truly coextensive with the child (exact same byte range).
// suppressCoextensiveWrappers walks single-line parents and drops wrapper actions
// that share the child's start byte, like single-child statements with trailing
// semicolons or scaffolding.
func suppressCoextensiveWrappers(
node *treesitter.ASTNode,
actionMap map[*treesitter.ASTNode]*actions.Action,
Expand All @@ -242,14 +243,12 @@ func suppressCoextensiveWrappers(
if r != nil && r.IsPair(parent.Type) {
continue
}
// Strict opening invariant: parent must not start before child (protects {hash}, [array], (expr))
if parent.StartByte == node.StartByte {
// Only suppress if parent is truly coextensive (exact same EndByte) and is a single-child or scaffolding wrapper
if parent.EndByte == node.EndByte && (len(parent.Children) <= 1 || parent.IsScaffolding()) {
parentAct := actionMap[parent]
if parentAct != nil && !suppressed[parentAct] && !parentAct.Subtree {
suppressed[parentAct] = true
}
// Parent can't start before the child: keeps opening delimiters like {hash}, [array], or (expr) intact.
if parent.StartByte == node.StartByte &&
(len(parent.Children) <= 1 || parent.IsScaffolding() || parent.EndByte == node.EndByte) {
parentAct := actionMap[parent]
if parentAct != nil && !suppressed[parentAct] && !parentAct.Subtree {
suppressed[parentAct] = true
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions internal/postprocess/collapsing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,7 @@ func TestInlineParentSuppression(t *testing.T) {
}
})

// (h) Trailing statement terminator (semicolon) in single-child expression_statement
// must STILL suppress the parent wrapper Insert even though parent.EndByte > dstChild.EndByte.
// (h) Trailing semicolons shouldn't keep single-child wrappers alive when their child moves.
t.Run("moved-child-suppresses-inline-parent-insert-with-semicolon", func(t *testing.T) {
srcChild := &treesitter.ASTNode{
Type: "assignment_expression",
Expand Down Expand Up @@ -580,17 +579,17 @@ func TestInlineParentSuppression(t *testing.T) {
moveSurvives = true
}
}
if !parentSurvives {
t.Error("expected parent expression_statement Insert with trailing semicolon to survive for delimiter coverage")
if parentSurvives {
t.Error("expected parent expression_statement Insert with trailing semicolon to be suppressed")
}
if !moveSurvives {
t.Error("expected child assignment_expression Move to survive")
}
})

// (i) Bidirectional symmetry: source-side single-line statement wrapper Delete is preserved
// when parent contains trailing delimiter punctuation (e.g. semicolon).
t.Run("moved-child-preserves-source-side-parent-delete-with-semicolon", func(t *testing.T) {
// (i) Symmetrical delete: source-side single-line statement wrappers with trailing
// semicolons get dropped too when their child moves.
t.Run("moved-child-suppresses-source-side-parent-delete-with-semicolon", func(t *testing.T) {
srcChild := &treesitter.ASTNode{
Type: "assignment_expression",
StartByte: 100, EndByte: 120,
Expand Down Expand Up @@ -633,8 +632,8 @@ func TestInlineParentSuppression(t *testing.T) {
moveSurvives = true
}
}
if !srcParentSurvives {
t.Error("expected source-side parent expression_statement Delete with trailing semicolon to survive")
if srcParentSurvives {
t.Error("expected source-side parent expression_statement Delete with trailing semicolon to be suppressed")
}
if !moveSurvives {
t.Error("expected child Move action to survive")
Expand Down
Binary file not shown.
Binary file not shown.
Binary file modified tests/testdata/zig_clap_more_than_2/expected_actions.json.gz
Binary file not shown.
Binary file modified tests/testdata/zig_clap_more_than_2/expected_ui.json.gz
Binary file not shown.
Binary file not shown.
Binary file modified tests/testdata/zig_clap_short_only_params/expected_ui.json.gz
Binary file not shown.
Binary file modified tests/testdata/zig_zls_build_build_gen/expected_actions.json.gz
Binary file not shown.
Binary file modified tests/testdata/zig_zls_build_build_gen/expected_ui.json.gz
Binary file not shown.
Binary file not shown.
Binary file modified tests/testdata/zig_zls_build_log_warning/expected_ui.json.gz
Binary file not shown.
Loading