aboutsummaryrefslogtreecommitdiff
path: root/vendor/honnef.co/go/tools/facts/deprecated.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/honnef.co/go/tools/facts/deprecated.go')
-rw-r--r--vendor/honnef.co/go/tools/facts/deprecated.go144
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 @@
1package facts
2
3import (
4 "go/ast"
5 "go/token"
6 "go/types"
7 "reflect"
8 "strings"
9
10 "golang.org/x/tools/go/analysis"
11)
12
13type IsDeprecated struct{ Msg string }
14
15func (*IsDeprecated) AFact() {}
16func (d *IsDeprecated) String() string { return "Deprecated: " + d.Msg }
17
18type DeprecatedResult struct {
19 Objects map[types.Object]*IsDeprecated
20 Packages map[*types.Package]*IsDeprecated
21}
22
23var 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
31func 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}