This repository has been archived by the owner on Dec 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
typeUnparen_checker.go
85 lines (75 loc) · 2.24 KB
/
typeUnparen_checker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package checkers
import (
"go/ast"
"github.com/go-lintpack/lintpack"
"github.com/go-lintpack/lintpack/astwalk"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astp"
"golang.org/x/tools/go/ast/astutil"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "typeUnparen"
info.Tags = []string{"style", "opinionated"}
info.Summary = "Detects unneded parenthesis inside type expressions and suggests to remove them"
info.Before = `type foo [](func([](func())))`
info.After = `type foo []func([]func())`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return astwalk.WalkerForTypeExpr(&typeUnparenChecker{ctx: ctx}, ctx.TypesInfo)
})
}
type typeUnparenChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
}
func (c *typeUnparenChecker) VisitTypeExpr(x ast.Expr) {
switch x := x.(type) {
case *ast.ParenExpr:
switch x.X.(type) {
case *ast.StructType:
c.ctx.Warn(x, "could simplify (struct{...}) to struct{...}")
case *ast.InterfaceType:
c.ctx.Warn(x, "could simplify (interface{...}) to interface{...}")
default:
c.warn(x, c.unparenExpr(astcopy.Expr(x)))
}
default:
c.checkTypeExpr(x)
}
}
func (c *typeUnparenChecker) checkTypeExpr(x ast.Expr) {
switch x := x.(type) {
case *ast.ArrayType:
// Arrays require extra care: we don't want to unparen
// length expression as they are not type expressions.
if !c.hasParens(x.Elt) {
return
}
noParens := astcopy.ArrayType(x)
noParens.Elt = c.unparenExpr(noParens.Elt)
c.warn(x, noParens)
case *ast.StructType, *ast.InterfaceType:
// Only nested fields are to be reported.
default:
if !c.hasParens(x) {
return
}
c.warn(x, c.unparenExpr(astcopy.Expr(x)))
}
}
func (c *typeUnparenChecker) hasParens(x ast.Expr) bool {
return containsNode(x, astp.IsParenExpr)
}
func (c *typeUnparenChecker) unparenExpr(x ast.Expr) ast.Expr {
// Replace every paren expr with expression it encloses.
return astutil.Apply(x, nil, func(cur *astutil.Cursor) bool {
if paren, ok := cur.Node().(*ast.ParenExpr); ok {
cur.Replace(paren.X)
}
return true
}).(ast.Expr)
}
func (c *typeUnparenChecker) warn(cause, noParens ast.Expr) {
c.SkipChilds = true
c.ctx.Warn(cause, "could simplify %s to %s", cause, noParens)
}