func hasRowsSignature(info *types.Info, expr *ast.CallExpr) bool {
	fun, _ := expr.Fun.(*ast.SelectorExpr)
	sig, _ := info.Types[fun].Type.(*types.Signature)
	if sig == nil {
		return false  
	}
	res := sig.Results()
	if res.Len() != 2 {
		return false  
	}
	if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "database/sql", "Rows") {
		return false  
	}
	errorType := types.Universe.Lookup("error").Type()
	if !types.Identical(res.At(1).Type(), errorType) {
		return false  
	}
	return true
}
hasRowsSignature checks whether the given call expression is on
either a function of the database/sql package that returns (*sql.Rows, error).
package sqlrows
import (
	"flag"
	"go/ast"
	"go/token"
	"go/types"
	"github.com/gostaticanalysis/analysisutil"
	"github.com/gostaticanalysis/sqlrows/sqlrowsutil"
	"golang.org/x/tools/go/analysis"
	"golang.org/x/tools/go/analysis/passes/buildssa"
	"golang.org/x/tools/go/analysis/passes/inspect"
	"golang.org/x/tools/go/ast/inspector"
	"golang.org/x/tools/go/ssa"
)
const Doc = `check for mistakes using Rows iterator of database/sql 
A common mistake when using the database/sql package is to defer a function
call to close the Rows before checking the error that
determines whether the returned records are valid:
	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
	defer rows.Close()
	if err != nil {
		log.Fatal(err)
	}
This checker helps uncover latent nil dereference bugs by reporting a
diagnostic for such mistakes.`
var (
	flagCheckErr *bool
)
var Analyzer = &analysis.Analyzer{
	Name: "sqlrows",
	Doc:  Doc,
	Requires: []*analysis.Analyzer{
		inspect.Analyzer,
		buildssa.Analyzer,
	},
	Flags: func() flag.FlagSet {
		flagSet := flag.NewFlagSet("sqlrows", flag.ExitOnError)
		flagCheckErr = flagSet.Bool("checkerr", false, "check wether rows.Err() has been called")
		return *flagSet
	}(),
	Run: run,
}
func run(pass *analysis.Pass) (interface{}, error) {
	funcs := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).SrcFuncs
	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
	if !imports(pass.Pkg, "database/sql") {
		return nil, nil
	}
	rowsType := analysisutil.TypeOf(pass, "database/sql", "*Rows")
	if rowsType == nil {
		return nil, nil
	}
	var methods []*types.Func
	if m := analysisutil.MethodOf(rowsType, "Close"); m != nil {
		methods = append(methods, m)
	}
	var errMethod *types.Func
	if m := analysisutil.MethodOf(rowsType, "Err"); m != nil {
		errMethod = m
	}
	for _, f := range funcs {
		for _, b := range f.Blocks {
			for i := range b.Instrs {
				var pos token.Pos
				var refs *[]ssa.Instruction
				switch instr := b.Instrs[i].(type) {
				case *ssa.Extract:
					pos = instr.Tuple.Pos()
					refs = instr.Referrers()
				default:
					pos = instr.Pos()
				}
				called, ok := sqlrowsutil.CalledFrom(b, i, rowsType, methods...)
				if called {
					var defered bool
					for _, ref := range *refs {
						if _, ok := ref.(*ssa.Defer); ok {
							defered = true
						}
					}
					if !defered {
						pass.Reportf(pos, "rows.Close must be called in defer function")
					}
				}
				if ok && !called {
					pass.Reportf(pos, "rows.Close must be called")
				}
				if *flagCheckErr {
					if called, ok := sqlrowsutil.CalledFrom(b, i, rowsType, errMethod); ok && !called {
						pass.Reportf(pos, "rows.Err must be called")
					}
				}
			}
		}
	}
	nodeFilter := []ast.Node{
		(*ast.CallExpr)(nil),
	}
	inspect.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool {
		if !push {
			return true
		}
		call := n.(*ast.CallExpr)
		if !hasRowsSignature(pass.TypesInfo, call) {
			return true  
		}
		stmts := restOfBlock(stack)
		if len(stmts) < 2 {
			return true  
		}
		asg, ok := stmts[0].(*ast.AssignStmt)
		if !ok {
			return true  
		}
		resp := rootIdent(asg.Lhs[0])
		if resp == nil {
			return true  
		}
		def, ok := stmts[1].(*ast.DeferStmt)
		if !ok {
			return true  
		}
		root := rootIdent(def.Call.Fun)
		if root == nil {
			return true  
		}
		if resp.Obj == root.Obj {
			pass.Reportf(root.Pos(), "using %s before checking for errors", resp.Name)
		}
		return true
	})
	return nil, nil
}