Skip to content

Instantly share code, notes, and snippets.

@starius
Last active October 1, 2017 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save starius/7a9a3f8fe1fff4f1e4e933baa0b34f69 to your computer and use it in GitHub Desktop.
Save starius/7a9a3f8fe1fff4f1e4e933baa0b34f69 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strings"
)
var (
root = flag.String("root", "", "Go source files root dir")
)
func inspectSource(path string, kind ast.ObjKind) bool {
source, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Failed to read %q: %v.", path, err)
}
lines := bytes.Split(source, []byte("\n"))
inIotaGroup := make(map[int]struct{})
inside := false
for l, line := range lines {
if bytes.Contains(line, []byte("iota")) {
inside = true
}
if bytes.Equal(line, []byte(")")) {
inside = false
}
if inside {
inIotaGroup[l+1] = struct{}{}
}
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, source, 0)
if err != nil {
log.Fatalf("Failed to parse %q: %v.", path, err)
}
var objects []*ast.Object
for _, obj := range f.Scope.Objects {
if obj.Kind == kind {
objects = append(objects, obj)
}
}
sort.Slice(objects, func(i, j int) bool {
return objects[i].Pos() < objects[j].Pos()
})
ok := true
for i, c := range objects {
if i == 0 {
continue
}
b := objects[i-1]
if strings.ToLower(b.Name) <= strings.ToLower(c.Name) {
continue
}
bLine := fset.Position(b.Pos()).Line
cLine := fset.Position(c.Pos()).Line
// Skip reporting if they belong to different groups.
differentGroups := false
for l := bLine - 1; l < cLine-1; l++ {
if bytes.Equal(lines[l], []byte(")")) {
differentGroups = true
}
}
if _, has := inIotaGroup[bLine]; has || differentGroups {
continue
}
fmt.Printf("%s: %s (line %d) and %s (line %d) are not ordered.\n", path, b.Name, bLine, c.Name, cLine)
ok = false
}
return ok
}
func main() {
flag.Parse()
if *root == "" {
log.Fatal("Specify -root")
}
ok := true
filepath.Walk(*root, func(path string, info os.FileInfo, err error) error {
if err == nil && !info.IsDir() && strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") && !strings.Contains(path, "vendor/") {
if !inspectSource(path, ast.Con) || !inspectSource(path, ast.Var) {
ok = false
}
}
return nil
})
if !ok {
os.Exit(1)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment