Skip to content

Commit fd3eb08

Browse files
xieyuschengopherbot
authored andcommitted
gopls/internal/cache/parsego: new test case for fixed syntax
This CL adds a new test case to verify the fixed syntax in parsego.Parse, which helps us better understand its behavior. Updates: golang/go#64335 Change-Id: I8bf93e43a1bb67853ca02e32232aef48159295d7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/664095 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent c24b06c commit fd3eb08

File tree

2 files changed

+106
-19
lines changed

2 files changed

+106
-19
lines changed

gopls/internal/cache/parsego/parse.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const (
4949
// Parse parses a buffer of Go source, repairing the tree if necessary.
5050
//
5151
// The provided ctx is used only for logging.
52-
func Parse(ctx context.Context, fset *token.FileSet, uri protocol.DocumentURI, src []byte, mode parser.Mode, purgeFuncBodies bool) (res *File, fixes []fixType) {
52+
func Parse(ctx context.Context, fset *token.FileSet, uri protocol.DocumentURI, src []byte, mode parser.Mode, purgeFuncBodies bool) (res *File, fixes []FixType) {
5353
if purgeFuncBodies {
5454
src = astutil.PurgeFuncBodies(src)
5555
}
@@ -147,13 +147,13 @@ func Parse(ctx context.Context, fset *token.FileSet, uri protocol.DocumentURI, s
147147
//
148148
// If fixAST returns true, the resulting AST is considered "fixed", meaning
149149
// positions have been mangled, and type checker errors may not make sense.
150-
func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
150+
func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []FixType) {
151151
var err error
152152
walkASTWithParent(n, func(n, parent ast.Node) bool {
153153
switch n := n.(type) {
154154
case *ast.BadStmt:
155155
if fixDeferOrGoStmt(n, parent, tok, src) {
156-
fixes = append(fixes, fixedDeferOrGo)
156+
fixes = append(fixes, FixedDeferOrGo)
157157
// Recursively fix in our fixed node.
158158
moreFixes := fixAST(parent, tok, src)
159159
fixes = append(fixes, moreFixes...)
@@ -163,7 +163,7 @@ func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
163163
return false
164164
case *ast.BadExpr:
165165
if fixArrayType(n, parent, tok, src) {
166-
fixes = append(fixes, fixedArrayType)
166+
fixes = append(fixes, FixedArrayType)
167167
// Recursively fix in our fixed node.
168168
moreFixes := fixAST(parent, tok, src)
169169
fixes = append(fixes, moreFixes...)
@@ -177,7 +177,7 @@ func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
177177
// for i := foo
178178
//
179179
if fixInitStmt(n, parent, tok, src) {
180-
fixes = append(fixes, fixedInit)
180+
fixes = append(fixes, FixedInit)
181181
}
182182
return false
183183
case *ast.SelectorExpr:
@@ -186,7 +186,7 @@ func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
186186
// foo.var<> // want to complete to "foo.variance"
187187
//
188188
if fixPhantomSelector(n, tok, src) {
189-
fixes = append(fixes, fixedPhantomSelector)
189+
fixes = append(fixes, FixedPhantomSelector)
190190
}
191191
return true
192192

@@ -196,7 +196,7 @@ func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
196196
// Adjust closing curly brace of empty switch/select
197197
// statements so we can complete inside them.
198198
if fixEmptySwitch(n, tok, src) {
199-
fixes = append(fixes, fixedEmptySwitch)
199+
fixes = append(fixes, FixedEmptySwitch)
200200
}
201201
}
202202

@@ -235,24 +235,24 @@ func walkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
235235

236236
// TODO(rfindley): revert this intrumentation once we're certain the crash in
237237
// #59097 is fixed.
238-
type fixType int
238+
type FixType int
239239

240240
const (
241-
noFix fixType = iota
242-
fixedCurlies
243-
fixedDanglingSelector
244-
fixedDeferOrGo
245-
fixedArrayType
246-
fixedInit
247-
fixedPhantomSelector
248-
fixedEmptySwitch
241+
noFix FixType = iota
242+
FixedCurlies
243+
FixedDanglingSelector
244+
FixedDeferOrGo
245+
FixedArrayType
246+
FixedInit
247+
FixedPhantomSelector
248+
FixedEmptySwitch
249249
)
250250

251251
// fixSrc attempts to modify the file's source code to fix certain
252252
// syntax errors that leave the rest of the file unparsed.
253253
//
254254
// fixSrc returns a non-nil result if and only if a fix was applied.
255-
func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte, fix fixType) {
255+
func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte, fix FixType) {
256256
walkASTWithParent(f, func(n, parent ast.Node) bool {
257257
if newSrc != nil {
258258
return false
@@ -262,12 +262,12 @@ func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte, fix fixType
262262
case *ast.BlockStmt:
263263
newSrc = fixMissingCurlies(f, n, parent, tf, src)
264264
if newSrc != nil {
265-
fix = fixedCurlies
265+
fix = FixedCurlies
266266
}
267267
case *ast.SelectorExpr:
268268
newSrc = fixDanglingSelector(n, tf, src)
269269
if newSrc != nil {
270-
fix = fixedDanglingSelector
270+
fix = FixedDanglingSelector
271271
}
272272
}
273273

gopls/internal/cache/parsego/parse_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ package parsego_test
66

77
import (
88
"context"
9+
"fmt"
910
"go/ast"
1011
"go/token"
12+
"slices"
1113
"testing"
1214

1315
"golang.org/x/tools/gopls/internal/cache/parsego"
1416
"golang.org/x/tools/gopls/internal/util/safetoken"
17+
"golang.org/x/tools/internal/analysisinternal"
1518
"golang.org/x/tools/internal/tokeninternal"
1619
)
1720

@@ -44,3 +47,87 @@ func _() {
4447
return true
4548
})
4649
}
50+
51+
func TestFixGoAndDefer_GoStmt(t *testing.T) {
52+
var testCases = []struct {
53+
source string
54+
fixes []parsego.FixType
55+
wantFix string
56+
}{
57+
{source: "g", fixes: nil},
58+
{source: "go", fixes: nil},
59+
{source: "go a.b(", fixes: nil},
60+
{source: "go a.b()", fixes: nil},
61+
{source: "go func {", fixes: nil},
62+
{
63+
source: "go f",
64+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
65+
wantFix: "go f()",
66+
},
67+
{
68+
source: "go func",
69+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
70+
wantFix: "go (func())()",
71+
},
72+
{
73+
source: "go func {}",
74+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
75+
wantFix: "go (func())()",
76+
},
77+
{
78+
source: "go func {}(",
79+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
80+
wantFix: "go (func())()",
81+
},
82+
{
83+
source: "go func {}()",
84+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
85+
wantFix: "go (func())()",
86+
},
87+
{
88+
source: "go a.",
89+
fixes: []parsego.FixType{parsego.FixedDeferOrGo, parsego.FixedDanglingSelector, parsego.FixedDeferOrGo},
90+
wantFix: "go a._()",
91+
},
92+
{
93+
source: "go a.b",
94+
fixes: []parsego.FixType{parsego.FixedDeferOrGo},
95+
wantFix: "go a.b()",
96+
},
97+
}
98+
99+
for _, tc := range testCases {
100+
t.Run(tc.source, func(t *testing.T) {
101+
src := filesrc(tc.source)
102+
pgf, fixes := parsego.Parse(context.Background(), token.NewFileSet(), "file://foo.go", src, parsego.Full, false)
103+
if !slices.Equal(fixes, tc.fixes) {
104+
t.Fatalf("TestFixGoAndDefer_GoStmt(): got %v want %v", fixes, tc.fixes)
105+
}
106+
fset := tokeninternal.FileSetFor(pgf.Tok)
107+
check := func(n ast.Node) bool {
108+
if n != nil {
109+
posn := safetoken.StartPosition(fset, n.Pos())
110+
if !posn.IsValid() {
111+
t.Fatalf("invalid position for %T (%v): %v not in [%d, %d]", n, n, n.Pos(), pgf.Tok.Base(), pgf.Tok.Base()+pgf.Tok.Size())
112+
}
113+
if deferStmt, ok := n.(*ast.GoStmt); ok && tc.fixes != nil {
114+
if got, want := fmt.Sprintf("go %s", analysisinternal.Format(fset, deferStmt.Call)), tc.wantFix; got != want {
115+
t.Fatalf("TestFixGoAndDefer_GoStmt(): got %v want %v", got, want)
116+
}
117+
}
118+
}
119+
return true
120+
}
121+
ast.Inspect(pgf.File, check)
122+
})
123+
}
124+
}
125+
126+
func filesrc(expressions string) []byte {
127+
const srcTmpl = `package foo
128+
129+
func _() {
130+
%s
131+
}`
132+
return fmt.Appendf(nil, srcTmpl, expressions)
133+
}

0 commit comments

Comments
 (0)