go_npecheck

package module
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2023 License: MIT Imports: 7 Imported by: 1

README

npecheck

pkg.go.dev

npecheck Check for potential nil pointer reference exceptions to compensate for go linter's shortcomings in this area. This linter is supposed to be the most rigorous and complete NPE solution.

How to use

$ go install github.com/chenfeining/go-npecheck/cmd/npecheck@latest
$ npecheck ./...

Test case

The full use case can be found at testdata. Some examples are posted here

  1. npecheck Function parameter is pointer, and its variable is directly referenced without validation
func np1Example(d *DataInfo) {
    fmt.Println(d.A) // want "potential nil pointer reference"

    // d may be is a nil pointer, you had better to check it before reference.
    // such as :
    // if d != nil {
    //	  fmt.Println(d.A)
    // }
    
    // Or:
    // if d == nil {
    //	  return
    // }
    // fmt.Println(d.A)
    
    // Otherwise it is potential nil pointer reference, sometimes it's unexpected disaster
}

  1. npecheck Function parameter is pointer, and its variables are directly referenced in a chain without validation
func np2Example(d *DataInfo) {
	fmt.Println(d.A.B) // want "potential nil pointer reference" "potential nil pointer reference"

	// d is a potential nil pointer
	// d.A is also a potential nil pointer
	// You can follow the writing below, and will be more safe:

	// if d != nil && d.A != nil {
	//     fmt.Println(d.A.B)
	//}

	// Or:
	// if d == nil {
	//	 return
	// }
	//
	// if d.A == nil {
	//	 return
	// }
	//
	// fmt.Println(d.A.B)
}
  1. npecheck A pointer variable obtained by calling an external function, unverified, directly referenced
func np3Example() {
	d := GetDataInfo() // d is a pointer obtained by calling an external function
	fmt.Println(d.A)   // want "potential nil pointer reference"

	// d may be is a nil pointer, you had better to check it before reference.
	// such as :
	// if d != nil {
	//	fmt.Println(d.A)
	// }

	// Or:
	// if d == nil {
	//	return
	// }
	// fmt.Println(d.A)

	// Otherwise it is potential nil pointer reference, sometimes it's unexpected disaster
}

  1. npecheck A pointer variable obtained by calling an external function, unverified, directly chain referenced
func np4Example() {
	d := GetDataInfo()
	fmt.Println(d.A.B) // want "potential nil pointer reference" "potential nil pointer reference"

	// d is a potential nil pointer
	// d.A is also a potential nil pointer
	// You can follow the writing below, and will be more safe:

	// if d != nil && d.A != nil {
	//     fmt.Println(d.A.B)
	//}

	// Or:
	// if d == nil {
	//	 return
	// }
	//
	// if d.A == nil {
	//	 return
	// }
	//
	// fmt.Println(d.A.B)
}

  1. npecheck Function input parameter is slice including pointer, and their elements are directly referenced without validation
func np5Example(infoList []*Node) {
	for _, info := range infoList {
		fmt.Println(info.A) // want "potential nil pointer reference"
		// info is a potential nil pointer
		// It can be written as follows, and will be more safe.

		// if info != nil {
		// 	fmt.Println(info.A)
		// }

		// Or:
		// if info == nil {
		// 	  continue
		// }
		// fmt.Println(info.A)
	}
}

  1. npecheck An slice including pointers obtained by a function, whose pointer elements are not checked and are directly referenced
func np6Example() {
	infoList := GetDataInfoList()
	for _, info := range infoList {
		fmt.Println(info.A) // want "potential nil pointer reference"

		// info is a potential nil pointer
		// It can be written as follows, and will be more safe.

		// if info != nil {
		// 	fmt.Println(info.A)
		// }

		// Or:
		// if info == nil {
		// 	  continue
		// }
		// 	fmt.Println(info.A)
	}
}

  1. npecheck Function parameter is pointer, and its method is directly referenced without validation
func np7Example1(d *DataInfo) {
	d.printDataInfo() // want "potential nil pointer reference"

	// d is a potential nil pointer
	// It can be written as follows, and will be more safe.
	// if d != nil {
	// 	d.printDataInfo()
	// }

	// Or:
	// if d == nil {
	// 	 return
	// }
	// d.printDataInfo()
}

  1. npecheck Function parameter is pointer, and its method is directly referenced in chain without validation
func np8Example(d *DataInfo) {
	_ = d.GetChildNodePtr().PrintScore() // want "potential nil pointer reference" "potential nil pointer reference"

	// d is a potential nil pointer reference
	// d.GetChildNodePtr() is also a potential nil pointer

	// It can be written as follows, and will be more safe.
	// if d != nil && d.GetChildNodePtr() != nil {
	// 	_ = d.GetChildNodePtr().PrintScore()
	// }

	// Or:
	// if d == nil {
	// 	 return
	// }
	//
	// if d.GetChildNodePtr() == nil {
	//	 return
	// }
	//
	// _ = d.GetChildNodePtr().PrintScore()
}

  1. npecheck A pointer variable obtained by calling an external function, and its method is directly referenced in chain without validation
func np9Example() {
	d := GetDataInfo()
	_ = d.GetChildNodePtr().PrintScore() // want "potential nil pointer reference" "potential nil pointer reference"

	// d is a potential nil pointer reference
	// d.GetChildNodePtr() is also a potential nil pointer

	// It can be written as follows, and will be more safe.
	// if d != nil && d.GetChildNodePtr() != nil {
	// 	_ = d.GetChildNodePtr().PrintScore()
	// }

	// Or:
	// if d == nil {
	// 	 return
	// }
	//
	// if d.GetChildNodePtr() == nil {
	//	 return
	// }
	//
	// _ = d.GetChildNodePtr().PrintScore()
}

  1. npecheck Function parameter is pointer, and its child-node method is directly referenced in chain without validation
func np10Example(d *DataInfo) {
	age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age // want "potential nil pointer reference" "potential nil pointer reference"
	fmt.Println(age)
	// d is a potential nil pointer
	// d.GetChildNodeNonPtr() is not a pointer, just a struct variable
	// d.GetChildNodeNonPtr().GetGrandsonNodePtr() is a potential nil pointer

	// It can be written as follows, and will be more safe.
	// if d == nil {
	// 	 return
	// }
	//
	// if d.GetChildNodeNonPtr().GetGrandsonNodePtr() != nil {
	//	 age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age
	//	 fmt.Println(age)
	// }

	// Or:
	// if d != nil && d.GetChildNodeNonPtr().GetGrandsonNodePtr() != nil {
	//	 age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age
	//	 fmt.Println(age)
	// }
}

  1. npecheck A pointer variable obtained by calling an external function, and its child-node method is directly referenced in chain without validation
func np11Example() {
	d := GetDataInfo()
	age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age // want "potential nil pointer reference" "potential nil pointer reference"
	fmt.Println(age)

	// d is a potential nil pointer
	// d.GetChildNodeNonPtr() is not a pointer, just a struct variable
	// d.GetChildNodeNonPtr().GetGrandsonNodePtr() is a potential nil pointer

	// It can be written as follows, and will be more safe.
	// if d == nil {
	// 	 return
	// }
	//
	// if d.GetChildNodeNonPtr().GetGrandsonNodePtr() != nil {
	//	 age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age
	//	 fmt.Println(age)
	// }

	// Or:
	// if d != nil && d.GetChildNodeNonPtr().GetGrandsonNodePtr() != nil {
	//	 age := d.GetChildNodeNonPtr().GetGrandsonNodePtr().Age
	//	 fmt.Println(age)
	// }
}

  1. npecheck Skip the parent node pointer check and directly verify the child node.
func np12Example(d *DataInfo) {
	if d.A != nil { // want "potential nil pointer reference"
		fmt.Println(d.A.B) // want "potential nil pointer reference" "potential nil pointer reference"
	}

	// d is a potential nil pointer. It should valid d first.
	// It can be written as follows, and will be more safe.

	// if d != nil && d.A != nil {
	//	 fmt.Println(d.A.B)
	// }

	// Or:
	// if d == nil {
	//	 return
	// }
	//
	// if d.A != nil {
	//	 fmt.Println(d.A.B)
	//}

	// Or:
	// if d == nil {
	//	 return
	// }
	// if d.A == nil {
	//	 return
	// }
	// fmt.Println(d.A.B)
}

Documentation

Index

Constants

View Source
const (
	DefaultPtrType      int = 0 // ptr
	SlicePtrType        int = 1 // []ptr
	ParentPtrCurNonType int = 2 //  A.B.GNode , A is ptr,B is not ptr
)
View Source
const (
	NodeTypeDefaultSinglePtr int = 0
	NodeTypeNonSinglePtr     int = 1
)
View Source
const Doc = "check potential nil pointer reference"
View Source
const NPEMessageTipInfo = "potential nil pointer reference"

Variables

View Source
var Analyzer = &analysis.Analyzer{
	Name: "npecheck",
	Doc:  Doc,
	Run:  Run,
}

Functions

func GetFuncSignature

func GetFuncSignature(ex *ast.CallExpr, typeInfo *types.Info) *types.Signature

func GetIdentPosition

func GetIdentPosition(p *token.Position, ident *ast.Ident, fset *token.FileSet)

func GetNodeType

func GetNodeType(ident *ast.Ident, typesInfo *types.Info) (int, bool)

func IsFuncPtrRespNeedSkip added in v1.0.4

func IsFuncPtrRespNeedSkip(name string) bool

func IsPointer

func IsPointer(typ types.Type) bool

func IsPointerArray

func IsPointerArray(ident *ast.Ident, info *types.Info) bool

func IsSliceIncludePointerElem

func IsSliceIncludePointerElem(typ types.Type) bool

func RemoveVarLeafNode

func RemoveVarLeafNode(varName string, originFieldMap map[string]string) string

func Run

func Run(pass *analysis.Pass) (interface{}, error)

func TravelSelectorName

func TravelSelectorName(expr *ast.SelectorExpr, fset *token.FileSet) []string

func WalkSelector

func WalkSelector(expr *ast.SelectorExpr, fset *token.FileSet, walkFunc func(ast.Node))

Types

type CheckPointerPosition

type CheckPointerPosition struct {
	Line      int
	Colum     int
	IsChecked bool
	Type      int // DefaultPtrType, SlicePtrType, ParentPtrCurNonType
}

type FuncDelChecker

type FuncDelChecker struct {
	// contains filtered or unexported fields
}

func InitFuncDelChecker

func InitFuncDelChecker(pass *analysis.Pass) *FuncDelChecker

type LintError

type LintError struct {
	Message string
	File    string
	Line    int
	Colum   int
}

func (*LintError) Error

func (err *LintError) Error() string

实现 Error 方法

type SelectNode

type SelectNode struct {
	Name               string
	Type               int // NodeTypeDefaultSinglePtr, NodeTypeNonSinglePtr
	IsReturnSingleFunc bool
	CurIdent           *ast.Ident
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL