Created
August 11, 2013 08:40
-
-
Save zephyrtronium/6204018 to your computer and use it in GitHub Desktop.
go run scnt.go packages...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "go/ast" | |
| "go/build" | |
| "go/parser" | |
| "go/token" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| ) | |
| type visitor struct { | |
| stmts, decls int | |
| comments int | |
| bs, be, bd int | |
| es int | |
| } | |
| func (v *visitor) Visit(node ast.Node) ast.Visitor { | |
| switch node.(type) { | |
| case *ast.BadStmt: | |
| v.bs++ | |
| return nil | |
| case *ast.BadExpr: | |
| v.be++ | |
| return nil | |
| case *ast.BadDecl: | |
| v.bd++ | |
| return nil | |
| case *ast.EmptyStmt: | |
| v.es++ | |
| return nil | |
| case *ast.ExprStmt, *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, | |
| *ast.GoStmt, *ast.DeferStmt, *ast.ReturnStmt, *ast.BranchStmt, | |
| *ast.IfStmt, *ast.CaseClause, *ast.SwitchStmt, *ast.TypeSwitchStmt, | |
| *ast.CommClause, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt: | |
| v.stmts++ | |
| case *ast.ImportSpec, *ast.ValueSpec, *ast.TypeSpec, *ast.FuncDecl: | |
| v.decls++ | |
| case *ast.CommentGroup: | |
| v.comments++ | |
| return nil | |
| } | |
| return v | |
| } | |
| func filter(fi os.FileInfo) bool { | |
| s := fi.Name() | |
| return len(s) > 3 && strings.EqualFold(s[len(s)-3:], ".go") | |
| } | |
| const sep = string(filepath.Separator) | |
| func walker(base string, trim int, args *[]string) filepath.WalkFunc { | |
| return func(path string, info os.FileInfo, err error) error { | |
| if info.IsDir() { | |
| if len(path) == len(base) { | |
| return nil | |
| } | |
| if len(path) > trim { | |
| path = path[trim:] | |
| } | |
| for _, part := range strings.Split(path, sep) { | |
| if strings.HasPrefix(part, ".") || strings.HasPrefix(part, "_") { | |
| return nil | |
| } | |
| } | |
| if err != nil { | |
| return filepath.SkipDir | |
| } | |
| *args = append(*args, path) | |
| } | |
| return nil | |
| } | |
| } | |
| func main() { | |
| args := os.Args[1:] | |
| for i, dir := range args { | |
| if dir == "..." { | |
| // all packages | |
| args = args[:0] | |
| base := filepath.Join(build.Default.GOROOT, "src", "pkg") | |
| filepath.Walk(base, walker(base, len(base)+len(sep), &args)) | |
| for _, gopath := range filepath.SplitList(build.Default.GOPATH) { | |
| base := filepath.Join(gopath, "src") | |
| filepath.Walk(base, walker(base, len(base)+len(sep), &args)) | |
| } | |
| } else if filepath.Base(dir) == "..." { | |
| copy(args[i:], args[i+1:]) | |
| args = args[:len(args)-1] | |
| pkg, err := build.Import(filepath.Dir(dir), ".", build.FindOnly) | |
| if err != nil { | |
| panic(err) | |
| } | |
| base := pkg.Dir | |
| filepath.Walk(base, walker(base, len(pkg.Root)+5, &args)) | |
| } | |
| } | |
| for _, dir := range args { | |
| path, err := build.Import(dir, ".", build.FindOnly) | |
| if err != nil { | |
| panic(err) | |
| } | |
| pkgs, err := parser.ParseDir(token.NewFileSet(), path.Dir, filter, parser.ParseComments|parser.AllErrors) | |
| if err != nil { | |
| fmt.Println(err) | |
| if len(pkgs) == 0 { | |
| fmt.Println("") | |
| } | |
| } | |
| for pkg, nn := range pkgs { | |
| if !strings.HasSuffix(dir, pkg) { | |
| fmt.Println(filepath.ToSlash(dir), "("+pkg+"):") | |
| } else { | |
| fmt.Println(filepath.ToSlash(dir) + ":") | |
| } | |
| v := visitor{} | |
| ast.Walk(&v, nn) | |
| fmt.Printf("%d statements, %d decls\n%d comments\n", v.stmts, v.decls, v.comments) | |
| if v.bs+v.be+v.bd > 0 { | |
| fmt.Printf("%d bad statements, %d bad expressions, %d bad decls\n", v.bs, v.be, v.bd) | |
| } | |
| if v.es > 0 { | |
| fmt.Printf("%d empty statements\n", v.es) | |
| } | |
| fmt.Println() | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment