all: merge master (ab04c19) into gopls-release-branch.0.18 Also add back the replace directive. For golang/go#71607 Merge List: + 2025-02-13 ab04c1963 gopls/internal/analysis/modernize: improve rangeint transformation + 2025-02-13 ddd4bde5a gopls/internal/golang: avoid PackageSymbols errors with missing packages + 2025-02-13 44b61a1d1 x/tools: eliminate various unparen (et al) helpers + 2025-02-13 d0d86e40a x/tools: run gopls/internal/analysis/gofix/main.go -fix + 2025-02-13 2f1b076c4 x/tools: add //go:fix inline + 2025-02-12 86f13a91f gopls/internal/analysis/gofix: rename local + 2025-02-12 57629448d gopls/internal/analysis/gofix: check package visibility + 2025-02-12 f9aad7054 go/types/typeutil: avoid shifting uintptr by 32 on 32-bit archs Change-Id: Iec742aa4d8dc370d050b8f33a5dd11838cdb7888
diff --git a/go.mod b/go.mod index 8cea866..e6e31d7 100644 --- a/go.mod +++ b/go.mod
@@ -12,3 +12,5 @@ ) require golang.org/x/sys v0.30.0 // indirect + +replace golang.org/x/tools => ../
diff --git a/go/analysis/checker/checker.go b/go/analysis/checker/checker.go index 502ec92..9480873 100644 --- a/go/analysis/checker/checker.go +++ b/go/analysis/checker/checker.go
@@ -594,7 +594,7 @@ func factType(fact analysis.Fact) reflect.Type { t := reflect.TypeOf(fact) - if t.Kind() != reflect.Ptr { + if t.Kind() != reflect.Pointer { log.Fatalf("invalid Fact type: got %T, want pointer", fact) } return t
diff --git a/go/analysis/passes/copylock/copylock.go b/go/analysis/passes/copylock/copylock.go index a9f02ac..8a21567 100644 --- a/go/analysis/passes/copylock/copylock.go +++ b/go/analysis/passes/copylock/copylock.go
@@ -378,7 +378,7 @@ // Construct a sync.Locker interface type. func init() { - nullary := types.NewSignature(nil, nil, nil, false) // func() + nullary := types.NewSignatureType(nil, nil, nil, nil, nil, false) // func() methods := []*types.Func{ types.NewFunc(token.NoPos, nil, "Lock", nullary), types.NewFunc(token.NoPos, nil, "Unlock", nullary),
diff --git a/go/analysis/passes/unusedresult/unusedresult.go b/go/analysis/passes/unusedresult/unusedresult.go index d7cc1e6..e298f64 100644 --- a/go/analysis/passes/unusedresult/unusedresult.go +++ b/go/analysis/passes/unusedresult/unusedresult.go
@@ -130,9 +130,7 @@ } // func() string -var sigNoArgsStringResult = types.NewSignature(nil, nil, - types.NewTuple(types.NewParam(token.NoPos, nil, "", types.Typ[types.String])), - false) +var sigNoArgsStringResult = types.NewSignatureType(nil, nil, nil, nil, types.NewTuple(types.NewParam(token.NoPos, nil, "", types.Typ[types.String])), false) type stringSetFlag map[string]bool
diff --git a/go/analysis/validate.go b/go/analysis/validate.go index 4f2c404..1453939 100644 --- a/go/analysis/validate.go +++ b/go/analysis/validate.go
@@ -63,7 +63,7 @@ return fmt.Errorf("fact type %s registered by two analyzers: %v, %v", t, a, prev) } - if t.Kind() != reflect.Ptr { + if t.Kind() != reflect.Pointer { return fmt.Errorf("%s: fact type %s is not a pointer", a, t) } factTypes[t] = a
diff --git a/go/ast/astutil/rewrite.go b/go/ast/astutil/rewrite.go index 58934f7..5c8dbbb 100644 --- a/go/ast/astutil/rewrite.go +++ b/go/ast/astutil/rewrite.go
@@ -183,7 +183,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { // convert typed nil into untyped nil - if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(n); v.Kind() == reflect.Pointer && v.IsNil() { n = nil }
diff --git a/go/ast/astutil/util.go b/go/ast/astutil/util.go index ca71e3e..c820b20 100644 --- a/go/ast/astutil/util.go +++ b/go/ast/astutil/util.go
@@ -8,4 +8,6 @@ // Unparen returns e with any enclosing parentheses stripped. // Deprecated: use [ast.Unparen]. +// +//go:fix inline func Unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) }
diff --git a/go/callgraph/vta/propagation_test.go b/go/callgraph/vta/propagation_test.go index 492258f..3885ef2 100644 --- a/go/callgraph/vta/propagation_test.go +++ b/go/callgraph/vta/propagation_test.go
@@ -203,7 +203,7 @@ a := newNamedType("A") b := newNamedType("B") c := newNamedType("C") - sig := types.NewSignature(nil, types.NewTuple(), types.NewTuple(), false) + sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(), false) f1 := &ssa.Function{Signature: sig} setName(f1, "F1")
diff --git a/go/internal/gccgoimporter/parser.go b/go/internal/gccgoimporter/parser.go index f315ec4..f70946e 100644 --- a/go/internal/gccgoimporter/parser.go +++ b/go/internal/gccgoimporter/parser.go
@@ -619,7 +619,7 @@ p.skipInlineBody() p.expectEOL() - sig := types.NewSignature(receiver, params, results, isVariadic) + sig := types.NewSignatureType(receiver, nil, nil, params, results, isVariadic) nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) } } @@ -800,7 +800,7 @@ params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) - *t = *types.NewSignature(nil, params, results, isVariadic) + *t = *types.NewSignatureType(nil, nil, nil, params, results, isVariadic) return t }
diff --git a/go/packages/packages.go b/go/packages/packages.go index c3a59b8..342f019 100644 --- a/go/packages/packages.go +++ b/go/packages/packages.go
@@ -141,6 +141,8 @@ LoadAllSyntax = LoadSyntax | NeedDeps // Deprecated: NeedExportsFile is a historical misspelling of NeedExportFile. + // + //go:fix inline NeedExportsFile = NeedExportFile )
diff --git a/go/ssa/builder.go b/go/ssa/builder.go index 4cd7126..1761dcc 100644 --- a/go/ssa/builder.go +++ b/go/ssa/builder.go
@@ -559,7 +559,7 @@ // literal that may reference parts of the LHS. func (b *builder) assign(fn *Function, loc lvalue, e ast.Expr, isZero bool, sb *storebuf) { // Can we initialize it in place? - if e, ok := unparen(e).(*ast.CompositeLit); ok { + if e, ok := ast.Unparen(e).(*ast.CompositeLit); ok { // A CompositeLit never evaluates to a pointer, // so if the type of the location is a pointer, // an &-operation is implied. @@ -614,7 +614,7 @@ // expr lowers a single-result expression e to SSA form, emitting code // to fn and returning the Value defined by the expression. func (b *builder) expr(fn *Function, e ast.Expr) Value { - e = unparen(e) + e = ast.Unparen(e) tv := fn.info.Types[e] @@ -704,7 +704,7 @@ return y } // Call to "intrinsic" built-ins, e.g. new, make, panic. - if id, ok := unparen(e.Fun).(*ast.Ident); ok { + if id, ok := ast.Unparen(e.Fun).(*ast.Ident); ok { if obj, ok := fn.info.Uses[id].(*types.Builtin); ok { if v := b.builtin(fn, obj, e.Args, fn.typ(tv.Type), e.Lparen); v != nil { return v @@ -721,7 +721,7 @@ switch e.Op { case token.AND: // &X --- potentially escaping. addr := b.addr(fn, e.X, true) - if _, ok := unparen(e.X).(*ast.StarExpr); ok { + if _, ok := ast.Unparen(e.X).(*ast.StarExpr); ok { // &*p must panic if p is nil (http://golang.org/s/go12nil). // For simplicity, we'll just (suboptimally) rely // on the side effects of a load. @@ -1002,7 +1002,7 @@ c.pos = e.Lparen // Is this a method call? - if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { + if selector, ok := ast.Unparen(e.Fun).(*ast.SelectorExpr); ok { sel := fn.selection(selector) if sel != nil && sel.kind == types.MethodVal { obj := sel.obj.(*types.Func) @@ -1372,7 +1372,7 @@ // An &-operation may be implied: // map[*struct{}]bool{&struct{}{}: true} wantAddr := false - if _, ok := unparen(e.Key).(*ast.CompositeLit); ok { + if _, ok := ast.Unparen(e.Key).(*ast.CompositeLit); ok { wantAddr = isPointerCore(t.Key()) } @@ -1547,9 +1547,9 @@ var x Value switch ass := s.Assign.(type) { case *ast.ExprStmt: // x.(type) - x = b.expr(fn, unparen(ass.X).(*ast.TypeAssertExpr).X) + x = b.expr(fn, ast.Unparen(ass.X).(*ast.TypeAssertExpr).X) case *ast.AssignStmt: // y := x.(type) - x = b.expr(fn, unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X) + x = b.expr(fn, ast.Unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X) } done := fn.newBasicBlock("typeswitch.done") @@ -1667,7 +1667,7 @@ } case *ast.AssignStmt: // x := <-ch - recv := unparen(comm.Rhs[0]).(*ast.UnaryExpr) + recv := ast.Unparen(comm.Rhs[0]).(*ast.UnaryExpr) st = &SelectState{ Dir: types.RecvOnly, Chan: b.expr(fn, recv.X), @@ -1678,7 +1678,7 @@ } case *ast.ExprStmt: // <-ch - recv := unparen(comm.X).(*ast.UnaryExpr) + recv := ast.Unparen(comm.X).(*ast.UnaryExpr) st = &SelectState{ Dir: types.RecvOnly, Chan: b.expr(fn, recv.X),
diff --git a/go/ssa/emit.go b/go/ssa/emit.go index a3d41ad..bca79ad 100644 --- a/go/ssa/emit.go +++ b/go/ssa/emit.go
@@ -81,7 +81,7 @@ panic("nil") } var obj types.Object - e = unparen(e) + e = ast.Unparen(e) if id, ok := e.(*ast.Ident); ok { if isBlankIdent(id) { return
diff --git a/go/ssa/interp/reflect.go b/go/ssa/interp/reflect.go index 8259e56..22f8cde 100644 --- a/go/ssa/interp/reflect.go +++ b/go/ssa/interp/reflect.go
@@ -231,7 +231,7 @@ case *types.Map: return reflect.Map case *types.Pointer: - return reflect.Ptr + return reflect.Pointer case *types.Slice: return reflect.Slice case *types.Struct: @@ -510,7 +510,7 @@ // that is needed is the "pointerness" of Recv.Type, and for // now, we'll set it to always be false since we're only // concerned with rtype. Encapsulate this better. - sig := types.NewSignature(types.NewParam(token.NoPos, nil, "recv", recvType), nil, nil, false) + sig := types.NewSignatureType(types.NewParam(token.NoPos, nil, "recv", recvType), nil, nil, nil, nil, false) fn := pkg.Prog.NewFunction(name, sig, "fake reflect method") fn.Pkg = pkg return fn
diff --git a/go/ssa/source.go b/go/ssa/source.go index 055a6b1..d0cc1f4 100644 --- a/go/ssa/source.go +++ b/go/ssa/source.go
@@ -153,7 +153,7 @@ // the ssa.Value.) func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) { if f.debugInfo() { // (opt) - e = unparen(e) + e = ast.Unparen(e) for _, b := range f.Blocks { for _, instr := range b.Instrs { if ref, ok := instr.(*DebugRef); ok {
diff --git a/go/ssa/util.go b/go/ssa/util.go index 4a056cb..2a9c9b9 100644 --- a/go/ssa/util.go +++ b/go/ssa/util.go
@@ -35,8 +35,6 @@ //// AST utilities -func unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) } - // isBlankIdent returns true iff e is an Ident with name "_". // They have no associated types.Object, and thus no type. func isBlankIdent(e ast.Expr) bool { @@ -195,7 +193,7 @@ lenParams := types.NewTuple(anonVar(T)) return &Builtin{ name: "len", - sig: types.NewSignature(nil, lenParams, lenResults, false), + sig: types.NewSignatureType(nil, nil, nil, lenParams, lenResults, false), } }
diff --git a/go/ssa/wrappers.go b/go/ssa/wrappers.go index d09b4f2..aeb160e 100644 --- a/go/ssa/wrappers.go +++ b/go/ssa/wrappers.go
@@ -106,9 +106,7 @@ var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", - sig: types.NewSignature(nil, - types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), - types.NewTuple(anonVar(fn.method.recv)), false), + sig: types.NewSignatureType(nil, nil, nil, types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(fn.method.recv)), false), } c.Call.Args = []Value{ v, @@ -262,7 +260,7 @@ } func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { - return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic()) + return types.NewSignatureType(recv, nil, nil, s.Params(), s.Results(), s.Variadic()) } // A local version of *types.Selection.
diff --git a/go/types/objectpath/objectpath_test.go b/go/types/objectpath/objectpath_test.go index 0805c9d..642d6da 100644 --- a/go/types/objectpath/objectpath_test.go +++ b/go/types/objectpath/objectpath_test.go
@@ -308,7 +308,7 @@ if err != nil { t.Fatal(err) } - conf := types.Config{Importer: importer.For("source", nil)} + conf := types.Config{Importer: importer.ForCompiler(token.NewFileSet(), "source", nil)} info := &types.Info{ Defs: make(map[*ast.Ident]types.Object), }
diff --git a/go/types/typeutil/map.go b/go/types/typeutil/map.go index 4326114..b6d542c 100644 --- a/go/types/typeutil/map.go +++ b/go/types/typeutil/map.go
@@ -389,8 +389,13 @@ // path, and whether or not it is a package-level typename. It // is rare for a package to define multiple local types with // the same name.) - hash := uintptr(unsafe.Pointer(tname)) - return uint32(hash ^ (hash >> 32)) + ptr := uintptr(unsafe.Pointer(tname)) + if unsafe.Sizeof(ptr) == 8 { + hash := uint64(ptr) + return uint32(hash ^ (hash >> 32)) + } else { + return uint32(ptr) + } } // shallowHash computes a hash of t without looking at any of its
diff --git a/gopls/internal/analysis/gofix/gofix.go b/gopls/internal/analysis/gofix/gofix.go index 1019243..8ec31bd 100644 --- a/gopls/internal/analysis/gofix/gofix.go +++ b/gopls/internal/analysis/gofix/gofix.go
@@ -220,15 +220,15 @@ case *ast.Ident: // If the identifier is a use of an inlinable constant, suggest inlining it. if con, ok := pass.TypesInfo.Uses[n].(*types.Const); ok { - fcon, ok := inlinableConsts[con] + incon, ok := inlinableConsts[con] if !ok { var fact goFixInlineConstFact if pass.ImportObjectFact(con, &fact) { - fcon = &fact - inlinableConsts[con] = fcon + incon = &fact + inlinableConsts[con] = incon } } - if fcon == nil { + if incon == nil { continue // nope } @@ -248,27 +248,30 @@ // If the RHS is not in the current package, AddImport will handle // shadowing, so we only need to worry about when both expressions // are in the current package. - if pass.Pkg.Path() == fcon.RHSPkgPath { + if pass.Pkg.Path() == incon.RHSPkgPath { // fcon.rhsObj is the object referred to by B in the definition of A. scope := pass.TypesInfo.Scopes[curFile].Innermost(n.Pos()) // n's scope - _, obj := scope.LookupParent(fcon.RHSName, n.Pos()) // what "B" means in n's scope + _, obj := scope.LookupParent(incon.RHSName, n.Pos()) // what "B" means in n's scope if obj == nil { // Should be impossible: if code at n can refer to the LHS, // it can refer to the RHS. - panic(fmt.Sprintf("no object for inlinable const %s RHS %s", n.Name, fcon.RHSName)) + panic(fmt.Sprintf("no object for inlinable const %s RHS %s", n.Name, incon.RHSName)) } - if obj != fcon.rhsObj { + if obj != incon.rhsObj { // "B" means something different here than at the inlinable const's scope. continue } + } else if !analysisinternal.CanImport(pass.Pkg.Path(), incon.RHSPkgPath) { + // If this package can't see the RHS's package, we can't inline. + continue } var ( importPrefix string edits []analysis.TextEdit ) - if fcon.RHSPkgPath != pass.Pkg.Path() { + if incon.RHSPkgPath != pass.Pkg.Path() { _, importPrefix, edits = analysisinternal.AddImport( - pass.TypesInfo, curFile, fcon.RHSPkgName, fcon.RHSPkgPath, fcon.RHSName, n.Pos()) + pass.TypesInfo, curFile, incon.RHSPkgName, incon.RHSPkgPath, incon.RHSName, n.Pos()) } var ( pos = n.Pos() @@ -284,7 +287,7 @@ edits = append(edits, analysis.TextEdit{ Pos: pos, End: end, - NewText: []byte(importPrefix + fcon.RHSName), + NewText: []byte(importPrefix + incon.RHSName), }) pass.Report(analysis.Diagnostic{ Pos: pos,
diff --git a/gopls/internal/analysis/gofix/testdata/src/a/a.go b/gopls/internal/analysis/gofix/testdata/src/a/a.go index ae48674..4f41b9a 100644 --- a/gopls/internal/analysis/gofix/testdata/src/a/a.go +++ b/gopls/internal/analysis/gofix/testdata/src/a/a.go
@@ -1,5 +1,7 @@ package a +import "a/internal" + // Functions. func f() { @@ -75,6 +77,9 @@ in8 = x ) +//go:fix inline +const D = internal.D // want D: `goFixInline const "a/internal".D` + func shadow() { var x int // shadows x at package scope
diff --git a/gopls/internal/analysis/gofix/testdata/src/a/a.go.golden b/gopls/internal/analysis/gofix/testdata/src/a/a.go.golden index 7d75a59..9e9cc25 100644 --- a/gopls/internal/analysis/gofix/testdata/src/a/a.go.golden +++ b/gopls/internal/analysis/gofix/testdata/src/a/a.go.golden
@@ -1,5 +1,7 @@ package a +import "a/internal" + // Functions. func f() { @@ -75,6 +77,9 @@ in8 = x ) +//go:fix inline +const D = internal.D // want D: `goFixInline const "a/internal".D` + func shadow() { var x int // shadows x at package scope
diff --git a/gopls/internal/analysis/gofix/testdata/src/a/internal/d.go b/gopls/internal/analysis/gofix/testdata/src/a/internal/d.go new file mode 100644 index 0000000..3211d7a --- /dev/null +++ b/gopls/internal/analysis/gofix/testdata/src/a/internal/d.go
@@ -0,0 +1,5 @@ +// According to the go toolchain's rule about internal packages, +// this package is visible to package a, but not package b. +package internal + +const D = 1
diff --git a/gopls/internal/analysis/gofix/testdata/src/b/b.go b/gopls/internal/analysis/gofix/testdata/src/b/b.go index 4bf9f0d..7487673 100644 --- a/gopls/internal/analysis/gofix/testdata/src/b/b.go +++ b/gopls/internal/analysis/gofix/testdata/src/b/b.go
@@ -28,3 +28,5 @@ _ = a _ = x } + +const d = a.D // nope: a.D refers to a constant in a package that is not visible here.
diff --git a/gopls/internal/analysis/gofix/testdata/src/b/b.go.golden b/gopls/internal/analysis/gofix/testdata/src/b/b.go.golden index b26a05c..b3608d6 100644 --- a/gopls/internal/analysis/gofix/testdata/src/b/b.go.golden +++ b/gopls/internal/analysis/gofix/testdata/src/b/b.go.golden
@@ -32,3 +32,5 @@ _ = a _ = x } + +const d = a.D // nope: a.D refers to a constant in a package that is not visible here.
diff --git a/gopls/internal/analysis/modernize/rangeint.go b/gopls/internal/analysis/modernize/rangeint.go index c36203c..2d25d6a 100644 --- a/gopls/internal/analysis/modernize/rangeint.go +++ b/gopls/internal/analysis/modernize/rangeint.go
@@ -8,10 +8,12 @@ "fmt" "go/ast" "go/token" + "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/astutil/cursor" "golang.org/x/tools/internal/astutil/edge" @@ -98,6 +100,14 @@ }) } + // If limit is len(slice), + // simplify "range len(slice)" to "range slice". + if call, ok := limit.(*ast.CallExpr); ok && + typeutil.Callee(info, call) == builtinLen && + is[*types.Slice](info.TypeOf(call.Args[0]).Underlying()) { + limit = call.Args[0] + } + pass.Report(analysis.Diagnostic{ Pos: init.Pos(), End: inc.End(),
diff --git a/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go b/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go index e17dcca..a60bd5e 100644 --- a/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go +++ b/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go
@@ -1,6 +1,6 @@ package rangeint -func _(i int, s struct{ i int }) { +func _(i int, s struct{ i int }, slice []int) { for i := 0; i < 10; i++ { // want "for loop can be modernized using range over int" println(i) } @@ -9,6 +9,9 @@ for i := 0; i < 10; i++ { // want "for loop can be modernized using range over int" // i unused within loop } + for i := 0; i < len(slice); i++ { // want "for loop can be modernized using range over int" + println(slice[i]) + } // nope for i := 0; i < 10; { // nope: missing increment
diff --git a/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go.golden b/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go.golden index 5a76229..348f775 100644 --- a/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go.golden +++ b/gopls/internal/analysis/modernize/testdata/src/rangeint/rangeint.go.golden
@@ -1,6 +1,6 @@ package rangeint -func _(i int, s struct{ i int }) { +func _(i int, s struct{ i int }, slice []int) { for i := range 10 { // want "for loop can be modernized using range over int" println(i) } @@ -9,6 +9,9 @@ for range 10 { // want "for loop can be modernized using range over int" // i unused within loop } + for i := range slice { // want "for loop can be modernized using range over int" + println(slice[i]) + } // nope for i := 0; i < 10; { // nope: missing increment
diff --git a/gopls/internal/golang/extract.go b/gopls/internal/golang/extract.go index 2ce8979..8c8758d 100644 --- a/gopls/internal/golang/extract.go +++ b/gopls/internal/golang/extract.go
@@ -1229,7 +1229,7 @@ // return value acts as an indicator for where it was defined. var sel func(n *ast.SelectorExpr) (types.Object, bool) sel = func(n *ast.SelectorExpr) (types.Object, bool) { - switch x := astutil.Unparen(n.X).(type) { + switch x := ast.Unparen(n.X).(type) { case *ast.SelectorExpr: return sel(x) case *ast.Ident:
diff --git a/gopls/internal/golang/freesymbols.go b/gopls/internal/golang/freesymbols.go index 2c9e251..3360253 100644 --- a/gopls/internal/golang/freesymbols.go +++ b/gopls/internal/golang/freesymbols.go
@@ -342,7 +342,7 @@ for { suffix = append(suffix, info.Uses[sel.Sel]) - switch x := astutil.Unparen(sel.X).(type) { + switch x := ast.Unparen(sel.X).(type) { case *ast.Ident: return id(x, suffix) default:
diff --git a/gopls/internal/golang/symbols.go b/gopls/internal/golang/symbols.go index 14f2703..db31baa 100644 --- a/gopls/internal/golang/symbols.go +++ b/gopls/internal/golang/symbols.go
@@ -86,17 +86,22 @@ ctx, done := event.Start(ctx, "source.PackageSymbols") defer done() - mp, err := NarrowestMetadataForFile(ctx, snapshot, uri) - if err != nil { - return command.PackageSymbolsResult{}, err + pkgFiles := []protocol.DocumentURI{uri} + + // golang/vscode-go#3681: do our best if the file is not in a package. + // TODO(rfindley): revisit this in the future once there is more graceful + // handling in VS Code. + if mp, err := NarrowestMetadataForFile(ctx, snapshot, uri); err == nil { + pkgFiles = mp.CompiledGoFiles } - pkgfiles := mp.CompiledGoFiles - // Maps receiver name to the methods that use it - receiverToMethods := make(map[string][]command.PackageSymbol) - // Maps type symbol name to its index in symbols - typeSymbolToIdx := make(map[string]int) - var symbols []command.PackageSymbol - for fidx, f := range pkgfiles { + + var ( + pkgName string + symbols []command.PackageSymbol + receiverToMethods = make(map[string][]command.PackageSymbol) // receiver name -> methods + typeSymbolToIdx = make(map[string]int) // type name -> index in symbols + ) + for fidx, f := range pkgFiles { fh, err := snapshot.ReadFile(ctx, f) if err != nil { return command.PackageSymbolsResult{}, err @@ -105,6 +110,9 @@ if err != nil { return command.PackageSymbolsResult{}, err } + if pkgName == "" && pgf.File != nil && pgf.File.Name != nil { + pkgName = pgf.File.Name.Name + } for _, decl := range pgf.File.Decls { switch decl := decl.(type) { case *ast.FuncDecl: @@ -154,8 +162,8 @@ } } return command.PackageSymbolsResult{ - PackageName: string(mp.Name), - Files: pkgfiles, + PackageName: pkgName, + Files: pkgFiles, Symbols: symbols, }, nil
diff --git a/gopls/internal/server/command.go b/gopls/internal/server/command.go index 2b5c282..007b8d5 100644 --- a/gopls/internal/server/command.go +++ b/gopls/internal/server/command.go
@@ -1741,6 +1741,10 @@ err := c.run(ctx, commandConfig{ forURI: args.URI, }, func(ctx context.Context, deps commandDeps) error { + if deps.snapshot.FileKind(deps.fh) != file.Go { + // golang/vscode-go#3681: fail silently, to avoid spurious error popups. + return nil + } res, err := golang.PackageSymbols(ctx, deps.snapshot, args.URI) if err != nil { return err
diff --git a/gopls/internal/test/integration/misc/package_symbols_test.go b/gopls/internal/test/integration/misc/package_symbols_test.go index 860264f..1e06a65 100644 --- a/gopls/internal/test/integration/misc/package_symbols_test.go +++ b/gopls/internal/test/integration/misc/package_symbols_test.go
@@ -16,6 +16,11 @@ func TestPackageSymbols(t *testing.T) { const files = ` +-- go.mod -- +module example.com + +go 1.20 + -- a.go -- package a @@ -33,68 +38,74 @@ func (s *S) M3() {} func F() {} +-- unloaded.go -- +//go:build unloaded + +package a + +var Unloaded int ` integration.Run(t, files, func(t *testing.T, env *integration.Env) { - a_uri := env.Sandbox.Workdir.URI("a.go") - b_uri := env.Sandbox.Workdir.URI("b.go") + aURI := env.Sandbox.Workdir.URI("a.go") + bURI := env.Sandbox.Workdir.URI("b.go") args, err := command.MarshalArgs(command.PackageSymbolsArgs{ - URI: a_uri, + URI: aURI, }) if err != nil { - t.Fatalf("failed to MarshalArgs: %v", err) + t.Fatal(err) } var res command.PackageSymbolsResult env.ExecuteCommand(&protocol.ExecuteCommandParams{ - Command: "gopls.package_symbols", + Command: command.PackageSymbols.String(), Arguments: args, }, &res) want := command.PackageSymbolsResult{ PackageName: "a", - Files: []protocol.DocumentURI{a_uri, b_uri}, + Files: []protocol.DocumentURI{aURI, bURI}, Symbols: []command.PackageSymbol{ - { - Name: "A", - Kind: protocol.Variable, - File: 0, - }, - { - Name: "F", - Kind: protocol.Function, - File: 1, - }, - { - Name: "S", - Kind: protocol.Struct, - File: 0, - Children: []command.PackageSymbol{ - { - Name: "M1", - Kind: protocol.Method, - File: 0, - }, - { - Name: "M2", - Kind: protocol.Method, - File: 1, - }, - { - Name: "M3", - Kind: protocol.Method, - File: 1, - }, - }, - }, - { - Name: "b", - Kind: protocol.Variable, - File: 1, - }, + {Name: "A", Kind: protocol.Variable, File: 0}, + {Name: "F", Kind: protocol.Function, File: 1}, + {Name: "S", Kind: protocol.Struct, File: 0, Children: []command.PackageSymbol{ + {Name: "M1", Kind: protocol.Method, File: 0}, + {Name: "M2", Kind: protocol.Method, File: 1}, + {Name: "M3", Kind: protocol.Method, File: 1}, + }}, + {Name: "b", Kind: protocol.Variable, File: 1}, }, } - if diff := cmp.Diff(want, res, cmpopts.IgnoreFields(command.PackageSymbol{}, "Range", "SelectionRange", "Detail")); diff != "" { - t.Errorf("gopls.package_symbols returned unexpected diff (-want +got):\n%s", diff) + ignore := cmpopts.IgnoreFields(command.PackageSymbol{}, "Range", "SelectionRange", "Detail") + if diff := cmp.Diff(want, res, ignore); diff != "" { + t.Errorf("package_symbols returned unexpected diff (-want +got):\n%s", diff) + } + + for file, want := range map[string]command.PackageSymbolsResult{ + "go.mod": {}, + "unloaded.go": { + PackageName: "a", + Files: []protocol.DocumentURI{env.Sandbox.Workdir.URI("unloaded.go")}, + Symbols: []command.PackageSymbol{ + {Name: "Unloaded", Kind: protocol.Variable, File: 0}, + }, + }, + } { + uri := env.Sandbox.Workdir.URI(file) + args, err := command.MarshalArgs(command.PackageSymbolsArgs{ + URI: uri, + }) + if err != nil { + t.Fatal(err) + } + var res command.PackageSymbolsResult + env.ExecuteCommand(&protocol.ExecuteCommandParams{ + Command: command.PackageSymbols.String(), + Arguments: args, + }, &res) + + if diff := cmp.Diff(want, res, ignore); diff != "" { + t.Errorf("package_symbols returned unexpected diff (-want +got):\n%s", diff) + } } }) }
diff --git a/internal/astutil/clone.go b/internal/astutil/clone.go index d5ee82c..2c9b6bb 100644 --- a/internal/astutil/clone.go +++ b/internal/astutil/clone.go
@@ -25,7 +25,7 @@ } clone = func(x reflect.Value) reflect.Value { switch x.Kind() { - case reflect.Ptr: + case reflect.Pointer: if x.IsNil() { return x }
diff --git a/internal/gcimporter/ureader_yes.go b/internal/gcimporter/ureader_yes.go index 522287d..37b4a39 100644 --- a/internal/gcimporter/ureader_yes.go +++ b/internal/gcimporter/ureader_yes.go
@@ -574,7 +574,7 @@ recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named) typesinternal.SetVarKind(recv, typesinternal.RecvVar) - methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic())) + methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignatureType(recv, nil, nil, sig.Params(), sig.Results(), sig.Variadic())) } embeds := make([]types.Type, iface.NumEmbeddeds())
diff --git a/internal/refactor/inline/inline.go b/internal/refactor/inline/inline.go index 96fbb8f..5430824 100644 --- a/internal/refactor/inline/inline.go +++ b/internal/refactor/inline/inline.go
@@ -2981,7 +2981,7 @@ var visit func(reflect.Value) visit = func(v reflect.Value) { switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: if v.Interface() == from { found = true
diff --git a/internal/refactor/inline/inline_test.go b/internal/refactor/inline/inline_test.go index 03fb5cc..3be37d5 100644 --- a/internal/refactor/inline/inline_test.go +++ b/internal/refactor/inline/inline_test.go
@@ -1977,7 +1977,7 @@ var visit func(reflect.Value) visit = func(v reflect.Value) { switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: ptr := v.UnsafePointer() writeUint64(uint64(uintptr(ptr))) if !v.IsNil() {
diff --git a/internal/tool/tool.go b/internal/tool/tool.go index 46f5b87..fe2b1c2 100644 --- a/internal/tool/tool.go +++ b/internal/tool/tool.go
@@ -250,7 +250,7 @@ child := value.Type().Field(i) v := value.Field(i) // make sure we have a pointer - if v.Kind() != reflect.Ptr { + if v.Kind() != reflect.Pointer { v = v.Addr() } // check if that field is a flag or contains flags @@ -289,7 +289,7 @@ func resolve(v reflect.Value) reflect.Value { for { switch v.Kind() { - case reflect.Interface, reflect.Ptr: + case reflect.Interface, reflect.Pointer: v = v.Elem() default: return v
diff --git a/refactor/eg/match.go b/refactor/eg/match.go index 31f8af2..d85a473 100644 --- a/refactor/eg/match.go +++ b/refactor/eg/match.go
@@ -13,8 +13,6 @@ "log" "os" "reflect" - - "golang.org/x/tools/go/ast/astutil" ) // matchExpr reports whether pattern x matches y. @@ -34,8 +32,8 @@ if x == nil || y == nil { return false } - x = unparen(x) - y = unparen(y) + x = ast.Unparen(x) + y = ast.Unparen(y) // Is x a wildcard? (a reference to a 'before' parameter) if xobj, ok := tr.wildcardObj(x); ok { @@ -229,8 +227,6 @@ // -- utilities -------------------------------------------------------- -func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } - // isRef returns the object referred to by this (possibly qualified) // identifier, or nil if the node is not a referring identifier. func isRef(n ast.Node, info *types.Info) types.Object {
diff --git a/refactor/eg/rewrite.go b/refactor/eg/rewrite.go index 3f71c53..6fb1e44 100644 --- a/refactor/eg/rewrite.go +++ b/refactor/eg/rewrite.go
@@ -338,7 +338,7 @@ } return v - case reflect.Ptr: + case reflect.Pointer: v := reflect.New(p.Type()).Elem() if elem := p.Elem(); elem.IsValid() { v.Set(tr.subst(env, elem, pos).Addr())
diff --git a/refactor/rename/spec.go b/refactor/rename/spec.go index 1d8c32c..99068c1 100644 --- a/refactor/rename/spec.go +++ b/refactor/rename/spec.go
@@ -155,7 +155,7 @@ } if e, ok := e.(*ast.SelectorExpr); ok { - x := unparen(e.X) + x := ast.Unparen(e.X) // Strip off star constructor, if any. if star, ok := x.(*ast.StarExpr); ok { @@ -172,7 +172,7 @@ if x, ok := x.(*ast.SelectorExpr); ok { // field/method of type e.g. ("encoding/json".Decoder).Decode - y := unparen(x.X) + y := ast.Unparen(x.X) if pkg := parseImportPath(y); pkg != "" { spec.pkg = pkg // e.g. "encoding/json" spec.pkgMember = x.Sel.Name // e.g. "Decoder"
diff --git a/refactor/rename/util.go b/refactor/rename/util.go index 7c1a634..cb7cea3 100644 --- a/refactor/rename/util.go +++ b/refactor/rename/util.go
@@ -5,7 +5,6 @@ package rename import ( - "go/ast" "go/token" "go/types" "os" @@ -14,8 +13,6 @@ "runtime" "strings" "unicode" - - "golang.org/x/tools/go/ast/astutil" ) func objectKind(obj types.Object) string { @@ -93,8 +90,6 @@ return false } -func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } - func is[T any](x any) bool { _, ok := x.(T) return ok
diff --git a/refactor/satisfy/find.go b/refactor/satisfy/find.go index 3d693aa..a897c3c 100644 --- a/refactor/satisfy/find.go +++ b/refactor/satisfy/find.go
@@ -126,13 +126,13 @@ case *ast.CallExpr: // x, err := f(args) - sig := coreType(f.expr(e.Fun)).(*types.Signature) + sig := typeparams.CoreType(f.expr(e.Fun)).(*types.Signature) f.call(sig, e.Args) case *ast.IndexExpr: // y, ok := x[i] x := f.expr(e.X) - f.assign(f.expr(e.Index), coreType(x).(*types.Map).Key()) + f.assign(f.expr(e.Index), typeparams.CoreType(x).(*types.Map).Key()) case *ast.TypeAssertExpr: // y, ok := x.(T) @@ -213,7 +213,7 @@ f.expr(args[1]) } else { // append(x, y, z) - tElem := coreType(s).(*types.Slice).Elem() + tElem := typeparams.CoreType(s).(*types.Slice).Elem() for _, arg := range args[1:] { f.assign(tElem, f.expr(arg)) } @@ -222,7 +222,7 @@ case "delete": m := f.expr(args[0]) k := f.expr(args[1]) - f.assign(coreType(m).(*types.Map).Key(), k) + f.assign(typeparams.CoreType(m).(*types.Map).Key(), k) default: // ordinary call @@ -273,7 +273,7 @@ if types.Identical(lhs, rhs) { return } - if !isInterface(lhs) { + if !types.IsInterface(lhs) { return } @@ -354,7 +354,7 @@ f.sig = saved case *ast.CompositeLit: - switch T := coreType(typeparams.Deref(tv.Type)).(type) { + switch T := typeparams.CoreType(typeparams.Deref(tv.Type)).(type) { case *types.Struct: for i, elem := range e.Elts { if kv, ok := elem.(*ast.KeyValueExpr); ok { @@ -405,7 +405,7 @@ // x[i] or m[k] -- index or lookup operation x := f.expr(e.X) i := f.expr(e.Index) - if ux, ok := coreType(x).(*types.Map); ok { + if ux, ok := typeparams.CoreType(x).(*types.Map); ok { f.assign(ux.Key(), i) } } @@ -440,7 +440,7 @@ // unsafe call. Treat calls to functions in unsafe like ordinary calls, // except that their signature cannot be determined by their func obj. // Without this special handling, f.expr(e.Fun) would fail below. - if s, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { + if s, ok := ast.Unparen(e.Fun).(*ast.SelectorExpr); ok { if obj, ok := f.info.Uses[s.Sel].(*types.Builtin); ok && obj.Pkg().Path() == "unsafe" { sig := f.info.Types[e.Fun].Type.(*types.Signature) f.call(sig, e.Args) @@ -449,7 +449,7 @@ } // builtin call - if id, ok := unparen(e.Fun).(*ast.Ident); ok { + if id, ok := ast.Unparen(e.Fun).(*ast.Ident); ok { if obj, ok := f.info.Uses[id].(*types.Builtin); ok { sig := f.info.Types[id].Type.(*types.Signature) f.builtin(obj, sig, e.Args) @@ -458,7 +458,7 @@ } // ordinary call - f.call(coreType(f.expr(e.Fun)).(*types.Signature), e.Args) + f.call(typeparams.CoreType(f.expr(e.Fun)).(*types.Signature), e.Args) } case *ast.StarExpr: @@ -518,7 +518,7 @@ case *ast.SendStmt: ch := f.expr(s.Chan) val := f.expr(s.Value) - f.assign(coreType(ch).(*types.Chan).Elem(), val) + f.assign(typeparams.CoreType(ch).(*types.Chan).Elem(), val) case *ast.IncDecStmt: f.expr(s.X) @@ -622,9 +622,9 @@ var I types.Type switch ass := s.Assign.(type) { case *ast.ExprStmt: // x.(type) - I = f.expr(unparen(ass.X).(*ast.TypeAssertExpr).X) + I = f.expr(ast.Unparen(ass.X).(*ast.TypeAssertExpr).X) case *ast.AssignStmt: // y := x.(type) - I = f.expr(unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X) + I = f.expr(ast.Unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X) } for _, cc := range s.Body.List { cc := cc.(*ast.CaseClause) @@ -668,7 +668,7 @@ var xelem types.Type // Keys of array, *array, slice, string aren't interesting // since the RHS key type is just an int. - switch ux := coreType(x).(type) { + switch ux := typeparams.CoreType(x).(type) { case *types.Chan: xelem = ux.Elem() case *types.Map: @@ -683,13 +683,13 @@ var xelem types.Type // Values of type strings aren't interesting because // the RHS value type is just a rune. - switch ux := coreType(x).(type) { + switch ux := typeparams.CoreType(x).(type) { case *types.Array: xelem = ux.Elem() case *types.Map: xelem = ux.Elem() case *types.Pointer: // *array - xelem = coreType(typeparams.Deref(ux)).(*types.Array).Elem() + xelem = typeparams.CoreType(typeparams.Deref(ux)).(*types.Array).Elem() case *types.Slice: xelem = ux.Elem() } @@ -707,12 +707,6 @@ // -- Plundered from golang.org/x/tools/go/ssa ----------------- -func unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) } - -func isInterface(T types.Type) bool { return types.IsInterface(T) } - -func coreType(T types.Type) types.Type { return typeparams.CoreType(T) } - func instance(info *types.Info, expr ast.Expr) bool { var id *ast.Ident switch x := expr.(type) {