diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-07-04 11:12:55 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-07-04 15:05:30 +0200 |
| commit | c7d7f10bdff703e4a3c0414e8a33d4e45c91eb35 (patch) | |
| tree | 0dff0ee1f98dbfa3ad8776112053a450d176592b /vendor/github.com/go-lintpack/lintpack/astwalk | |
| parent | 9573094ce235bd9afe88f5da27a47dd6bcc1e13b (diff) | |
go.mod: vendor golangci-lint
Diffstat (limited to 'vendor/github.com/go-lintpack/lintpack/astwalk')
14 files changed, 710 insertions, 0 deletions
diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/comment_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/comment_walker.go new file mode 100644 index 000000000..6c60e3fed --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/comment_walker.go @@ -0,0 +1,41 @@ +package astwalk + +import ( + "go/ast" + "strings" +) + +type commentWalker struct { + visitor CommentVisitor +} + +func (w *commentWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, cg := range f.Comments { + visitCommentGroups(cg, w.visitor.VisitComment) + } +} + +func visitCommentGroups(cg *ast.CommentGroup, visit func(*ast.CommentGroup)) { + var group []*ast.Comment + visitGroup := func(list []*ast.Comment) { + if len(list) == 0 { + return + } + cg := &ast.CommentGroup{List: list} + visit(cg) + } + for _, comment := range cg.List { + if strings.HasPrefix(comment.Text, "/*") { + visitGroup(group) + group = group[:0] + visitGroup([]*ast.Comment{comment}) + } else { + group = append(group, comment) + } + } + visitGroup(group) +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/doc_comment_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/doc_comment_walker.go new file mode 100644 index 000000000..39b536508 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/doc_comment_walker.go @@ -0,0 +1,48 @@ +package astwalk + +import ( + "go/ast" +) + +type docCommentWalker struct { + visitor DocCommentVisitor +} + +func (w *docCommentWalker) WalkFile(f *ast.File) { + for _, decl := range f.Decls { + switch decl := decl.(type) { + case *ast.FuncDecl: + if decl.Doc != nil { + w.visitor.VisitDocComment(decl.Doc) + } + case *ast.GenDecl: + if decl.Doc != nil { + w.visitor.VisitDocComment(decl.Doc) + } + for _, spec := range decl.Specs { + switch spec := spec.(type) { + case *ast.ImportSpec: + if spec.Doc != nil { + w.visitor.VisitDocComment(spec.Doc) + } + case *ast.ValueSpec: + if spec.Doc != nil { + w.visitor.VisitDocComment(spec.Doc) + } + case *ast.TypeSpec: + if spec.Doc != nil { + w.visitor.VisitDocComment(spec.Doc) + } + ast.Inspect(spec.Type, func(n ast.Node) bool { + if n, ok := n.(*ast.Field); ok { + if n.Doc != nil { + w.visitor.VisitDocComment(n.Doc) + } + } + return true + }) + } + } + } + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/expr_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/expr_walker.go new file mode 100644 index 000000000..64098b2b7 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/expr_walker.go @@ -0,0 +1,29 @@ +package astwalk + +import "go/ast" + +type exprWalker struct { + visitor ExprVisitor +} + +func (w *exprWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + if decl, ok := decl.(*ast.FuncDecl); ok { + if !w.visitor.EnterFunc(decl) { + continue + } + } + + ast.Inspect(decl, func(x ast.Node) bool { + if x, ok := x.(ast.Expr); ok { + w.visitor.VisitExpr(x) + return !w.visitor.skipChilds() + } + return true + }) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/func_decl_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/func_decl_walker.go new file mode 100644 index 000000000..90d921f6f --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/func_decl_walker.go @@ -0,0 +1,21 @@ +package astwalk + +import "go/ast" + +type funcDeclWalker struct { + visitor FuncDeclVisitor +} + +func (w *funcDeclWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + w.visitor.VisitFuncDecl(decl) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/local_comment_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/local_comment_walker.go new file mode 100644 index 000000000..e042f0d5e --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/local_comment_walker.go @@ -0,0 +1,32 @@ +package astwalk + +import ( + "go/ast" +) + +type localCommentWalker struct { + visitor LocalCommentVisitor +} + +func (w *localCommentWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + + for _, cg := range f.Comments { + // Not sure that decls/comments are sorted + // by positions, so do a naive full scan for now. + if cg.Pos() < decl.Pos() || cg.Pos() > decl.End() { + continue + } + + visitCommentGroups(cg, w.visitor.VisitLocalComment) + } + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_visitor.go b/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_visitor.go new file mode 100644 index 000000000..bed0f44ab --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_visitor.go @@ -0,0 +1,51 @@ +package astwalk + +import ( + "go/ast" +) + +// LocalDefVisitor visits every name definitions inside a function. +// +// Next elements are considered as name definitions: +// - Function parameters (input, output, receiver) +// - Every LHS of ":=" assignment that defines a new name +// - Every local var/const declaration. +// +// NOTE: this visitor is experimental. +// This is also why it lives in a separate file. +type LocalDefVisitor interface { + walkerEvents + VisitLocalDef(Name, ast.Expr) +} + +type ( + // NameKind describes what kind of name Name object holds. + NameKind int + + // Name holds ver/const/param definition symbol info. + Name struct { + ID *ast.Ident + Kind NameKind + + // Index is NameVar-specific field that is used to + // specify nth tuple element being assigned to the name. + Index int + } +) + +// NOTE: set of name kinds is not stable and may change over time. +// +// TODO(quasilyte): is NameRecv/NameParam/NameResult granularity desired? +// TODO(quasilyte): is NameVar/NameBind (var vs :=) granularity desired? +const ( + // NameParam is function/method receiver/input/output name. + // Initializing expression is always nil. + NameParam NameKind = iota + // NameVar is var or ":=" declared name. + // Initizlizing expression may be nil for var-declared names + // without explicit initializing expression. + NameVar + // NameConst is const-declared name. + // Initializing expression is never nil. + NameConst +) diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_walker.go new file mode 100644 index 000000000..f6808cbb4 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/local_def_walker.go @@ -0,0 +1,118 @@ +package astwalk + +import ( + "go/ast" + "go/token" + "go/types" +) + +type localDefWalker struct { + visitor LocalDefVisitor + info *types.Info +} + +func (w *localDefWalker) WalkFile(f *ast.File) { + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + w.walkFunc(decl) + } +} + +func (w *localDefWalker) walkFunc(decl *ast.FuncDecl) { + w.walkSignature(decl) + w.walkFuncBody(decl) +} + +func (w *localDefWalker) walkFuncBody(decl *ast.FuncDecl) { + ast.Inspect(decl.Body, func(x ast.Node) bool { + switch x := x.(type) { + case *ast.AssignStmt: + if x.Tok != token.DEFINE { + return false + } + if len(x.Lhs) != len(x.Rhs) { + // Multi-value assignment. + // Invariant: there is only 1 RHS. + for i, lhs := range x.Lhs { + id, ok := lhs.(*ast.Ident) + if !ok || w.info.Defs[id] == nil { + continue + } + def := Name{ID: id, Kind: NameVar, Index: i} + w.visitor.VisitLocalDef(def, x.Rhs[0]) + } + } else { + // Simple 1-1 assignments. + for i, lhs := range x.Lhs { + id, ok := lhs.(*ast.Ident) + if !ok || w.info.Defs[id] == nil { + continue + } + def := Name{ID: id, Kind: NameVar} + w.visitor.VisitLocalDef(def, x.Rhs[i]) + } + } + return false + + case *ast.GenDecl: + // Decls always introduce new names. + for _, spec := range x.Specs { + spec, ok := spec.(*ast.ValueSpec) + if !ok { // Ignore type/import specs + return false + } + switch { + case len(spec.Values) == 0: + // var-specific decls without explicit init. + for _, id := range spec.Names { + def := Name{ID: id, Kind: NameVar} + w.visitor.VisitLocalDef(def, nil) + } + case len(spec.Names) != len(spec.Values): + // var-specific decls that assign tuple results. + for i, id := range spec.Names { + def := Name{ID: id, Kind: NameVar, Index: i} + w.visitor.VisitLocalDef(def, spec.Values[0]) + } + default: + // Can be either var or const decl. + kind := NameVar + if x.Tok == token.CONST { + kind = NameConst + } + for i, id := range spec.Names { + def := Name{ID: id, Kind: kind} + w.visitor.VisitLocalDef(def, spec.Values[i]) + } + } + } + return false + } + + return true + }) +} + +func (w *localDefWalker) walkSignature(decl *ast.FuncDecl) { + for _, p := range decl.Type.Params.List { + for _, id := range p.Names { + def := Name{ID: id, Kind: NameParam} + w.visitor.VisitLocalDef(def, nil) + } + } + if decl.Type.Results != nil { + for _, p := range decl.Type.Results.List { + for _, id := range p.Names { + def := Name{ID: id, Kind: NameParam} + w.visitor.VisitLocalDef(def, nil) + } + } + } + if decl.Recv != nil && len(decl.Recv.List[0].Names) != 0 { + def := Name{ID: decl.Recv.List[0].Names[0], Kind: NameParam} + w.visitor.VisitLocalDef(def, nil) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/local_expr_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/local_expr_walker.go new file mode 100644 index 000000000..951fd97e5 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/local_expr_walker.go @@ -0,0 +1,27 @@ +package astwalk + +import "go/ast" + +type localExprWalker struct { + visitor LocalExprVisitor +} + +func (w *localExprWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + ast.Inspect(decl.Body, func(x ast.Node) bool { + if x, ok := x.(ast.Expr); ok { + w.visitor.VisitLocalExpr(x) + return !w.visitor.skipChilds() + } + return true + }) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_list_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_list_walker.go new file mode 100644 index 000000000..1cc0493a4 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_list_walker.go @@ -0,0 +1,31 @@ +package astwalk + +import "go/ast" + +type stmtListWalker struct { + visitor StmtListVisitor +} + +func (w *stmtListWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + ast.Inspect(decl.Body, func(x ast.Node) bool { + switch x := x.(type) { + case *ast.BlockStmt: + w.visitor.VisitStmtList(x.List) + case *ast.CaseClause: + w.visitor.VisitStmtList(x.Body) + case *ast.CommClause: + w.visitor.VisitStmtList(x.Body) + } + return !w.visitor.skipChilds() + }) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_walker.go new file mode 100644 index 000000000..722eeb116 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/stmt_walker.go @@ -0,0 +1,27 @@ +package astwalk + +import "go/ast" + +type stmtWalker struct { + visitor StmtVisitor +} + +func (w *stmtWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + decl, ok := decl.(*ast.FuncDecl) + if !ok || !w.visitor.EnterFunc(decl) { + continue + } + ast.Inspect(decl.Body, func(x ast.Node) bool { + if x, ok := x.(ast.Stmt); ok { + w.visitor.VisitStmt(x) + return !w.visitor.skipChilds() + } + return true + }) + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/type_expr_walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/type_expr_walker.go new file mode 100644 index 000000000..24c150084 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/type_expr_walker.go @@ -0,0 +1,114 @@ +package astwalk + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/go-toolsmith/astp" + "github.com/go-toolsmith/typep" +) + +type typeExprWalker struct { + visitor TypeExprVisitor + info *types.Info +} + +func (w *typeExprWalker) WalkFile(f *ast.File) { + if !w.visitor.EnterFile(f) { + return + } + + for _, decl := range f.Decls { + if decl, ok := decl.(*ast.FuncDecl); ok { + if !w.visitor.EnterFunc(decl) { + continue + } + } + switch decl := decl.(type) { + case *ast.FuncDecl: + if !w.visitor.EnterFunc(decl) { + continue + } + w.walkSignature(decl.Type) + ast.Inspect(decl.Body, w.walk) + case *ast.GenDecl: + if decl.Tok == token.IMPORT { + continue + } + ast.Inspect(decl, w.walk) + } + } +} + +func (w *typeExprWalker) visit(x ast.Expr) bool { + w.visitor.VisitTypeExpr(x) + return !w.visitor.skipChilds() +} + +func (w *typeExprWalker) walk(x ast.Node) bool { + switch x := x.(type) { + case *ast.ParenExpr: + if typep.IsTypeExpr(w.info, x.X) { + return w.visit(x) + } + return true + case *ast.CallExpr: + // Pointer conversions require parenthesis around pointer type. + // These casts are represented as call expressions. + // Because it's impossible for the visitor to distinguish such + // "required" parenthesis, walker skips outmost parenthesis in such cases. + return w.inspectInner(x.Fun) + case *ast.SelectorExpr: + // Like with conversions, method expressions are another special. + return w.inspectInner(x.X) + case *ast.StarExpr: + if typep.IsTypeExpr(w.info, x.X) { + return w.visit(x) + } + return true + case *ast.MapType: + return w.visit(x) + case *ast.FuncType: + return w.visit(x) + case *ast.StructType: + return w.visit(x) + case *ast.InterfaceType: + if !w.visit(x) { + return false + } + for _, method := range x.Methods.List { + switch x := method.Type.(type) { + case *ast.FuncType: + w.walkSignature(x) + default: + // Embedded interface. + w.walk(x) + } + } + return false + case *ast.ArrayType: + return w.visit(x) + } + return true +} + +func (w *typeExprWalker) inspectInner(x ast.Expr) bool { + parens, ok := x.(*ast.ParenExpr) + if ok && typep.IsTypeExpr(w.info, parens.X) && astp.IsStarExpr(parens.X) { + ast.Inspect(parens.X, w.walk) + return false + } + return true +} + +func (w *typeExprWalker) walkSignature(typ *ast.FuncType) { + for _, p := range typ.Params.List { + ast.Inspect(p.Type, w.walk) + } + if typ.Results != nil { + for _, p := range typ.Results.List { + ast.Inspect(p.Type, w.walk) + } + } +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/visitor.go b/vendor/github.com/go-lintpack/lintpack/astwalk/visitor.go new file mode 100644 index 000000000..9f973a2b3 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/visitor.go @@ -0,0 +1,80 @@ +package astwalk + +import ( + "go/ast" +) + +// Visitor interfaces. +type ( + // DocCommentVisitor visits every doc-comment. + // Does not visit doc-comments for function-local definitions (types, etc). + // Also does not visit package doc-comment (file-level doc-comments). + DocCommentVisitor interface { + VisitDocComment(*ast.CommentGroup) + } + + // FuncDeclVisitor visits every top-level function declaration. + FuncDeclVisitor interface { + walkerEvents + VisitFuncDecl(*ast.FuncDecl) + } + + // ExprVisitor visits every expression inside AST file. + ExprVisitor interface { + walkerEvents + VisitExpr(ast.Expr) + } + + // LocalExprVisitor visits every expression inside function body. + LocalExprVisitor interface { + walkerEvents + VisitLocalExpr(ast.Expr) + } + + // StmtListVisitor visits every statement list inside function body. + // This includes block statement bodies as well as implicit blocks + // introduced by case clauses and alike. + StmtListVisitor interface { + walkerEvents + VisitStmtList([]ast.Stmt) + } + + // StmtVisitor visits every statement inside function body. + StmtVisitor interface { + walkerEvents + VisitStmt(ast.Stmt) + } + + // TypeExprVisitor visits every type describing expression. + // It also traverses struct types and interface types to run + // checker over their fields/method signatures. + TypeExprVisitor interface { + walkerEvents + VisitTypeExpr(ast.Expr) + } + + // LocalCommentVisitor visits every comment inside function body. + LocalCommentVisitor interface { + walkerEvents + VisitLocalComment(*ast.CommentGroup) + } + + // CommentVisitor visits every comment. + CommentVisitor interface { + walkerEvents + VisitComment(*ast.CommentGroup) + } +) + +// walkerEvents describes common hooks available for most visitor types. +type walkerEvents interface { + // EnterFile is called for every file that is about to be traversed. + // If false is returned, file is not visited. + EnterFile(*ast.File) bool + + // EnterFunc is called for every function declaration that is about + // to be traversed. If false is returned, function is not visited. + EnterFunc(*ast.FuncDecl) bool + + skipChilds() bool +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/walk_handler.go b/vendor/github.com/go-lintpack/lintpack/astwalk/walk_handler.go new file mode 100644 index 000000000..1f6e948d5 --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/walk_handler.go @@ -0,0 +1,34 @@ +package astwalk + +import ( + "go/ast" +) + +// WalkHandler is a type to be embedded into every checker +// that uses astwalk walkers. +type WalkHandler struct { + // SkipChilds controls whether currently analyzed + // node childs should be traversed. + // + // Value is reset after each visitor invocation, + // so there is no need to set value back to false. + SkipChilds bool +} + +// EnterFile is a default walkerEvents.EnterFile implementation +// that reports every file as accepted candidate for checking. +func (w *WalkHandler) EnterFile(f *ast.File) bool { + return true +} + +// EnterFunc is a default walkerEvents.EnterFunc implementation +// that skips extern function (ones that do not have body). +func (w *WalkHandler) EnterFunc(decl *ast.FuncDecl) bool { + return decl.Body != nil +} + +func (w *WalkHandler) skipChilds() bool { + v := w.SkipChilds + w.SkipChilds = false + return v +} diff --git a/vendor/github.com/go-lintpack/lintpack/astwalk/walker.go b/vendor/github.com/go-lintpack/lintpack/astwalk/walker.go new file mode 100644 index 000000000..fddae710a --- /dev/null +++ b/vendor/github.com/go-lintpack/lintpack/astwalk/walker.go @@ -0,0 +1,57 @@ +package astwalk + +import ( + "go/types" + + "github.com/go-lintpack/lintpack" +) + +// WalkerForFuncDecl returns file walker implementation for FuncDeclVisitor. +func WalkerForFuncDecl(v FuncDeclVisitor) lintpack.FileWalker { + return &funcDeclWalker{visitor: v} +} + +// WalkerForExpr returns file walker implementation for ExprVisitor. +func WalkerForExpr(v ExprVisitor) lintpack.FileWalker { + return &exprWalker{visitor: v} +} + +// WalkerForLocalExpr returns file walker implementation for LocalExprVisitor. +func WalkerForLocalExpr(v LocalExprVisitor) lintpack.FileWalker { + return &localExprWalker{visitor: v} +} + +// WalkerForStmtList returns file walker implementation for StmtListVisitor. +func WalkerForStmtList(v StmtListVisitor) lintpack.FileWalker { + return &stmtListWalker{visitor: v} +} + +// WalkerForStmt returns file walker implementation for StmtVisitor. +func WalkerForStmt(v StmtVisitor) lintpack.FileWalker { + return &stmtWalker{visitor: v} +} + +// WalkerForTypeExpr returns file walker implementation for TypeExprVisitor. +func WalkerForTypeExpr(v TypeExprVisitor, info *types.Info) lintpack.FileWalker { + return &typeExprWalker{visitor: v, info: info} +} + +// WalkerForLocalComment returns file walker implementation for LocalCommentVisitor. +func WalkerForLocalComment(v LocalCommentVisitor) lintpack.FileWalker { + return &localCommentWalker{visitor: v} +} + +// WalkerForComment returns file walker implementation for CommentVisitor. +func WalkerForComment(v CommentVisitor) lintpack.FileWalker { + return &commentWalker{visitor: v} +} + +// WalkerForDocComment returns file walker implementation for DocCommentVisitor. +func WalkerForDocComment(v DocCommentVisitor) lintpack.FileWalker { + return &docCommentWalker{visitor: v} +} + +// WalkerForLocalDef returns file walker implementation for LocalDefVisitor. +func WalkerForLocalDef(v LocalDefVisitor, info *types.Info) lintpack.FileWalker { + return &localDefWalker{visitor: v, info: info} +} |
