diff options
Diffstat (limited to 'vendor/github.com/golangci/prealloc/prealloc.go')
| -rw-r--r-- | vendor/github.com/golangci/prealloc/prealloc.go | 403 |
1 files changed, 0 insertions, 403 deletions
diff --git a/vendor/github.com/golangci/prealloc/prealloc.go b/vendor/github.com/golangci/prealloc/prealloc.go deleted file mode 100644 index 1235ad363..000000000 --- a/vendor/github.com/golangci/prealloc/prealloc.go +++ /dev/null @@ -1,403 +0,0 @@ -package prealloc - -import ( - "errors" - "flag" - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - "log" - "os" - "path/filepath" - "strings" -) - -// Support: (in order of priority) -// * Full make suggestion with type? -// * Test flag -// * Embedded ifs? -// * Use an import rather than the duplcated import.go - -const ( - pwd = "./" -) - -func usage() { - log.Printf("Usage of %s:\n", os.Args[0]) - log.Printf("\nprealloc [flags] # runs on package in current directory\n") - log.Printf("\nprealloc [flags] [packages]\n") - log.Printf("Flags:\n") - flag.PrintDefaults() -} - -type sliceDeclaration struct { - name string - // sType string - genD *ast.GenDecl -} - -type returnsVisitor struct { - // flags - simple bool - includeRangeLoops bool - includeForLoops bool - // visitor fields - sliceDeclarations []*sliceDeclaration - preallocHints []Hint - returnsInsideOfLoop bool - arrayTypes []string -} - -func NoMain() { - - // Remove log timestamp - log.SetFlags(0) - - simple := flag.Bool("simple", true, "Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them") - includeRangeLoops := flag.Bool("rangeloops", true, "Report preallocation suggestions on range loops") - includeForLoops := flag.Bool("forloops", false, "Report preallocation suggestions on for loops") - setExitStatus := flag.Bool("set_exit_status", false, "Set exit status to 1 if any issues are found") - flag.Usage = usage - flag.Parse() - - hints, err := checkForPreallocations(flag.Args(), simple, includeRangeLoops, includeForLoops) - if err != nil { - log.Println(err) - } - - for _, hint := range hints { - log.Println(hint) - } - if *setExitStatus && len(hints) > 0 { - os.Exit(1) - } -} - -func checkForPreallocations(args []string, simple, includeRangeLoops *bool, includeForLoops *bool) ([]Hint, error) { - - fset := token.NewFileSet() - - files, err := parseInput(args, fset) - if err != nil { - return nil, fmt.Errorf("could not parse input %v", err) - } - - if simple == nil { - return nil, errors.New("simple nil") - } - - if includeRangeLoops == nil { - return nil, errors.New("includeRangeLoops nil") - } - - if includeForLoops == nil { - return nil, errors.New("includeForLoops nil") - } - - hints := []Hint{} - for _, f := range files { - retVis := &returnsVisitor{ - simple: *simple, - includeRangeLoops: *includeRangeLoops, - includeForLoops: *includeForLoops, - } - ast.Walk(retVis, f) - // if simple is true, then we actually have to check if we had returns - // inside of our loop. Otherwise, we can just report all messages. - if !retVis.simple || !retVis.returnsInsideOfLoop { - hints = append(hints, retVis.preallocHints...) - } - } - - return hints, nil -} - -func Check(files []*ast.File, simple, includeRangeLoops, includeForLoops bool) []Hint { - hints := []Hint{} - for _, f := range files { - retVis := &returnsVisitor{ - simple: simple, - includeRangeLoops: includeRangeLoops, - includeForLoops: includeForLoops, - } - ast.Walk(retVis, f) - - // if simple is true, then we actually have to check if we had returns - // inside of our loop. Otherwise, we can just report all messages. - if !retVis.simple || !retVis.returnsInsideOfLoop { - hints = append(hints, retVis.preallocHints...) - } - } - - return hints -} - -func parseInput(args []string, fset *token.FileSet) ([]*ast.File, error) { - var directoryList []string - var fileMode bool - files := make([]*ast.File, 0) - - if len(args) == 0 { - directoryList = append(directoryList, pwd) - } else { - for _, arg := range args { - if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) { - - for _, dirname := range allPackagesInFS(arg) { - directoryList = append(directoryList, dirname) - } - - } else if isDir(arg) { - directoryList = append(directoryList, arg) - - } else if exists(arg) { - if strings.HasSuffix(arg, ".go") { - fileMode = true - f, err := parser.ParseFile(fset, arg, nil, 0) - if err != nil { - return nil, err - } - files = append(files, f) - } else { - return nil, fmt.Errorf("invalid file %v specified", arg) - } - } else { - - //TODO clean this up a bit - imPaths := importPaths([]string{arg}) - for _, importPath := range imPaths { - pkg, err := build.Import(importPath, ".", 0) - if err != nil { - return nil, err - } - var stringFiles []string - stringFiles = append(stringFiles, pkg.GoFiles...) - // files = append(files, pkg.CgoFiles...) - stringFiles = append(stringFiles, pkg.TestGoFiles...) - if pkg.Dir != "." { - for i, f := range stringFiles { - stringFiles[i] = filepath.Join(pkg.Dir, f) - } - } - - fileMode = true - for _, stringFile := range stringFiles { - f, err := parser.ParseFile(fset, stringFile, nil, 0) - if err != nil { - return nil, err - } - files = append(files, f) - } - - } - } - } - } - - // if we're not in file mode, then we need to grab each and every package in each directory - // we can to grab all the files - if !fileMode { - for _, fpath := range directoryList { - pkgs, err := parser.ParseDir(fset, fpath, nil, 0) - if err != nil { - return nil, err - } - - for _, pkg := range pkgs { - for _, f := range pkg.Files { - files = append(files, f) - } - } - } - } - - return files, nil -} - -func isDir(filename string) bool { - fi, err := os.Stat(filename) - return err == nil && fi.IsDir() -} - -func exists(filename string) bool { - _, err := os.Stat(filename) - return err == nil -} - -func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - - return false -} - -func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor { - - v.sliceDeclarations = nil - v.returnsInsideOfLoop = false - - switch n := node.(type) { - case *ast.TypeSpec: - if _, ok := n.Type.(*ast.ArrayType); ok { - if n.Name != nil { - v.arrayTypes = append(v.arrayTypes, n.Name.Name) - } - } - case *ast.FuncDecl: - if n.Body != nil { - for _, stmt := range n.Body.List { - switch s := stmt.(type) { - // Find non pre-allocated slices - case *ast.DeclStmt: - genD, ok := s.Decl.(*ast.GenDecl) - if !ok { - continue - } - if genD.Tok == token.TYPE { - for _, spec := range genD.Specs { - tSpec, ok := spec.(*ast.TypeSpec) - if !ok { - continue - } - - if _, ok := tSpec.Type.(*ast.ArrayType); ok { - if tSpec.Name != nil { - v.arrayTypes = append(v.arrayTypes, tSpec.Name.Name) - } - } - } - } else if genD.Tok == token.VAR { - for _, spec := range genD.Specs { - vSpec, ok := spec.(*ast.ValueSpec) - if !ok { - continue - } - var isArrType bool - switch val := vSpec.Type.(type) { - case *ast.ArrayType: - isArrType = true - case *ast.Ident: - isArrType = contains(v.arrayTypes, val.Name) - } - if isArrType { - if vSpec.Names != nil { - /*atID, ok := arrayType.Elt.(*ast.Ident) - if !ok { - continue - }*/ - - // We should handle multiple slices declared on same line e.g. var mySlice1, mySlice2 []uint32 - for _, vName := range vSpec.Names { - v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: vName.Name /*sType: atID.Name,*/, genD: genD}) - } - } - } - } - } - - case *ast.RangeStmt: - if v.includeRangeLoops { - if len(v.sliceDeclarations) == 0 { - continue - } - if s.Body != nil { - v.handleLoops(s.Body) - } - } - - case *ast.ForStmt: - if v.includeForLoops { - if len(v.sliceDeclarations) == 0 { - continue - } - if s.Body != nil { - v.handleLoops(s.Body) - } - } - - default: - } - } - } - } - return v -} - -// handleLoops is a helper function to share the logic required for both *ast.RangeLoops and *ast.ForLoops -func (v *returnsVisitor) handleLoops(blockStmt *ast.BlockStmt) { - - for _, stmt := range blockStmt.List { - switch bodyStmt := stmt.(type) { - case *ast.AssignStmt: - asgnStmt := bodyStmt - for _, expr := range asgnStmt.Rhs { - callExpr, ok := expr.(*ast.CallExpr) - if !ok { - continue // should this be break? comes back to multi-call support I think - } - ident, ok := callExpr.Fun.(*ast.Ident) - if !ok { - continue - } - if ident.Name == "append" { - // see if this append is appending the slice we found - for _, lhsExpr := range asgnStmt.Lhs { - lhsIdent, ok := lhsExpr.(*ast.Ident) - if !ok { - continue - } - for _, sliceDecl := range v.sliceDeclarations { - if sliceDecl.name == lhsIdent.Name { - // This is a potential mark, we just need to make sure there are no returns/continues in the - // range loop. - // now we just need to grab whatever we're ranging over - /*sxIdent, ok := s.X.(*ast.Ident) - if !ok { - continue - }*/ - - v.preallocHints = append(v.preallocHints, Hint{ - Pos: sliceDecl.genD.Pos(), - DeclaredSliceName: sliceDecl.name, - }) - } - } - } - - } - } - case *ast.IfStmt: - ifStmt := bodyStmt - if ifStmt.Body != nil { - for _, ifBodyStmt := range ifStmt.Body.List { - // TODO should probably handle embedded ifs here - switch /*ift :=*/ ifBodyStmt.(type) { - case *ast.BranchStmt, *ast.ReturnStmt: - v.returnsInsideOfLoop = true - default: - } - } - } - - default: - - } - } - -} - -// Hint stores the information about an occurence of a slice that could be -// preallocated. -type Hint struct { - Pos token.Pos - DeclaredSliceName string -} - -func (h Hint) String() string { - return fmt.Sprintf("%v: Consider preallocating %v", h.Pos, h.DeclaredSliceName) -} |
