src

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

s1020.go (2059B)


      1 package s1020
      2 
      3 import (
      4 	"fmt"
      5 	"go/ast"
      6 	"go/types"
      7 
      8 	"honnef.co/go/tools/analysis/code"
      9 	"honnef.co/go/tools/analysis/facts/generated"
     10 	"honnef.co/go/tools/analysis/lint"
     11 	"honnef.co/go/tools/analysis/report"
     12 	"honnef.co/go/tools/pattern"
     13 
     14 	"golang.org/x/tools/go/analysis"
     15 )
     16 
     17 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     18 	Analyzer: &analysis.Analyzer{
     19 		Name:     "S1020",
     20 		Run:      run,
     21 		Requires: append([]*analysis.Analyzer{generated.Analyzer}, code.RequiredAnalyzers...),
     22 	},
     23 	Doc: &lint.RawDocumentation{
     24 		Title:   `Omit redundant nil check in type assertion`,
     25 		Before:  `if _, ok := i.(T); ok && i != nil {}`,
     26 		After:   `if _, ok := i.(T); ok {}`,
     27 		Since:   "2017.1",
     28 		MergeIf: lint.MergeIfAny,
     29 	},
     30 })
     31 
     32 var Analyzer = SCAnalyzer.Analyzer
     33 
     34 var (
     35 	checkAssertNotNilFn1Q = pattern.MustParse(`
     36 		(IfStmt
     37 			(AssignStmt [(Ident "_") ok@(Object _)] _ [(TypeAssertExpr assert@(Object _) _)])
     38 			(Or
     39 				(BinaryExpr ok "&&" (BinaryExpr assert "!=" (Builtin "nil")))
     40 				(BinaryExpr (BinaryExpr assert "!=" (Builtin "nil")) "&&" ok))
     41 			_
     42 			_)`)
     43 	checkAssertNotNilFn2Q = pattern.MustParse(`
     44 		(IfStmt
     45 			nil
     46 			(BinaryExpr lhs@(Object _) "!=" (Builtin "nil"))
     47 			[
     48 				ifstmt@(IfStmt
     49 					(AssignStmt [(Ident "_") ok@(Object _)] _ [(TypeAssertExpr lhs _)])
     50 					ok
     51 					_
     52 					nil)
     53 			]
     54 			nil)`)
     55 )
     56 
     57 func run(pass *analysis.Pass) (any, error) {
     58 	for node, m := range code.Matches(pass, checkAssertNotNilFn1Q) {
     59 		assert := m.State["assert"].(types.Object)
     60 		assign := m.State["ok"].(types.Object)
     61 		report.Report(pass, node, fmt.Sprintf("when %s is true, %s can't be nil", assign.Name(), assert.Name()),
     62 			report.ShortRange(),
     63 			report.FilterGenerated())
     64 	}
     65 	for _, m := range code.Matches(pass, checkAssertNotNilFn2Q) {
     66 		ifstmt := m.State["ifstmt"].(*ast.IfStmt)
     67 		lhs := m.State["lhs"].(types.Object)
     68 		assignIdent := m.State["ok"].(types.Object)
     69 		report.Report(pass, ifstmt, fmt.Sprintf("when %s is true, %s can't be nil", assignIdent.Name(), lhs.Name()),
     70 			report.ShortRange(),
     71 			report.FilterGenerated())
     72 	}
     73 	return nil, nil
     74 }