Skip to content

Commit 9075930

Browse files
committed
Merge branch 'master' into gopls-release-branch.0.21
Since nearly all recent work has been fixes, it's easier to merge from master than to cherrypick. For golang/go#76367 Change-Id: I6ca9ac63aaae81ee6dc3e3c6b3704ff156d9dcd7
2 parents 486c611 + ebdeef3 commit 9075930

File tree

144 files changed

+3614
-1287
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+3614
-1287
lines changed

go/analysis/internal/checker/checker.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) {
205205
}
206206
}
207207
}
208-
if err := driverutil.ApplyFixes(fixActions, analysisflags.Diff, dbg('v')); err != nil {
208+
write := func(filename string, content []byte) error {
209+
return os.WriteFile(filename, content, 0644)
210+
}
211+
if err := driverutil.ApplyFixes(fixActions, write, analysisflags.Diff, dbg('v')); err != nil {
209212
// Fail when applying fixes failed.
210213
log.Print(err)
211214
exitAtLeast(1)

go/analysis/internal/checker/testdata/json.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Test basic JSON output.
2-
#
3-
# File slashes assume non-Windows.
42

3+
# File slashes assume non-Windows.
54
skip GOOS=windows
5+
66
checker -rename -json example.com/p
77
exit 0
88

@@ -21,6 +21,7 @@ func f(bar int) {}
2121
"rename": [
2222
{
2323
"posn": "/TMP/p/p.go:3:8",
24+
"end": "/TMP/p/p.go:3:11",
2425
"message": "renaming \"bar\" to \"baz\"",
2526
"suggested_fixes": [
2627
{

go/analysis/passes/ctrlflow/ctrlflow.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,13 @@ func (c *CFGs) buildDecl(fn *types.Func, di *declInfo) {
179179
}
180180
di.started = true
181181

182-
noreturn := isIntrinsicNoReturn(fn)
183-
184-
if di.decl.Body != nil {
185-
di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
186-
if cfginternal.IsNoReturn(di.cfg) {
187-
noreturn = true
182+
noreturn, known := knownIntrinsic(fn)
183+
if !known {
184+
if di.decl.Body != nil {
185+
di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
186+
if cfginternal.IsNoReturn(di.cfg) {
187+
noreturn = true
188+
}
188189
}
189190
}
190191
if noreturn {
@@ -233,11 +234,36 @@ func (c *CFGs) callMayReturn(call *ast.CallExpr) (r bool) {
233234

234235
var panicBuiltin = types.Universe.Lookup("panic").(*types.Builtin)
235236

236-
// isIntrinsicNoReturn reports whether a function intrinsically never
237-
// returns because it stops execution of the calling thread.
237+
// knownIntrinsic reports whether a function intrinsically never
238+
// returns because it stops execution of the calling thread, or does
239+
// in fact return, contrary to its apparent body, because it is
240+
// handled specially by the compiler.
241+
//
238242
// It is the base case in the recursion.
239-
func isIntrinsicNoReturn(fn *types.Func) bool {
243+
func knownIntrinsic(fn *types.Func) (noreturn, known bool) {
240244
// Add functions here as the need arises, but don't allocate memory.
241-
return typesinternal.IsFunctionNamed(fn, "syscall", "Exit", "ExitProcess", "ExitThread") ||
242-
typesinternal.IsFunctionNamed(fn, "runtime", "Goexit")
245+
246+
// Functions known intrinsically never to return.
247+
if typesinternal.IsFunctionNamed(fn, "syscall", "Exit", "ExitProcess", "ExitThread") ||
248+
typesinternal.IsFunctionNamed(fn, "runtime", "Goexit") {
249+
return true, true
250+
}
251+
252+
// Compiler intrinsics known to return, contrary to
253+
// what analysis of the function body would conclude.
254+
//
255+
// Not all such intrinsics must be listed here: ctrlflow
256+
// considers any function called for its value--such as
257+
// crypto/internal/constanttime.bool2Uint8--to potentially
258+
// return; only functions called as a statement, for effects,
259+
// are no-return candidates.
260+
//
261+
// Unfortunately this does sometimes mean peering into internals.
262+
// Where possible, use the nearest enclosing public API function.
263+
if typesinternal.IsFunctionNamed(fn, "internal/abi", "EscapeNonString") ||
264+
typesinternal.IsFunctionNamed(fn, "hash/maphash", "Comparable") {
265+
return false, true
266+
}
267+
268+
return // unknown
243269
}

go/analysis/passes/ctrlflow/testdata/src/a/a.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package a
77
// This file tests facts produced by ctrlflow.
88

99
import (
10+
"hash/maphash"
1011
"log"
1112
"os"
1213
"runtime"
@@ -192,3 +193,11 @@ func osexit() { // want osexit:"noReturn"
192193
os.Exit(0)
193194
print(2)
194195
}
196+
197+
func intrinsic() { // (no fact)
198+
199+
// Comparable calls abi.EscapeNonString, whose body appears to panic;
200+
// but that's a lie, as EscapeNonString is a compiler intrinsic.
201+
// (go1.24 used a different intrinsic, maphash.escapeForHash.)
202+
maphash.Comparable[int](maphash.Seed{}, 0)
203+
}

go/analysis/passes/inline/inline.go

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package inline
77
import (
88
"fmt"
99
"go/ast"
10-
"go/token"
1110
"go/types"
1211
"slices"
1312
"strings"
@@ -23,7 +22,6 @@ import (
2322
"golang.org/x/tools/internal/analysis/analyzerutil"
2423
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
2524
"golang.org/x/tools/internal/astutil"
26-
"golang.org/x/tools/internal/diff"
2725
"golang.org/x/tools/internal/moreiters"
2826
"golang.org/x/tools/internal/packagepath"
2927
"golang.org/x/tools/internal/refactor"
@@ -204,19 +202,12 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
204202
var edits []analysis.TextEdit
205203
if !lazyEdits {
206204
// Inline the call.
207-
content, err := a.readFile(call)
208-
if err != nil {
209-
a.pass.Reportf(call.Lparen, "invalid inlining candidate: cannot read source file: %v", err)
210-
return
211-
}
212-
curFile := astutil.EnclosingFile(cur)
213205
caller := &inline.Caller{
214-
Fset: a.pass.Fset,
215-
Types: a.pass.Pkg,
216-
Info: a.pass.TypesInfo,
217-
File: curFile,
218-
Call: call,
219-
Content: content,
206+
Fset: a.pass.Fset,
207+
Types: a.pass.Pkg,
208+
Info: a.pass.TypesInfo,
209+
File: astutil.EnclosingFile(cur),
210+
Call: call,
220211
CountUses: func(pkgname *types.PkgName) int {
221212
return moreiters.Len(a.index.Uses(pkgname))
222213
},
@@ -245,15 +236,7 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
245236
// The flag allows them to decline such fixes.
246237
return
247238
}
248-
got := res.Content
249-
250-
for _, edit := range diff.Bytes(content, got) {
251-
edits = append(edits, analysis.TextEdit{
252-
Pos: curFile.FileStart + token.Pos(edit.Start),
253-
End: curFile.FileStart + token.Pos(edit.End),
254-
NewText: []byte(edit.New),
255-
})
256-
}
239+
edits = res.Edits
257240
}
258241

259242
a.pass.Report(analysis.Diagnostic{

go/analysis/passes/modernize/doc.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,19 @@ are often used to express optionality.
199199
200200
omitzero: suggest replacing omitempty with omitzero for struct fields
201201
202-
The omitzero analyzer identifies uses of the `omitempty` JSON struct tag on
203-
fields that are themselves structs. The `omitempty` tag has no effect on
204-
struct-typed fields. The analyzer offers two suggestions: either remove the
202+
The omitzero analyzer identifies uses of the `omitempty` JSON struct
203+
tag on fields that are themselves structs. For struct-typed fields,
204+
the `omitempty` tag has no effect on the behavior of json.Marshal and
205+
json.Unmarshal. The analyzer offers two suggestions: either remove the
205206
tag, or replace it with `omitzero` (added in Go 1.24), which correctly
206207
omits the field if the struct value is zero.
207208
209+
However, some other serialization packages (notably kubebuilder, see
210+
https://book.kubebuilder.io/reference/markers.html) may have their own
211+
interpretation of the `json:",omitzero"` tag, so removing it may affect
212+
program behavior. For this reason, the omitzero modernizer will not
213+
make changes in any package that contains +kubebuilder annotations.
214+
208215
Replacing `omitempty` with `omitzero` is a change in behavior. The
209216
original code would always encode the struct field, whereas the
210217
modified code will omit it if it is a zero-value.
@@ -475,6 +482,22 @@ with a single call to t.Context(), which was added in Go 1.24.
475482
This change is only suggested if the `cancel` function is not used
476483
for any other purpose.
477484
485+
# Analyzer unsafefuncs
486+
487+
unsafefuncs: replace unsafe pointer arithmetic with function calls
488+
489+
The unsafefuncs analyzer simplifies pointer arithmetic expressions by
490+
replacing them with calls to helper functions such as unsafe.Add,
491+
added in Go 1.17.
492+
493+
Example:
494+
495+
unsafe.Pointer(uintptr(ptr) + uintptr(n))
496+
497+
where ptr is an unsafe.Pointer, is replaced by:
498+
499+
unsafe.Add(ptr, n)
500+
478501
# Analyzer waitgroup
479502
480503
waitgroup: replace wg.Add(1)/go/wg.Done() with wg.Go

go/analysis/passes/modernize/forvar.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var ForVarAnalyzer = &analysis.Analyzer{
3535
// where the two idents are the same,
3636
// and the ident is defined (:=) as a variable in the for statement.
3737
// (Note that this 'fix' does not work for three clause loops
38-
// because the Go specfilesUsingGoVersionsays "The variable used by each subsequent iteration
38+
// because the Go spec says "The variable used by each subsequent iteration
3939
// is declared implicitly before executing the post statement and initialized to the
4040
// value of the previous iteration's variable at that moment.")
4141
//

go/analysis/passes/modernize/maps.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,16 @@ func mapsloop(pass *analysis.Pass) (any, error) {
233233
assign := rng.Body.List[0].(*ast.AssignStmt)
234234
if index, ok := assign.Lhs[0].(*ast.IndexExpr); ok &&
235235
astutil.EqualSyntax(rng.Key, index.Index) &&
236-
astutil.EqualSyntax(rng.Value, assign.Rhs[0]) &&
237-
is[*types.Map](typeparams.CoreType(info.TypeOf(index.X))) &&
238-
types.Identical(info.TypeOf(index), info.TypeOf(rng.Value)) { // m[k], v
236+
astutil.EqualSyntax(rng.Value, assign.Rhs[0]) {
237+
if tmap, ok := typeparams.CoreType(info.TypeOf(index.X)).(*types.Map); ok &&
238+
types.Identical(info.TypeOf(index), info.TypeOf(rng.Value)) && // m[k], v
239+
types.Identical(tmap.Key(), info.TypeOf(rng.Key)) {
239240

240-
// Have: for k, v := range x { m[k] = v }
241-
// where there is no implicit conversion.
242-
check(file, curRange, assign, index.X, rng.X)
241+
// Have: for k, v := range x { m[k] = v }
242+
// where there is no implicit conversion
243+
// of either key or value.
244+
check(file, curRange, assign, index.X, rng.X)
245+
}
243246
}
244247
}
245248
}

go/analysis/passes/modernize/modernize.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var Suite = []*analysis.Analyzer{
5353
StringsSeqAnalyzer,
5454
StringsBuilderAnalyzer,
5555
TestingContextAnalyzer,
56+
unsafeFuncsAnalyzer,
5657
WaitGroupAnalyzer,
5758
}
5859

go/analysis/passes/modernize/modernize_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestNewExpr(t *testing.T) {
5555
}
5656

5757
func TestOmitZero(t *testing.T) {
58-
RunWithSuggestedFixes(t, TestData(), modernize.OmitZeroAnalyzer, "omitzero")
58+
RunWithSuggestedFixes(t, TestData(), modernize.OmitZeroAnalyzer, "omitzero/...")
5959
}
6060

6161
func TestRangeInt(t *testing.T) {
@@ -109,6 +109,10 @@ func TestTestingContext(t *testing.T) {
109109
RunWithSuggestedFixes(t, TestData(), modernize.TestingContextAnalyzer, "testingcontext")
110110
}
111111

112+
func TestUnsafeFuncs(t *testing.T) {
113+
RunWithSuggestedFixes(t, TestData(), goplsexport.UnsafeFuncsModernizer, "unsafefuncs")
114+
}
115+
112116
func TestWaitGroup(t *testing.T) {
113117
RunWithSuggestedFixes(t, TestData(), modernize.WaitGroupAnalyzer, "waitgroup")
114118
}

0 commit comments

Comments
 (0)