File: toonew.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.25.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 22,724 kB
  • sloc: javascript: 2,027; asm: 1,645; sh: 166; yacc: 155; makefile: 49; ansic: 8
file content (89 lines) | stat: -rw-r--r-- 2,943 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package typesinternal

import (
	"go/types"

	"golang.org/x/tools/internal/stdlib"
	"golang.org/x/tools/internal/versions"
)

// TooNewStdSymbols computes the set of package-level symbols
// exported by pkg that are not available at the specified version.
// The result maps each symbol to its minimum version.
//
// The pkg is allowed to contain type errors.
func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]string {
	disallowed := make(map[types.Object]string)

	// Pass 1: package-level symbols.
	symbols := stdlib.PackageSymbols[pkg.Path()]
	for _, sym := range symbols {
		symver := sym.Version.String()
		if versions.Before(version, symver) {
			switch sym.Kind {
			case stdlib.Func, stdlib.Var, stdlib.Const, stdlib.Type:
				disallowed[pkg.Scope().Lookup(sym.Name)] = symver
			}
		}
	}

	// Pass 2: fields and methods.
	//
	// We allow fields and methods if their associated type is
	// disallowed, as otherwise we would report false positives
	// for compatibility shims. Consider:
	//
	//   //go:build go1.22
	//   type T struct { F std.Real } // correct new API
	//
	//   //go:build !go1.22
	//   type T struct { F fake } // shim
	//   type fake struct { ... }
	//   func (fake) M () {}
	//
	// These alternative declarations of T use either the std.Real
	// type, introduced in go1.22, or a fake type, for the field
	// F. (The fakery could be arbitrarily deep, involving more
	// nested fields and methods than are shown here.) Clients
	// that use the compatibility shim T will compile with any
	// version of go, whether older or newer than go1.22, but only
	// the newer version will use the std.Real implementation.
	//
	// Now consider a reference to method M in new(T).F.M() in a
	// module that requires a minimum of go1.21. The analysis may
	// occur using a version of Go higher than 1.21, selecting the
	// first version of T, so the method M is Real.M. This would
	// spuriously cause the analyzer to report a reference to a
	// too-new symbol even though this expression compiles just
	// fine (with the fake implementation) using go1.21.
	for _, sym := range symbols {
		symVersion := sym.Version.String()
		if !versions.Before(version, symVersion) {
			continue // allowed
		}

		var obj types.Object
		switch sym.Kind {
		case stdlib.Field:
			typename, name := sym.SplitField()
			if t := pkg.Scope().Lookup(typename); t != nil && disallowed[t] == "" {
				obj, _, _ = types.LookupFieldOrMethod(t.Type(), false, pkg, name)
			}

		case stdlib.Method:
			ptr, recvname, name := sym.SplitMethod()
			if t := pkg.Scope().Lookup(recvname); t != nil && disallowed[t] == "" {
				obj, _, _ = types.LookupFieldOrMethod(t.Type(), ptr, pkg, name)
			}
		}
		if obj != nil {
			disallowed[obj] = symVersion
		}
	}

	return disallowed
}