Skip to content

Commit 59b29f4

Browse files
committed
Fix all bugs for the grouping of decl
1 parent c669675 commit 59b29f4

File tree

7 files changed

+134
-68
lines changed

7 files changed

+134
-68
lines changed

go.mod

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module github.com/bombsimon/wsl/v3
22

33
go 1.19
44

5-
require golang.org/x/tools v0.6.0
5+
require (
6+
github.com/dave/dst v0.27.2
7+
golang.org/x/tools v0.6.0
8+
)
69

710
require (
811
golang.org/x/mod v0.8.0 // indirect

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
github.com/dave/dst v0.27.2 h1:4Y5VFTkhGLC1oddtNwuxxe36pnyLxMFXT51FOzH8Ekc=
2+
github.com/dave/dst v0.27.2/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=
3+
github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg=
4+
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
15
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
26
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
37
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=

testdata/src/default_config/var_decl.go

+12
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,16 @@ func fn() {
3737
Addr: ":8081",
3838
ReadTimeout: 2 * time.Second,
3939
}
40+
41+
var a1 = 1 // want "declarations should never be cuddled"
42+
var s1 = http.Server{
43+
Addr: ":8080", // important comment
44+
ReadTimeout: time.Second,
45+
}
46+
47+
var s2 = http.Server{ // want "declarations should never be cuddled"
48+
Addr: ":8080", // important comment
49+
ReadTimeout: time.Second,
50+
}
51+
var a2 = 1 // also comment
4052
}

testdata/src/default_config/var_decl.go.golden

+21-8
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,12 @@ func fn() {
1414
)
1515

1616
var (
17-
c = 1 // want "declarations should never be cuddled"
18-
17+
c = 1 // want "declarations should never be cuddled"
1918
d = 1 // like this
2019
extendedAlign = 33
21-
22-
x = 1
23-
y = 2
24-
25-
afsa = 1
20+
x = 1
21+
y = 2
22+
afsa = 1
2623
)
2724

2825
if true {
@@ -35,7 +32,7 @@ func fn() {
3532
)
3633

3734
var (
38-
s = http.Server{
35+
s = http.Server{ // want "declarations should never be cuddled"
3936
Addr: ":8080", // important comment
4037
ReadTimeout: time.Second,
4138
}
@@ -44,4 +41,20 @@ func fn() {
4441
ReadTimeout: 2 * time.Second,
4542
}
4643
)
44+
45+
var (
46+
a1 = 1 // want "declarations should never be cuddled"
47+
s1 = http.Server{
48+
Addr: ":8080", // important comment
49+
ReadTimeout: time.Second,
50+
}
51+
)
52+
53+
var (
54+
s2 = http.Server{ // want "declarations should never be cuddled"
55+
Addr: ":8080", // important comment
56+
ReadTimeout: time.Second,
57+
}
58+
a2 = 1 // also comment
59+
)
4760
}

testdata/src/wip/wip.go

-24
Original file line numberDiff line numberDiff line change
@@ -1,25 +1 @@
11
package testpkg
2-
3-
func fn() {
4-
var a = 1 // want "declarations should never be cuddled"
5-
var baba = 2 // what about
6-
var xx = 2 // Some comments?
7-
var yy = 2
8-
9-
var c = 1 // want "declarations should never be cuddled"
10-
var (
11-
d = 1 // like this
12-
extendedAlign = 33
13-
)
14-
var (
15-
x = 1
16-
y = 2
17-
)
18-
var afsa = 1
19-
20-
if true {
21-
//
22-
}
23-
var x = 1
24-
var z = 1
25-
}

testdata/src/wip/wip.go.golden

-21
Original file line numberDiff line numberDiff line change
@@ -1,22 +1 @@
11
package testpkg
2-
3-
func fn() {
4-
var (
5-
a = 1 // want "declarations should never be cuddled"
6-
baba = 2 // what about
7-
xx = 2 // Some comments?
8-
yy = 2
9-
)
10-
11-
var (
12-
c = 1 // want "declarations should never be cuddled"
13-
14-
d = 1 // like this
15-
extendedAlign = 33
16-
17-
x = 1
18-
y = 2
19-
20-
afsa = 1
21-
)
22-
}

wsl.go

+93-14
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"bytes"
55
"fmt"
66
"go/ast"
7-
"go/printer"
87
"go/token"
98
"reflect"
109
"sort"
1110
"strings"
11+
12+
"github.com/dave/dst"
13+
"github.com/dave/dst/decorator"
1214
)
1315

1416
// Error reason strings.
@@ -194,20 +196,29 @@ type result struct {
194196
// processor is the type that keeps track of the file and fileset and holds the
195197
// results from parsing the AST.
196198
type processor struct {
197-
config *Configuration
198-
file *ast.File
199-
fileSet *token.FileSet
200-
Result map[token.Pos]result
201-
Warnings []string
199+
config *Configuration
200+
file *ast.File
201+
fileSet *token.FileSet
202+
decorator *decorator.Decorator
203+
Result map[token.Pos]result
204+
Warnings []string
202205
}
203206

204207
// newProcessorWithConfig will create a Processor with the passed configuration.
205208
func newProcessorWithConfig(file *ast.File, fileSet *token.FileSet, cfg *Configuration) *processor {
209+
dec := decorator.NewDecorator(fileSet)
210+
211+
_, err := dec.DecorateFile(file)
212+
if err != nil {
213+
panic(err)
214+
}
215+
206216
return &processor{
207-
config: cfg,
208-
file: file,
209-
fileSet: fileSet,
210-
Result: make(map[token.Pos]result),
217+
config: cfg,
218+
file: file,
219+
fileSet: fileSet,
220+
decorator: dec,
221+
Result: make(map[token.Pos]result),
211222
}
212223
}
213224

@@ -562,6 +573,28 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) {
562573
// and look forward until we no longer have a cuddled decl.
563574
var endNode ast.Node = previousDeclNode
564575

576+
// There's a difference on where `dst` decorates decl stmts based on
577+
// if it's a single value spec or if it's a grouped var block or any
578+
// kind of node with multiple child nodes.
579+
// If we have a single `var a = 1` we need to move the decoration
580+
// from the *dst.DeclStmt to the *dst.ValueSpec which holds the
581+
// assigned value. This will make sure we keep the comment when
582+
// combining all the specs.
583+
moveCommentsIfGrouped := func(node *ast.DeclStmt, specs []dst.Spec) {
584+
if len(specs) != 1 {
585+
return
586+
}
587+
588+
dds, _ := p.decorator.Dst.Nodes[node].(*dst.DeclStmt)
589+
590+
if spec, ok := specs[0].(*dst.ValueSpec); ok {
591+
if spec.Decs.NodeDecs.Start == nil && spec.Decs.NodeDecs.End == nil {
592+
spec.Decs.NodeDecs = dds.Decs.NodeDecs
593+
dds.Decs.NodeDecs = dst.NodeDecs{}
594+
}
595+
}
596+
}
597+
565598
seenDeclStmtIdx = i
566599
for seenDeclStmtIdx < len(statements) {
567600
// If next statement is not a decl there's nothing more to
@@ -586,22 +619,68 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) {
586619
break
587620
}
588621

589-
previousGenDecl.Specs = append(previousGenDecl.Specs, nextGenDecl.Specs...)
590-
previousDeclNode.Decl = previousGenDecl
622+
pd, _ := p.decorator.Dst.Nodes[previousGenDecl].(*dst.GenDecl)
623+
nd, _ := p.decorator.Dst.Nodes[nextGenDecl].(*dst.GenDecl)
624+
625+
// We must set Rparen to true on the first node to indicate that
626+
// it's a multiline block and that the comment should end with
627+
// the assignment, not the closing parenthesis.
628+
pd.Rparen = true
629+
630+
moveCommentsIfGrouped(previousDeclNode, pd.Specs)
631+
moveCommentsIfGrouped(nextStatement, nd.Specs)
632+
633+
pd.Specs = append(pd.Specs, nd.Specs...)
634+
635+
pn, _ := p.decorator.Dst.Nodes[previousDeclNode].(*dst.DeclStmt)
636+
pn.Decl = pd
591637

592638
endNode = nextStatement
593639
seenDeclStmtIdx++
594640
}
595641

642+
// More hacks to ensure new text spans the whole way. If we have a
643+
// comment on our end node that starts after the node ends it's a
644+
// trailing comment so we need to span over it wit our new text.
645+
//
646+
// var a = 1
647+
// var b = 2 // comment
648+
// -------------------^ Need to end here
649+
commentMap := ast.NewCommentMap(p.fileSet, endNode, p.file.Comments)
650+
if cm, ok := commentMap[endNode]; ok {
651+
lastComment := cm[len(cm)-1]
652+
if lastComment.Pos() > endNode.End() {
653+
endNode = lastComment
654+
}
655+
}
656+
657+
decl, ok := p.decorator.Dst.Nodes[previousStatement].(*dst.DeclStmt)
658+
if !ok {
659+
p.addWarning("failed to get node", stmt.Pos(), stmt)
660+
continue
661+
}
662+
663+
dummyFile := &dst.File{
664+
Name: dst.NewIdent("dummy"),
665+
Decls: []dst.Decl{
666+
decl.Decl,
667+
},
668+
}
669+
596670
b := bytes.Buffer{}
597-
_ = printer.Fprint(&b, p.fileSet, previousDeclNode)
671+
decorator.Fprint(&b, dummyFile)
672+
673+
stripLen := len("package dummy\n\n")
674+
newText := b.Bytes()
675+
newText = newText[stripLen:]
676+
newText = newText[:len(newText)-1]
598677

599678
p.addErrorRangeWithFix(
600679
previousDeclNode.Pos(),
601680
previousDeclNode.Pos(),
602681
endNode.End(),
603682
reasonNeverCuddleDeclare,
604-
b.Bytes(),
683+
newText,
605684
)
606685

607686
case *ast.ExprStmt:

0 commit comments

Comments
 (0)