/
bones.go
126 lines (110 loc) · 2.51 KB
/
bones.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* bones
* Copyright (c) 2017, Christian Muehlhaeuser <muesli@gmail.com>
*
* For license see LICENSE
*/
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"strings"
"github.com/tsuna/gorewrite"
)
var fs = token.NewFileSet() // positions are relative to fset
var srcs = make(map[string][]byte)
// file represents a file being analyzed
type file struct {
f *ast.File
pkg *ast.Package
lastGen *ast.GenDecl // last GenDecl entered
filename string
al annotationList
}
type walker func(ast.Node) (ast.Node, bool)
func (w walker) Rewrite(node ast.Node) (ast.Node, gorewrite.Rewriter) {
n, v := w(node)
if v {
return n, w
}
return n, nil
}
func (f *file) walk(fn func(ast.Node) (ast.Node, bool)) ast.Node {
return gorewrite.Rewrite(walker(fn), f.f)
}
func (f *file) nodeWalk(node ast.Node) (ast.Node, bool) {
switch v := node.(type) {
case *ast.GenDecl:
if v.Tok == token.IMPORT {
return node, false
}
// token.CONST, token.TYPE or token.VAR
f.lastGen = v
return node, true
case *ast.FuncDecl:
f.checkFuncDoc(v)
// Don't proceed inside funcs
return node, false
case *ast.TypeSpec:
// inside a GenDecl, which usually has the doc
if v.Doc == nil {
v.Doc = f.lastGen.Doc
}
f.checkTypeDoc(v)
node = v
// Don't proceed inside types
return node, false
case *ast.ValueSpec:
// f.lintValueSpecDoc(v, lastGen, genDeclMissingComments)
return node, false
}
return node, true
}
func main() {
flag.Parse()
root := flag.Arg(0)
if len(root) == 0 {
root = "."
}
pkgs, err := parser.ParseDir(fs, root, func(fi os.FileInfo) bool {
// exclude tests
return !strings.HasSuffix(fi.Name(), "_test.go")
}, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
astf := make([]file, 0)
for _, pkg := range pkgs {
fmt.Printf("package %v\n", pkg.Name)
for fn, f := range pkg.Files {
fmt.Printf("file %v\n", fn)
fl := file{
f: f,
filename: fn,
}
srcs[fn] = readSource(fn)
astf = append(astf, fl)
}
}
// Ideally we'd use an ast.CommentMap to create the comments for us
// In the meantime though:
for _, fl := range astf {
fl.walk(fl.nodeWalk)
insertAnnotations(fl.filename, fl.al)
// Save the modified AST
/* var buf bytes.Buffer
if err := format.Node(&buf, fs, fl.f); err != nil {
panic(err)
}
if !bytes.Equal(buf.Bytes(), srcs[fl.filename][:len(srcs[fl.filename])-1]) {
if err := ioutil.WriteFile(fl.filename+".fixed", buf.Bytes(), 0644); err != nil {
log.Fatal(err)
}
} */
}
}