Skip to content
This repository was archived by the owner on Apr 10, 2019. It is now read-only.

Commit f64e0e4

Browse files
yasushi-saitoalecthomas
authored andcommitted
Update errcheck to the head.
It has whitelisted fmt.Fprintf, etc.
1 parent 5672743 commit f64e0e4

File tree

3 files changed

+82
-50
lines changed

3 files changed

+82
-50
lines changed

_linters/src/github.com/kisielk/errcheck/internal/errcheck/errcheck.go

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"errors"
99
"fmt"
1010
"go/ast"
11-
"go/build"
1211
"go/token"
1312
"go/types"
1413
"os"
@@ -17,8 +16,7 @@ import (
1716
"strings"
1817
"sync"
1918

20-
"go/parser"
21-
"golang.org/x/tools/go/loader"
19+
"golang.org/x/tools/go/packages"
2220
)
2321

2422
var errorType *types.Interface
@@ -137,6 +135,15 @@ func (c *Checker) SetExclude(l map[string]bool) {
137135
"fmt.Print",
138136
"fmt.Printf",
139137
"fmt.Println",
138+
"fmt.Fprint(*bytes.Buffer)",
139+
"fmt.Fprintf(*bytes.Buffer)",
140+
"fmt.Fprintln(*bytes.Buffer)",
141+
"fmt.Fprint(*strings.Builder)",
142+
"fmt.Fprintf(*strings.Builder)",
143+
"fmt.Fprintln(*strings.Builder)",
144+
"fmt.Fprint(os.Stderr)",
145+
"fmt.Fprintf(os.Stderr)",
146+
"fmt.Fprintln(os.Stderr)",
140147

141148
// math/rand
142149
"math/rand.Read",
@@ -165,28 +172,18 @@ func (c *Checker) logf(msg string, args ...interface{}) {
165172
}
166173
}
167174

168-
func (c *Checker) load(paths ...string) (*loader.Program, error) {
169-
ctx := build.Default
170-
for _, tag := range c.Tags {
171-
ctx.BuildTags = append(ctx.BuildTags, tag)
172-
}
173-
loadcfg := loader.Config{
174-
Build: &ctx,
175-
}
176-
177-
if c.WithoutGeneratedCode {
178-
loadcfg.ParserMode = parser.ParseComments
179-
}
175+
// loadPackages is used for testing.
176+
var loadPackages = func(cfg *packages.Config, paths ...string) ([]*packages.Package, error) {
177+
return packages.Load(cfg, paths...)
178+
}
180179

181-
rest, err := loadcfg.FromArgs(paths, !c.WithoutTests)
182-
if err != nil {
183-
return nil, fmt.Errorf("could not parse arguments: %s", err)
184-
}
185-
if len(rest) > 0 {
186-
return nil, fmt.Errorf("unhandled extra arguments: %v", rest)
180+
func (c *Checker) load(paths ...string) ([]*packages.Package, error) {
181+
cfg := &packages.Config{
182+
Mode: packages.LoadAllSyntax,
183+
Tests: !c.WithoutTests,
184+
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(c.Tags, " "))},
187185
}
188-
189-
return loadcfg.Load()
186+
return loadPackages(cfg, paths...)
190187
}
191188

192189
var generatedCodeRegexp = regexp.MustCompile("^// Code generated .* DO NOT EDIT\\.$")
@@ -209,27 +206,28 @@ func (c *Checker) shouldSkipFile(file *ast.File) bool {
209206

210207
// CheckPackages checks packages for errors.
211208
func (c *Checker) CheckPackages(paths ...string) error {
212-
program, err := c.load(paths...)
209+
pkgs, err := c.load(paths...)
213210
if err != nil {
214-
return fmt.Errorf("could not type check: %s", err)
211+
return err
212+
}
213+
// Check for errors in the initial packages.
214+
for _, pkg := range pkgs {
215+
if len(pkg.Errors) > 0 {
216+
return fmt.Errorf("errors while loading package %s: %v", pkg.ID, pkg.Errors)
217+
}
215218
}
216219

217220
var wg sync.WaitGroup
218221
u := &UncheckedErrors{}
219-
for _, pkgInfo := range program.InitialPackages() {
220-
if pkgInfo.Pkg.Path() == "unsafe" { // not a real package
221-
continue
222-
}
223-
222+
for _, pkg := range pkgs {
224223
wg.Add(1)
225224

226-
go func(pkgInfo *loader.PackageInfo) {
225+
go func(pkg *packages.Package) {
227226
defer wg.Done()
228-
c.logf("Checking %s", pkgInfo.Pkg.Path())
227+
c.logf("Checking %s", pkg.Types.Path())
229228

230229
v := &visitor{
231-
prog: program,
232-
pkg: pkgInfo,
230+
pkg: pkg,
233231
ignore: c.Ignore,
234232
blank: c.Blank,
235233
asserts: c.Asserts,
@@ -238,28 +236,36 @@ func (c *Checker) CheckPackages(paths ...string) error {
238236
errors: []UncheckedError{},
239237
}
240238

241-
for _, astFile := range v.pkg.Files {
239+
for _, astFile := range v.pkg.Syntax {
242240
if c.shouldSkipFile(astFile) {
243241
continue
244242
}
245243
ast.Walk(v, astFile)
246244
}
247245
u.Append(v.errors...)
248-
}(pkgInfo)
246+
}(pkg)
249247
}
250248

251249
wg.Wait()
252250
if u.Len() > 0 {
251+
// Sort unchecked errors and remove duplicates. Duplicates may occur when a file
252+
// containing an unchecked error belongs to > 1 package.
253253
sort.Sort(byName{u})
254+
uniq := u.Errors[:0] // compact in-place
255+
for i, err := range u.Errors {
256+
if i == 0 || err != u.Errors[i-1] {
257+
uniq = append(uniq, err)
258+
}
259+
}
260+
u.Errors = uniq
254261
return u
255262
}
256263
return nil
257264
}
258265

259266
// visitor implements the errcheck algorithm
260267
type visitor struct {
261-
prog *loader.Program
262-
pkg *loader.PackageInfo
268+
pkg *packages.Package
263269
ignore map[string]*regexp.Regexp
264270
blank bool
265271
asserts bool
@@ -284,7 +290,7 @@ func (v *visitor) selectorAndFunc(call *ast.CallExpr) (*ast.SelectorExpr, *types
284290
return nil, nil, false
285291
}
286292

287-
fn, ok := v.pkg.ObjectOf(sel.Sel).(*types.Func)
293+
fn, ok := v.pkg.TypesInfo.ObjectOf(sel.Sel).(*types.Func)
288294
if !ok {
289295
// Shouldn't happen, but be paranoid
290296
return nil, nil, false
@@ -340,7 +346,7 @@ func (v *visitor) namesForExcludeCheck(call *ast.CallExpr) []string {
340346

341347
// This will be missing for functions without a receiver (like fmt.Printf),
342348
// so just fall back to the the function's fullName in that case.
343-
selection, ok := v.pkg.Selections[sel]
349+
selection, ok := v.pkg.TypesInfo.Selections[sel]
344350
if !ok {
345351
return []string{name}
346352
}
@@ -363,13 +369,37 @@ func (v *visitor) namesForExcludeCheck(call *ast.CallExpr) []string {
363369
return result
364370
}
365371

372+
// isBufferType checks if the expression type is a known in-memory buffer type.
373+
func (v *visitor) argName(expr ast.Expr) string {
374+
// Special-case literal "os.Stdout" and "os.Stderr"
375+
if sel, ok := expr.(*ast.SelectorExpr); ok {
376+
if obj := v.pkg.TypesInfo.ObjectOf(sel.Sel); obj != nil {
377+
vr, ok := obj.(*types.Var)
378+
if ok && vr.Pkg() != nil && vr.Pkg().Name() == "os" && (vr.Name() == "Stderr" || vr.Name() == "Stdout") {
379+
return "os." + vr.Name()
380+
}
381+
}
382+
}
383+
t := v.pkg.TypesInfo.TypeOf(expr)
384+
if t == nil {
385+
return ""
386+
}
387+
return t.String()
388+
}
389+
366390
func (v *visitor) excludeCall(call *ast.CallExpr) bool {
391+
var arg0 string
392+
if len(call.Args) > 0 {
393+
arg0 = v.argName(call.Args[0])
394+
}
367395
for _, name := range v.namesForExcludeCheck(call) {
368396
if v.exclude[name] {
369397
return true
370398
}
399+
if arg0 != "" && v.exclude[name+"("+arg0+")"] {
400+
return true
401+
}
371402
}
372-
373403
return false
374404
}
375405

@@ -401,7 +431,7 @@ func (v *visitor) ignoreCall(call *ast.CallExpr) bool {
401431
return true
402432
}
403433

404-
if obj := v.pkg.Uses[id]; obj != nil {
434+
if obj := v.pkg.TypesInfo.Uses[id]; obj != nil {
405435
if pkg := obj.Pkg(); pkg != nil {
406436
if re, ok := v.ignore[pkg.Path()]; ok {
407437
return re.MatchString(id.Name)
@@ -435,7 +465,7 @@ func nonVendoredPkgPath(pkgPath string) (string, bool) {
435465
// len(s) == number of return types of call
436466
// s[i] == true iff return type at position i from left is an error type
437467
func (v *visitor) errorsByArg(call *ast.CallExpr) []bool {
438-
switch t := v.pkg.Types[call].Type.(type) {
468+
switch t := v.pkg.TypesInfo.Types[call].Type.(type) {
439469
case *types.Named:
440470
// Single return
441471
return []bool{isErrorType(t)}
@@ -477,15 +507,15 @@ func (v *visitor) callReturnsError(call *ast.CallExpr) bool {
477507
// isRecover returns true if the given CallExpr is a call to the built-in recover() function.
478508
func (v *visitor) isRecover(call *ast.CallExpr) bool {
479509
if fun, ok := call.Fun.(*ast.Ident); ok {
480-
if _, ok := v.pkg.Uses[fun].(*types.Builtin); ok {
510+
if _, ok := v.pkg.TypesInfo.Uses[fun].(*types.Builtin); ok {
481511
return fun.Name == "recover"
482512
}
483513
}
484514
return false
485515
}
486516

487517
func (v *visitor) addErrorAtPosition(position token.Pos, call *ast.CallExpr) {
488-
pos := v.prog.Fset.Position(position)
518+
pos := v.pkg.Fset.Position(position)
489519
lines, ok := v.lines[pos.Filename]
490520
if !ok {
491521
lines = readfile(pos.Filename)

_linters/src/github.com/kisielk/errcheck/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"strings"
1212

1313
"github.com/kisielk/errcheck/internal/errcheck"
14-
"github.com/kisielk/gotool"
1514
)
1615

1716
const (
@@ -133,7 +132,7 @@ func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) {
133132
flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier")
134133
flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results")
135134
flags.BoolVar(&checker.WithoutTests, "ignoretests", false, "if true, checking of _test.go files is disabled")
136-
flags.BoolVar(&checker.WithoutGeneratedCode, "ignoregenerated", false, "if true, checking of files with generated code is disabled")
135+
flags.BoolVar(&checker.WithoutGeneratedCode, "ignoregenerated", false, "if true, checking of files with generated code is disabled")
137136
flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging")
138137

139138
flags.BoolVar(&abspath, "abspath", false, "print absolute paths to files")
@@ -183,8 +182,11 @@ func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) {
183182
}
184183
checker.Ignore = ignore
185184

186-
// ImportPaths normalizes paths and expands '...'
187-
return gotool.ImportPaths(flags.Args()), exitCodeOk
185+
paths := flags.Args()
186+
if len(paths) == 0 {
187+
paths = []string{"."}
188+
}
189+
return paths, exitCodeOk
188190
}
189191

190192
func main() {

_linters/src/manifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
"importpath": "github.com/kisielk/errcheck",
7878
"repository": "https://github.com/kisielk/errcheck",
7979
"vcs": "git",
80-
"revision": "e96dacdb078a5166c20b48dd667fb26d2ce0379f",
80+
"revision": "e14f8d59a22d460d56c5ee92507cd94c78fbf274",
8181
"branch": "master",
8282
"notests": true
8383
},

0 commit comments

Comments
 (0)