parent
23861fa6a7
commit
5d484e2770
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Minio Client (C) 2014, 2015 Minio, Inc. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
fmt.Println(time.Now().UTC().Format(time.RFC3339Nano)) |
||||||
|
} |
@ -1,247 +0,0 @@ |
|||||||
package main |
|
||||||
|
|
||||||
import ( |
|
||||||
"flag" |
|
||||||
"fmt" |
|
||||||
"go/ast" |
|
||||||
"go/parser" |
|
||||||
"go/token" |
|
||||||
"os" |
|
||||||
"path/filepath" |
|
||||||
"sort" |
|
||||||
"strings" |
|
||||||
) |
|
||||||
|
|
||||||
var exitCode int |
|
||||||
var dirs []string |
|
||||||
|
|
||||||
func appendUniq(slice []string, i string) []string { |
|
||||||
for _, ele := range slice { |
|
||||||
if ele == i { |
|
||||||
return slice |
|
||||||
} |
|
||||||
} |
|
||||||
return append(slice, i) |
|
||||||
} |
|
||||||
|
|
||||||
// error formats the error to standard error, adding program
|
|
||||||
// identification and a newline
|
|
||||||
func errorf(format string, args ...interface{}) { |
|
||||||
fmt.Fprintf(os.Stderr, "verifier: "+format+"\n", args...) |
|
||||||
exitCode = 2 |
|
||||||
} |
|
||||||
|
|
||||||
type goPackage struct { |
|
||||||
p *ast.Package |
|
||||||
fs *token.FileSet |
|
||||||
decl map[string]ast.Node |
|
||||||
missingcomments map[string]ast.Node |
|
||||||
used map[string]bool |
|
||||||
} |
|
||||||
|
|
||||||
type usedWalker goPackage |
|
||||||
|
|
||||||
// Walks through the AST marking used identifiers.
|
|
||||||
func (p *usedWalker) Visit(node ast.Node) ast.Visitor { |
|
||||||
// just be stupid and mark all *ast.Ident
|
|
||||||
switch n := node.(type) { |
|
||||||
case *ast.Ident: |
|
||||||
p.used[n.Name] = true |
|
||||||
} |
|
||||||
return p |
|
||||||
} |
|
||||||
|
|
||||||
type report struct { |
|
||||||
pos token.Pos |
|
||||||
name string |
|
||||||
} |
|
||||||
type reports []report |
|
||||||
|
|
||||||
// Len
|
|
||||||
func (l reports) Len() int { return len(l) } |
|
||||||
|
|
||||||
// Less
|
|
||||||
func (l reports) Less(i, j int) bool { return l[i].pos < l[j].pos } |
|
||||||
|
|
||||||
// Swap
|
|
||||||
func (l reports) Swap(i, j int) { l[i], l[j] = l[j], l[i] } |
|
||||||
|
|
||||||
// Visits files for used nodes.
|
|
||||||
func (p *goPackage) Visit(node ast.Node) ast.Visitor { |
|
||||||
u := usedWalker(*p) // hopefully p fields are references.
|
|
||||||
switch n := node.(type) { |
|
||||||
// don't walk whole file, but only:
|
|
||||||
case *ast.ValueSpec: |
|
||||||
// - variable initializers
|
|
||||||
for _, value := range n.Values { |
|
||||||
ast.Walk(&u, value) |
|
||||||
} |
|
||||||
// variable types.
|
|
||||||
if n.Type != nil { |
|
||||||
ast.Walk(&u, n.Type) |
|
||||||
} |
|
||||||
case *ast.BlockStmt: |
|
||||||
// - function bodies
|
|
||||||
for _, stmt := range n.List { |
|
||||||
ast.Walk(&u, stmt) |
|
||||||
} |
|
||||||
case *ast.FuncDecl: |
|
||||||
// - function signatures
|
|
||||||
ast.Walk(&u, n.Type) |
|
||||||
case *ast.TypeSpec: |
|
||||||
// - type declarations
|
|
||||||
ast.Walk(&u, n.Type) |
|
||||||
} |
|
||||||
return p |
|
||||||
} |
|
||||||
|
|
||||||
func getAllMinioPkgs(path string, fl os.FileInfo, err error) error { |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
if fl.IsDir() { |
|
||||||
// Skip godeps
|
|
||||||
if strings.Contains(path, "Godeps") { |
|
||||||
return nil |
|
||||||
} |
|
||||||
dirs = appendUniq(dirs, path) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func doDir(name string) { |
|
||||||
notests := func(info os.FileInfo) bool { |
|
||||||
if !info.IsDir() && strings.HasSuffix(info.Name(), ".go") && |
|
||||||
!strings.HasSuffix(info.Name(), "_test.go") { |
|
||||||
return true |
|
||||||
} |
|
||||||
return false |
|
||||||
} |
|
||||||
fs := token.NewFileSet() |
|
||||||
pkgs, err := parser.ParseDir(fs, name, notests, parser.ParseComments|parser.Mode(0)) |
|
||||||
if err != nil { |
|
||||||
errorf("%s", err) |
|
||||||
return |
|
||||||
} |
|
||||||
for _, pkg := range pkgs { |
|
||||||
doPackage(fs, pkg) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func doDecl(p *goPackage, decl interface{}, cmap ast.CommentMap) bool { |
|
||||||
switch n := decl.(type) { |
|
||||||
case *ast.GenDecl: |
|
||||||
// var, const, types
|
|
||||||
for _, spec := range n.Specs { |
|
||||||
switch s := spec.(type) { |
|
||||||
case *ast.ValueSpec: |
|
||||||
// constants and variables.
|
|
||||||
for _, name := range s.Names { |
|
||||||
p.decl[name.Name] = n |
|
||||||
} |
|
||||||
case *ast.TypeSpec: |
|
||||||
// type definitions.
|
|
||||||
p.decl[s.Name.Name] = n |
|
||||||
} |
|
||||||
} |
|
||||||
case *ast.FuncDecl: |
|
||||||
// if function is 'main', never check
|
|
||||||
if n.Name.Name == "main" { |
|
||||||
return true |
|
||||||
} |
|
||||||
// Do not be strict on non-exported functions
|
|
||||||
if !ast.IsExported(n.Name.Name) { |
|
||||||
return true |
|
||||||
} |
|
||||||
// Do not be strict for field list functions
|
|
||||||
// if n.Recv != nil {
|
|
||||||
// continue
|
|
||||||
//}
|
|
||||||
// Be strict for global functions
|
|
||||||
_, ok := cmap[n] |
|
||||||
if ok == false { |
|
||||||
p.missingcomments[n.Name.Name] = n |
|
||||||
} |
|
||||||
|
|
||||||
// function declarations
|
|
||||||
// TODO(remy): do methods
|
|
||||||
if n.Recv == nil { |
|
||||||
p.decl[n.Name.Name] = n |
|
||||||
} |
|
||||||
} |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
func doPackage(fs *token.FileSet, pkg *ast.Package) { |
|
||||||
p := &goPackage{ |
|
||||||
p: pkg, |
|
||||||
fs: fs, |
|
||||||
decl: make(map[string]ast.Node), |
|
||||||
missingcomments: make(map[string]ast.Node), |
|
||||||
used: make(map[string]bool), |
|
||||||
} |
|
||||||
for _, file := range pkg.Files { |
|
||||||
cmap := ast.NewCommentMap(fs, file, file.Comments) |
|
||||||
for _, decl := range file.Decls { |
|
||||||
if doDecl(p, decl, cmap) { |
|
||||||
continue |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
// init() is always used
|
|
||||||
p.used["init"] = true |
|
||||||
if pkg.Name != "main" { |
|
||||||
// exported names are marked used for non-main packages.
|
|
||||||
for name := range p.decl { |
|
||||||
if ast.IsExported(name) { |
|
||||||
p.used[name] = true |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
// in main programs, main() is called.
|
|
||||||
p.used["main"] = true |
|
||||||
} |
|
||||||
for _, file := range pkg.Files { |
|
||||||
// walk file looking for used nodes.
|
|
||||||
ast.Walk(p, file) |
|
||||||
} |
|
||||||
|
|
||||||
// reports.
|
|
||||||
reports := reports(nil) |
|
||||||
for name, node := range p.decl { |
|
||||||
if !p.used[name] { |
|
||||||
reports = append(reports, report{node.Pos(), name}) |
|
||||||
} |
|
||||||
} |
|
||||||
sort.Sort(reports) |
|
||||||
for _, report := range reports { |
|
||||||
errorf("%s: %s is unused", fs.Position(report.pos), report.name) |
|
||||||
} |
|
||||||
|
|
||||||
for name, node := range p.missingcomments { |
|
||||||
errorf("%s: comment is missing for 'func %s'", fs.Position(node.Pos()), name) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func main() { |
|
||||||
flag.Parse() |
|
||||||
if flag.NArg() == 0 { |
|
||||||
doDir(".") |
|
||||||
} else { |
|
||||||
for _, name := range flag.Args() { |
|
||||||
// Is it a directory?
|
|
||||||
if fi, err := os.Stat(name); err == nil && fi.IsDir() { |
|
||||||
err := filepath.Walk(name, getAllMinioPkgs) |
|
||||||
if err != nil { |
|
||||||
errorf(err.Error()) |
|
||||||
} |
|
||||||
for _, dir := range dirs { |
|
||||||
doDir(dir) |
|
||||||
} |
|
||||||
} else { |
|
||||||
errorf("not a directory: %s", name) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
os.Exit(exitCode) |
|
||||||
} |
|
Loading…
Reference in new issue