diff options
Diffstat (limited to 'vendor/honnef.co/go/tools/facts/deprecated.go')
-rw-r--r-- | vendor/honnef.co/go/tools/facts/deprecated.go | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/vendor/honnef.co/go/tools/facts/deprecated.go b/vendor/honnef.co/go/tools/facts/deprecated.go new file mode 100644 index 0000000..8587b0e --- /dev/null +++ b/vendor/honnef.co/go/tools/facts/deprecated.go | |||
@@ -0,0 +1,144 @@ | |||
1 | package facts | ||
2 | |||
3 | import ( | ||
4 | "go/ast" | ||
5 | "go/token" | ||
6 | "go/types" | ||
7 | "reflect" | ||
8 | "strings" | ||
9 | |||
10 | "golang.org/x/tools/go/analysis" | ||
11 | ) | ||
12 | |||
13 | type IsDeprecated struct{ Msg string } | ||
14 | |||
15 | func (*IsDeprecated) AFact() {} | ||
16 | func (d *IsDeprecated) String() string { return "Deprecated: " + d.Msg } | ||
17 | |||
18 | type DeprecatedResult struct { | ||
19 | Objects map[types.Object]*IsDeprecated | ||
20 | Packages map[*types.Package]*IsDeprecated | ||
21 | } | ||
22 | |||
23 | var Deprecated = &analysis.Analyzer{ | ||
24 | Name: "fact_deprecated", | ||
25 | Doc: "Mark deprecated objects", | ||
26 | Run: deprecated, | ||
27 | FactTypes: []analysis.Fact{(*IsDeprecated)(nil)}, | ||
28 | ResultType: reflect.TypeOf(DeprecatedResult{}), | ||
29 | } | ||
30 | |||
31 | func deprecated(pass *analysis.Pass) (interface{}, error) { | ||
32 | var names []*ast.Ident | ||
33 | |||
34 | extractDeprecatedMessage := func(docs []*ast.CommentGroup) string { | ||
35 | for _, doc := range docs { | ||
36 | if doc == nil { | ||
37 | continue | ||
38 | } | ||
39 | parts := strings.Split(doc.Text(), "\n\n") | ||
40 | last := parts[len(parts)-1] | ||
41 | if !strings.HasPrefix(last, "Deprecated: ") { | ||
42 | continue | ||
43 | } | ||
44 | alt := last[len("Deprecated: "):] | ||
45 | alt = strings.Replace(alt, "\n", " ", -1) | ||
46 | return alt | ||
47 | } | ||
48 | return "" | ||
49 | } | ||
50 | doDocs := func(names []*ast.Ident, docs []*ast.CommentGroup) { | ||
51 | alt := extractDeprecatedMessage(docs) | ||
52 | if alt == "" { | ||
53 | return | ||
54 | } | ||
55 | |||
56 | for _, name := range names { | ||
57 | obj := pass.TypesInfo.ObjectOf(name) | ||
58 | pass.ExportObjectFact(obj, &IsDeprecated{alt}) | ||
59 | } | ||
60 | } | ||
61 | |||
62 | var docs []*ast.CommentGroup | ||
63 | for _, f := range pass.Files { | ||
64 | docs = append(docs, f.Doc) | ||
65 | } | ||
66 | if alt := extractDeprecatedMessage(docs); alt != "" { | ||
67 | // Don't mark package syscall as deprecated, even though | ||
68 | // it is. A lot of people still use it for simple | ||
69 | // constants like SIGKILL, and I am not comfortable | ||
70 | // telling them to use x/sys for that. | ||
71 | if pass.Pkg.Path() != "syscall" { | ||
72 | pass.ExportPackageFact(&IsDeprecated{alt}) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | docs = docs[:0] | ||
77 | for _, f := range pass.Files { | ||
78 | fn := func(node ast.Node) bool { | ||
79 | if node == nil { | ||
80 | return true | ||
81 | } | ||
82 | var ret bool | ||
83 | switch node := node.(type) { | ||
84 | case *ast.GenDecl: | ||
85 | switch node.Tok { | ||
86 | case token.TYPE, token.CONST, token.VAR: | ||
87 | docs = append(docs, node.Doc) | ||
88 | return true | ||
89 | default: | ||
90 | return false | ||
91 | } | ||
92 | case *ast.FuncDecl: | ||
93 | docs = append(docs, node.Doc) | ||
94 | names = []*ast.Ident{node.Name} | ||
95 | ret = false | ||
96 | case *ast.TypeSpec: | ||
97 | docs = append(docs, node.Doc) | ||
98 | names = []*ast.Ident{node.Name} | ||
99 | ret = true | ||
100 | case *ast.ValueSpec: | ||
101 | docs = append(docs, node.Doc) | ||
102 | names = node.Names | ||
103 | ret = false | ||
104 | case *ast.File: | ||
105 | return true | ||
106 | case *ast.StructType: | ||
107 | for _, field := range node.Fields.List { | ||
108 | doDocs(field.Names, []*ast.CommentGroup{field.Doc}) | ||
109 | } | ||
110 | return false | ||
111 | case *ast.InterfaceType: | ||
112 | for _, field := range node.Methods.List { | ||
113 | doDocs(field.Names, []*ast.CommentGroup{field.Doc}) | ||
114 | } | ||
115 | return false | ||
116 | default: | ||
117 | return false | ||
118 | } | ||
119 | if len(names) == 0 || len(docs) == 0 { | ||
120 | return ret | ||
121 | } | ||
122 | doDocs(names, docs) | ||
123 | |||
124 | docs = docs[:0] | ||
125 | names = nil | ||
126 | return ret | ||
127 | } | ||
128 | ast.Inspect(f, fn) | ||
129 | } | ||
130 | |||
131 | out := DeprecatedResult{ | ||
132 | Objects: map[types.Object]*IsDeprecated{}, | ||
133 | Packages: map[*types.Package]*IsDeprecated{}, | ||
134 | } | ||
135 | |||
136 | for _, fact := range pass.AllObjectFacts() { | ||
137 | out.Objects[fact.Object] = fact.Fact.(*IsDeprecated) | ||
138 | } | ||
139 | for _, fact := range pass.AllPackageFacts() { | ||
140 | out.Packages[fact.Package] = fact.Fact.(*IsDeprecated) | ||
141 | } | ||
142 | |||
143 | return out, nil | ||
144 | } | ||