Skip to content

Commit 47a5f7d

Browse files
committed
gopls/internal/golang: fix bad slice append in function extraction
With multiple return statements, a slice append would overwrite the return values of earlier returns. Fix by using slices.Concat. For golang/go#66289 Change-Id: Ib23bcb9ff297aa1ce9511c7ae54e692b14facca7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/627537 Reviewed-by: Hongxiang Jiang <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 5b5d57c commit 47a5f7d

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

gopls/internal/golang/extract.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go/parser"
1313
"go/token"
1414
"go/types"
15+
"slices"
1516
"sort"
1617
"strings"
1718
"text/scanner"
@@ -1214,10 +1215,14 @@ func generateReturnInfo(enclosing *ast.FuncType, pkg *types.Package, path []ast.
12141215
}
12151216
var name string
12161217
name, idx = generateAvailableIdentifier(pos, path, pkg, info, "returnValue", idx)
1218+
z := analysisinternal.ZeroValue(file, pkg, typ)
1219+
if z == nil {
1220+
return nil, nil, fmt.Errorf("can't generate zero value for %T", typ)
1221+
}
12171222
retVars = append(retVars, &returnVariable{
12181223
name: ast.NewIdent(name),
12191224
decl: &ast.Field{Type: expr},
1220-
zeroVal: analysisinternal.ZeroValue(file, pkg, typ),
1225+
zeroVal: z,
12211226
})
12221227
}
12231228
}
@@ -1250,8 +1255,7 @@ func adjustReturnStatements(returnTypes []*ast.Field, seenVars map[types.Object]
12501255
break
12511256
}
12521257
if val == nil {
1253-
return fmt.Errorf(
1254-
"could not find matching AST expression for %T", returnType.Type)
1258+
return fmt.Errorf("could not find matching AST expression for %T", returnType.Type)
12551259
}
12561260
zeroVals = append(zeroVals, val)
12571261
}
@@ -1266,7 +1270,7 @@ func adjustReturnStatements(returnTypes []*ast.Field, seenVars map[types.Object]
12661270
return false
12671271
}
12681272
if n, ok := n.(*ast.ReturnStmt); ok {
1269-
n.Results = append(zeroVals, n.Results...)
1273+
n.Results = slices.Concat(zeroVals, n.Results)
12701274
return false
12711275
}
12721276
return true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
-- a.go --
3+
package a
4+
5+
import (
6+
"fmt"
7+
"encoding/json"
8+
)
9+
10+
func F() error {
11+
a, err := json.Marshal(0) //@codeaction("a", end, "refactor.extract.function", out)
12+
if err != nil {
13+
return fmt.Errorf("1: %w", err)
14+
}
15+
b, err := json.Marshal(0)
16+
if err != nil {
17+
return fmt.Errorf("2: %w", err)
18+
} //@loc(end, "}")
19+
fmt.Println(a, b)
20+
return nil
21+
}
22+
23+
-- @out/a.go --
24+
package a
25+
26+
import (
27+
"fmt"
28+
"encoding/json"
29+
)
30+
31+
func F() error {
32+
//@codeaction("a", end, "refactor.extract.function", out)
33+
a, b, shouldReturn, returnValue := newFunction()
34+
if shouldReturn {
35+
return returnValue
36+
} //@loc(end, "}")
37+
fmt.Println(a, b)
38+
return nil
39+
}
40+
41+
func newFunction() ([]byte, []byte, bool, error) {
42+
a, err := json.Marshal(0)
43+
if err != nil {
44+
return nil, nil, true, fmt.Errorf("1: %w", err)
45+
}
46+
b, err := json.Marshal(0)
47+
if err != nil {
48+
return nil, nil, true, fmt.Errorf("2: %w", err)
49+
}
50+
return a, b, false, nil
51+
}
52+

internal/analysisinternal/analysis.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@ func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
8080
case under.Info()&types.IsNumeric != 0:
8181
return &ast.BasicLit{Kind: token.INT, Value: "0"}
8282
case under.Info()&types.IsBoolean != 0:
83-
return &ast.Ident{Name: "false"}
83+
return ast.NewIdent("false")
8484
case under.Info()&types.IsString != 0:
8585
return &ast.BasicLit{Kind: token.STRING, Value: `""`}
86+
case under == types.Typ[types.Invalid]:
87+
return nil
8688
default:
8789
panic(fmt.Sprintf("unknown basic type %v", under))
8890
}

0 commit comments

Comments
 (0)