Skip to content

Commit 5572979

Browse files
authored
dev: sync checker with x/[email protected] (golangci#5201)
1 parent e5d8818 commit 5572979

13 files changed

+339
-133
lines changed

.golangci.next.reference.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,8 @@ linters-settings:
18401840
- unusedresult
18411841
# Checks for unused writes.
18421842
- unusedwrite
1843+
# Checks for misuses of sync.WaitGroup.
1844+
- waitgroup
18431845

18441846
# Enable all analyzers.
18451847
# Default: false

.golangci.yml

+3
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ issues:
222222
exclude-dirs:
223223
- test/testdata_etc # test files
224224
- internal/go # extracted from Go code
225+
- internal/x # extracted from x/tools code
226+
exclude-files:
227+
- pkg/goanalysis/runner_checker.go # extracted from x/tools code
225228

226229
run:
227230
timeout: 5m

internal/x/LICENSE

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright 2009 The Go Authors.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google LLC nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# analysisflags
2+
3+
Extracted from `/go/analysis/internal/analysisflags` (related to `checker`).
4+
This is just a copy of the code without any changes.
5+
6+
## History
7+
8+
- sync with https://github.com/golang/tools/blob/v0.28.0

internal/x/tools/analysisflags/url.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package analysisflags
6+
7+
import (
8+
"fmt"
9+
"net/url"
10+
11+
"golang.org/x/tools/go/analysis"
12+
)
13+
14+
// ResolveURL resolves the URL field for a Diagnostic from an Analyzer
15+
// and returns the URL. See Diagnostic.URL for details.
16+
func ResolveURL(a *analysis.Analyzer, d analysis.Diagnostic) (string, error) {
17+
if d.URL == "" && d.Category == "" && a.URL == "" {
18+
return "", nil // do nothing
19+
}
20+
raw := d.URL
21+
if d.URL == "" && d.Category != "" {
22+
raw = "#" + d.Category
23+
}
24+
u, err := url.Parse(raw)
25+
if err != nil {
26+
return "", fmt.Errorf("invalid Diagnostic.URL %q: %s", raw, err)
27+
}
28+
base, err := url.Parse(a.URL)
29+
if err != nil {
30+
return "", fmt.Errorf("invalid Analyzer.URL %q: %s", a.URL, err)
31+
}
32+
return base.ResolveReference(u).String(), nil
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package analysisinternal provides gopls' internal analyses with a
6+
// number of helper functions that operate on typed syntax trees.
7+
package analysisinternal
8+
9+
import (
10+
"fmt"
11+
"os"
12+
13+
"golang.org/x/tools/go/analysis"
14+
)
15+
16+
// MakeReadFile returns a simple implementation of the Pass.ReadFile function.
17+
func MakeReadFile(pass *analysis.Pass) func(filename string) ([]byte, error) {
18+
return func(filename string) ([]byte, error) {
19+
if err := CheckReadable(pass, filename); err != nil {
20+
return nil, err
21+
}
22+
return os.ReadFile(filename)
23+
}
24+
}
25+
26+
// CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass].
27+
func CheckReadable(pass *analysis.Pass, filename string) error {
28+
if slicesContains(pass.OtherFiles, filename) ||
29+
slicesContains(pass.IgnoredFiles, filename) {
30+
return nil
31+
}
32+
for _, f := range pass.Files {
33+
if pass.Fset.File(f.FileStart).Name() == filename {
34+
return nil
35+
}
36+
}
37+
return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
38+
}
39+
40+
// TODO(adonovan): use go1.21 slices.Contains.
41+
func slicesContains[S ~[]E, E comparable](slice S, x E) bool {
42+
for _, elem := range slice {
43+
if elem == x {
44+
return true
45+
}
46+
}
47+
return false
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# analysisinternal
2+
3+
Extracted from `/internal/analysisinternal/` (related to `checker`).
4+
This is just a copy of the code without any changes.
5+
6+
## History
7+
8+
- sync with https://github.com/golang/tools/blob/v0.28.0

jsonschema/golangci.next.jsonschema.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@
210210
"unreachable",
211211
"unsafeptr",
212212
"unusedresult",
213-
"unusedwrite"
213+
"unusedwrite",
214+
"waitgroup"
214215
]
215216
},
216217
"revive-rules": {

pkg/goanalysis/runner.go

+19-19
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ func (r *runner) makeAction(a *analysis.Analyzer, pkg *packages.Package,
121121
}
122122

123123
act = actAlloc.alloc()
124-
act.a = a
125-
act.pkg = pkg
126-
act.r = r
124+
act.Analyzer = a
125+
act.Package = pkg
126+
act.runner = r
127127
act.isInitialPkg = initialPkgs[pkg]
128128
act.needAnalyzeSource = initialPkgs[pkg]
129129
act.analysisDoneCh = make(chan struct{})
@@ -132,11 +132,11 @@ func (r *runner) makeAction(a *analysis.Analyzer, pkg *packages.Package,
132132
if len(a.FactTypes) > 0 {
133133
depsCount += len(pkg.Imports)
134134
}
135-
act.deps = make([]*action, 0, depsCount)
135+
act.Deps = make([]*action, 0, depsCount)
136136

137137
// Add a dependency on each required analyzers.
138138
for _, req := range a.Requires {
139-
act.deps = append(act.deps, r.makeAction(req, pkg, initialPkgs, actions, actAlloc))
139+
act.Deps = append(act.Deps, r.makeAction(req, pkg, initialPkgs, actions, actAlloc))
140140
}
141141

142142
r.buildActionFactDeps(act, a, pkg, initialPkgs, actions, actAlloc)
@@ -162,7 +162,7 @@ func (r *runner) buildActionFactDeps(act *action, a *analysis.Analyzer, pkg *pac
162162
sort.Strings(paths) // for determinism
163163
for _, path := range paths {
164164
dep := r.makeAction(a, pkg.Imports[path], initialPkgs, actions, actAlloc)
165-
act.deps = append(act.deps, dep)
165+
act.Deps = append(act.Deps, dep)
166166
}
167167

168168
// Need to register fact types for pkgcache proper gob encoding.
@@ -203,7 +203,7 @@ func (r *runner) prepareAnalysis(pkgs []*packages.Package,
203203
for _, a := range analyzers {
204204
for _, pkg := range pkgs {
205205
root := r.makeAction(a, pkg, initialPkgs, actions, actAlloc)
206-
root.isroot = true
206+
root.IsRoot = true
207207
roots = append(roots, root)
208208
}
209209
}
@@ -220,7 +220,7 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze
220220

221221
actionPerPkg := map[*packages.Package][]*action{}
222222
for _, act := range actions {
223-
actionPerPkg[act.pkg] = append(actionPerPkg[act.pkg], act)
223+
actionPerPkg[act.Package] = append(actionPerPkg[act.Package], act)
224224
}
225225

226226
// Fill Imports field.
@@ -250,7 +250,7 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze
250250
}
251251
}
252252
for _, act := range actions {
253-
dfs(act.pkg)
253+
dfs(act.Package)
254254
}
255255

256256
// Limit memory and IO usage.
@@ -282,7 +282,7 @@ func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []err
282282
for _, act := range actions {
283283
if !extracted[act] {
284284
extracted[act] = true
285-
visitAll(act.deps)
285+
visitAll(act.Deps)
286286
extract(act)
287287
}
288288
}
@@ -299,31 +299,31 @@ func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []err
299299
seen := make(map[key]bool)
300300

301301
extract = func(act *action) {
302-
if act.err != nil {
303-
if pe, ok := act.err.(*errorutil.PanicError); ok {
302+
if act.Err != nil {
303+
if pe, ok := act.Err.(*errorutil.PanicError); ok {
304304
panic(pe)
305305
}
306-
retErrors = append(retErrors, fmt.Errorf("%s: %w", act.a.Name, act.err))
306+
retErrors = append(retErrors, fmt.Errorf("%s: %w", act.Analyzer.Name, act.Err))
307307
return
308308
}
309309

310-
if act.isroot {
311-
for _, diag := range act.diagnostics {
310+
if act.IsRoot {
311+
for _, diag := range act.Diagnostics {
312312
// We don't display a.Name/f.Category
313313
// as most users don't care.
314314

315-
posn := act.pkg.Fset.Position(diag.Pos)
316-
k := key{posn, act.a, diag.Message}
315+
posn := act.Package.Fset.Position(diag.Pos)
316+
k := key{posn, act.Analyzer, diag.Message}
317317
if seen[k] {
318318
continue // duplicate
319319
}
320320
seen[k] = true
321321

322322
retDiag := Diagnostic{
323323
Diagnostic: diag,
324-
Analyzer: act.a,
324+
Analyzer: act.Analyzer,
325325
Position: posn,
326-
Pkg: act.pkg,
326+
Pkg: act.Package,
327327
}
328328
retDiags = append(retDiags, retDiag)
329329
}

pkg/goanalysis/runner_action.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ func (actAlloc *actionAllocator) alloc() *action {
2929
}
3030

3131
func (act *action) waitUntilDependingAnalyzersWorked() {
32-
for _, dep := range act.deps {
33-
if dep.pkg == act.pkg {
32+
for _, dep := range act.Deps {
33+
if dep.Package == act.Package {
3434
<-dep.analysisDoneCh
3535
}
3636
}
@@ -39,26 +39,26 @@ func (act *action) waitUntilDependingAnalyzersWorked() {
3939
func (act *action) analyzeSafe() {
4040
defer func() {
4141
if p := recover(); p != nil {
42-
if !act.isroot {
42+
if !act.IsRoot {
4343
// This line allows to display "hidden" panic with analyzers like buildssa.
4444
// Some linters are dependent of sub-analyzers but when a sub-analyzer fails the linter is not aware of that,
4545
// this results to another panic (ex: "interface conversion: interface {} is nil, not *buildssa.SSA").
46-
act.r.log.Errorf("%s: panic during analysis: %v, %s", act.a.Name, p, string(debug.Stack()))
46+
act.runner.log.Errorf("%s: panic during analysis: %v, %s", act.Analyzer.Name, p, string(debug.Stack()))
4747
}
4848

49-
act.err = errorutil.NewPanicError(fmt.Sprintf("%s: package %q (isInitialPkg: %t, needAnalyzeSource: %t): %s",
50-
act.a.Name, act.pkg.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack())
49+
act.Err = errorutil.NewPanicError(fmt.Sprintf("%s: package %q (isInitialPkg: %t, needAnalyzeSource: %t): %s",
50+
act.Analyzer.Name, act.Package.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack())
5151
}
5252
}()
5353

54-
act.r.sw.TrackStage(act.a.Name, act.analyze)
54+
act.runner.sw.TrackStage(act.Analyzer.Name, act.analyze)
5555
}
5656

5757
func (act *action) markDepsForAnalyzingSource() {
5858
// Horizontal deps (analyzer.Requires) must be loaded from source and analyzed before analyzing
5959
// this action.
60-
for _, dep := range act.deps {
61-
if dep.pkg == act.pkg {
60+
for _, dep := range act.Deps {
61+
if dep.Package == act.Package {
6262
// Analyze source only for horizontal dependencies, e.g. from "buildssa".
6363
dep.needAnalyzeSource = true // can't be set in parallel
6464
}

pkg/goanalysis/runner_action_cache.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (act *action) loadCachedFacts() bool {
2626
return true // load cached facts only for non-initial packages
2727
}
2828

29-
if len(act.a.FactTypes) == 0 {
29+
if len(act.Analyzer.FactTypes) == 0 {
3030
return true // no need to load facts
3131
}
3232

@@ -38,15 +38,15 @@ func (act *action) loadCachedFacts() bool {
3838
}
3939

4040
func (act *action) persistFactsToCache() error {
41-
analyzer := act.a
41+
analyzer := act.Analyzer
4242
if len(analyzer.FactTypes) == 0 {
4343
return nil
4444
}
4545

4646
// Merge new facts into the package and persist them.
4747
var facts []Fact
4848
for key, fact := range act.packageFacts {
49-
if key.pkg != act.pkg.Types {
49+
if key.pkg != act.Package.Types {
5050
// The fact is from inherited facts from another package
5151
continue
5252
}
@@ -57,7 +57,7 @@ func (act *action) persistFactsToCache() error {
5757
}
5858
for key, fact := range act.objectFacts {
5959
obj := key.obj
60-
if obj.Pkg() != act.pkg.Types {
60+
if obj.Pkg() != act.Package.Types {
6161
// The fact is from inherited facts from another package
6262
continue
6363
}
@@ -74,33 +74,33 @@ func (act *action) persistFactsToCache() error {
7474
})
7575
}
7676

77-
factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
77+
factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.Package.Name, act.Analyzer.Name)
7878

79-
return act.r.pkgCache.Put(act.pkg, cache.HashModeNeedAllDeps, factCacheKey(analyzer), facts)
79+
return act.runner.pkgCache.Put(act.Package, cache.HashModeNeedAllDeps, factCacheKey(analyzer), facts)
8080
}
8181

8282
func (act *action) loadPersistedFacts() bool {
8383
var facts []Fact
8484

85-
err := act.r.pkgCache.Get(act.pkg, cache.HashModeNeedAllDeps, factCacheKey(act.a), &facts)
85+
err := act.runner.pkgCache.Get(act.Package, cache.HashModeNeedAllDeps, factCacheKey(act.Analyzer), &facts)
8686
if err != nil {
8787
if !errors.Is(err, cache.ErrMissing) && !errors.Is(err, io.EOF) {
88-
act.r.log.Warnf("Failed to get persisted facts: %s", err)
88+
act.runner.log.Warnf("Failed to get persisted facts: %s", err)
8989
}
9090

91-
factsCacheDebugf("No cached facts for package %q and analyzer %s", act.pkg.Name, act.a.Name)
91+
factsCacheDebugf("No cached facts for package %q and analyzer %s", act.Package.Name, act.Analyzer.Name)
9292
return false
9393
}
9494

95-
factsCacheDebugf("Loaded %d cached facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
95+
factsCacheDebugf("Loaded %d cached facts for package %q and analyzer %s", len(facts), act.Package.Name, act.Analyzer.Name)
9696

9797
for _, f := range facts {
9898
if f.Path == "" { // this is a package fact
99-
key := packageFactKey{act.pkg.Types, act.factType(f.Fact)}
99+
key := packageFactKey{act.Package.Types, act.factType(f.Fact)}
100100
act.packageFacts[key] = f.Fact
101101
continue
102102
}
103-
obj, err := objectpath.Object(act.pkg.Types, objectpath.Path(f.Path))
103+
obj, err := objectpath.Object(act.Package.Types, objectpath.Path(f.Path))
104104
if err != nil {
105105
// Be lenient about these errors. For example, when
106106
// analyzing io/ioutil from source, we may get a fact

0 commit comments

Comments
 (0)