src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

s1019.go (2383B)


      1 package s1019
      2 
      3 import (
      4 	"fmt"
      5 	"go/ast"
      6 	"go/types"
      7 	"path/filepath"
      8 
      9 	"honnef.co/go/tools/analysis/code"
     10 	"honnef.co/go/tools/analysis/facts/generated"
     11 	"honnef.co/go/tools/analysis/lint"
     12 	"honnef.co/go/tools/analysis/report"
     13 	"honnef.co/go/tools/go/types/typeutil"
     14 	"honnef.co/go/tools/pattern"
     15 
     16 	"golang.org/x/tools/go/analysis"
     17 	"golang.org/x/tools/go/analysis/passes/inspect"
     18 )
     19 
     20 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     21 	Analyzer: &analysis.Analyzer{
     22 		Name:     "S1019",
     23 		Run:      run,
     24 		Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer},
     25 	},
     26 	Doc: &lint.RawDocumentation{
     27 		Title: `Simplify \"make\" call by omitting redundant arguments`,
     28 		Text: `The \"make\" function has default values for the length and capacity
     29 arguments. For channels, the length defaults to zero, and for slices,
     30 the capacity defaults to the length.`,
     31 		Since: "2017.1",
     32 		// MergeIfAll because the type might be different under different build tags.
     33 		// You shouldn't write code like that…
     34 		MergeIf: lint.MergeIfAll,
     35 	},
     36 })
     37 
     38 var Analyzer = SCAnalyzer.Analyzer
     39 
     40 var (
     41 	checkMakeLenCapQ1 = pattern.MustParse(`(CallExpr (Builtin "make") [typ size@(IntegerLiteral "0")])`)
     42 	checkMakeLenCapQ2 = pattern.MustParse(`(CallExpr (Builtin "make") [typ size size])`)
     43 )
     44 
     45 func run(pass *analysis.Pass) (any, error) {
     46 	fn := func(node ast.Node) {
     47 		if pass.Pkg.Path() == "runtime_test" && filepath.Base(pass.Fset.Position(node.Pos()).Filename) == "map_test.go" {
     48 			// special case of runtime tests testing map creation
     49 			return
     50 		}
     51 		if m, ok := code.Match(pass, checkMakeLenCapQ1, node); ok {
     52 			T := m.State["typ"].(ast.Expr)
     53 			size := m.State["size"].(ast.Node)
     54 
     55 			if _, ok := typeutil.CoreType(pass.TypesInfo.TypeOf(T)).Underlying().(*types.Chan); ok {
     56 				report.Report(pass, size, fmt.Sprintf("should use make(%s) instead", report.Render(pass, T)), report.FilterGenerated())
     57 			}
     58 
     59 		} else if m, ok := code.Match(pass, checkMakeLenCapQ2, node); ok {
     60 			// TODO(dh): don't consider sizes identical if they're
     61 			// dynamic. for example: make(T, <-ch, <-ch).
     62 			T := m.State["typ"].(ast.Expr)
     63 			size := m.State["size"].(ast.Node)
     64 			report.Report(pass, size,
     65 				fmt.Sprintf("should use make(%s, %s) instead", report.Render(pass, T), report.Render(pass, size)),
     66 				report.FilterGenerated())
     67 		}
     68 	}
     69 	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
     70 	return nil, nil
     71 }