go/analysis: unindent some pieces of code
All of these were quite heavily indented for no good reason; breaking or returning early makes the code easier to read and follow. Change-Id: Ic539517b07604d71495277b16f1b7eb60d2e3d3c Reviewed-on: https://go-review.googlesource.com/c/149978 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
2ddaf7f79a
commit
70b12541d3
|
@ -93,32 +93,32 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
|
||||||
// ctx, cancel = context.WithCancel(...)
|
// ctx, cancel = context.WithCancel(...)
|
||||||
// var ctx, cancel = context.WithCancel(...)
|
// var ctx, cancel = context.WithCancel(...)
|
||||||
//
|
//
|
||||||
if isContextWithCancel(pass.TypesInfo, n) && isCall(stack[len(stack)-2]) {
|
if !isContextWithCancel(pass.TypesInfo, n) || !isCall(stack[len(stack)-2]) {
|
||||||
var id *ast.Ident // id of cancel var
|
return true
|
||||||
stmt := stack[len(stack)-3]
|
}
|
||||||
switch stmt := stmt.(type) {
|
var id *ast.Ident // id of cancel var
|
||||||
case *ast.ValueSpec:
|
stmt := stack[len(stack)-3]
|
||||||
if len(stmt.Names) > 1 {
|
switch stmt := stmt.(type) {
|
||||||
id = stmt.Names[1]
|
case *ast.ValueSpec:
|
||||||
}
|
if len(stmt.Names) > 1 {
|
||||||
case *ast.AssignStmt:
|
id = stmt.Names[1]
|
||||||
if len(stmt.Lhs) > 1 {
|
|
||||||
id, _ = stmt.Lhs[1].(*ast.Ident)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if id != nil {
|
case *ast.AssignStmt:
|
||||||
if id.Name == "_" {
|
if len(stmt.Lhs) > 1 {
|
||||||
pass.Reportf(id.Pos(),
|
id, _ = stmt.Lhs[1].(*ast.Ident)
|
||||||
"the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
|
}
|
||||||
n.(*ast.SelectorExpr).Sel.Name)
|
}
|
||||||
} else if v, ok := pass.TypesInfo.Uses[id].(*types.Var); ok {
|
if id != nil {
|
||||||
cancelvars[v] = stmt
|
if id.Name == "_" {
|
||||||
} else if v, ok := pass.TypesInfo.Defs[id].(*types.Var); ok {
|
pass.Reportf(id.Pos(),
|
||||||
cancelvars[v] = stmt
|
"the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
|
||||||
}
|
n.(*ast.SelectorExpr).Sel.Name)
|
||||||
|
} else if v, ok := pass.TypesInfo.Uses[id].(*types.Var); ok {
|
||||||
|
cancelvars[v] = stmt
|
||||||
|
} else if v, ok := pass.TypesInfo.Defs[id].(*types.Var); ok {
|
||||||
|
cancelvars[v] = stmt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -179,18 +179,22 @@ func hasImport(pkg *types.Package, path string) bool {
|
||||||
// isContextWithCancel reports whether n is one of the qualified identifiers
|
// isContextWithCancel reports whether n is one of the qualified identifiers
|
||||||
// context.With{Cancel,Timeout,Deadline}.
|
// context.With{Cancel,Timeout,Deadline}.
|
||||||
func isContextWithCancel(info *types.Info, n ast.Node) bool {
|
func isContextWithCancel(info *types.Info, n ast.Node) bool {
|
||||||
if sel, ok := n.(*ast.SelectorExpr); ok {
|
sel, ok := n.(*ast.SelectorExpr)
|
||||||
switch sel.Sel.Name {
|
if !ok {
|
||||||
case "WithCancel", "WithTimeout", "WithDeadline":
|
return false
|
||||||
if x, ok := sel.X.(*ast.Ident); ok {
|
}
|
||||||
if pkgname, ok := info.Uses[x].(*types.PkgName); ok {
|
switch sel.Sel.Name {
|
||||||
return pkgname.Imported().Path() == contextPackage
|
case "WithCancel", "WithTimeout", "WithDeadline":
|
||||||
}
|
default:
|
||||||
// Import failed, so we can't check package path.
|
return false
|
||||||
// Just check the local package name (heuristic).
|
}
|
||||||
return x.Name == "context"
|
if x, ok := sel.X.(*ast.Ident); ok {
|
||||||
}
|
if pkgname, ok := info.Uses[x].(*types.PkgName); ok {
|
||||||
|
return pkgname.Imported().Path() == contextPackage
|
||||||
}
|
}
|
||||||
|
// Import failed, so we can't check package path.
|
||||||
|
// Just check the local package name (heuristic).
|
||||||
|
return x.Name == "context"
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -270,29 +274,30 @@ outer:
|
||||||
var search func(blocks []*cfg.Block) *ast.ReturnStmt
|
var search func(blocks []*cfg.Block) *ast.ReturnStmt
|
||||||
search = func(blocks []*cfg.Block) *ast.ReturnStmt {
|
search = func(blocks []*cfg.Block) *ast.ReturnStmt {
|
||||||
for _, b := range blocks {
|
for _, b := range blocks {
|
||||||
if !seen[b] {
|
if seen[b] {
|
||||||
seen[b] = true
|
continue
|
||||||
|
}
|
||||||
|
seen[b] = true
|
||||||
|
|
||||||
// Prune the search if the block uses v.
|
// Prune the search if the block uses v.
|
||||||
if blockUses(pass, v, b) {
|
if blockUses(pass, v, b) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found path to return statement?
|
// Found path to return statement?
|
||||||
if ret := b.Return(); ret != nil {
|
if ret := b.Return(); ret != nil {
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Printf("found path to return in block %s\n", b)
|
fmt.Printf("found path to return in block %s\n", b)
|
||||||
}
|
|
||||||
return ret // found
|
|
||||||
}
|
}
|
||||||
|
return ret // found
|
||||||
|
}
|
||||||
|
|
||||||
// Recur
|
// Recur
|
||||||
if ret := search(b.Succs); ret != nil {
|
if ret := search(b.Succs); ret != nil {
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Printf(" from block %s\n", b)
|
fmt.Printf(" from block %s\n", b)
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -62,28 +62,28 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
|
||||||
return isSafeUintptr(info, x.X)
|
return isSafeUintptr(info, x.X)
|
||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
switch x.Sel.Name {
|
if x.Sel.Name != "Data" {
|
||||||
case "Data":
|
break
|
||||||
// reflect.SliceHeader and reflect.StringHeader are okay,
|
}
|
||||||
// but only if they are pointing at a real slice or string.
|
// reflect.SliceHeader and reflect.StringHeader are okay,
|
||||||
// It's not okay to do:
|
// but only if they are pointing at a real slice or string.
|
||||||
// var x SliceHeader
|
// It's not okay to do:
|
||||||
// x.Data = uintptr(unsafe.Pointer(...))
|
// var x SliceHeader
|
||||||
// ... use x ...
|
// x.Data = uintptr(unsafe.Pointer(...))
|
||||||
// p := unsafe.Pointer(x.Data)
|
// ... use x ...
|
||||||
// because in the middle the garbage collector doesn't
|
// p := unsafe.Pointer(x.Data)
|
||||||
// see x.Data as a pointer and so x.Data may be dangling
|
// because in the middle the garbage collector doesn't
|
||||||
// by the time we get to the conversion at the end.
|
// see x.Data as a pointer and so x.Data may be dangling
|
||||||
// For now approximate by saying that *Header is okay
|
// by the time we get to the conversion at the end.
|
||||||
// but Header is not.
|
// For now approximate by saying that *Header is okay
|
||||||
pt, ok := info.Types[x.X].Type.(*types.Pointer)
|
// but Header is not.
|
||||||
if ok {
|
pt, ok := info.Types[x.X].Type.(*types.Pointer)
|
||||||
t, ok := pt.Elem().(*types.Named)
|
if ok {
|
||||||
if ok && t.Obj().Pkg().Path() == "reflect" {
|
t, ok := pt.Elem().(*types.Named)
|
||||||
switch t.Obj().Name() {
|
if ok && t.Obj().Pkg().Path() == "reflect" {
|
||||||
case "StringHeader", "SliceHeader":
|
switch t.Obj().Name() {
|
||||||
return true
|
case "StringHeader", "SliceHeader":
|
||||||
}
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue