10 "golang.org/x/tools/go/analysis"
13 type IsDeprecated struct{ Msg string }
15 func (*IsDeprecated) AFact() {}
16 func (d *IsDeprecated) String() string { return "Deprecated: " + d.Msg }
18 type DeprecatedResult struct {
19 Objects map[types.Object]*IsDeprecated
20 Packages map[*types.Package]*IsDeprecated
23 var Deprecated = &analysis.Analyzer{
24 Name: "fact_deprecated",
25 Doc: "Mark deprecated objects",
27 FactTypes: []analysis.Fact{(*IsDeprecated)(nil)},
28 ResultType: reflect.TypeOf(DeprecatedResult{}),
31 func deprecated(pass *analysis.Pass) (interface{}, error) {
32 var names []*ast.Ident
34 extractDeprecatedMessage := func(docs []*ast.CommentGroup) string {
35 for _, doc := range docs {
39 parts := strings.Split(doc.Text(), "\n\n")
40 last := parts[len(parts)-1]
41 if !strings.HasPrefix(last, "Deprecated: ") {
44 alt := last[len("Deprecated: "):]
45 alt = strings.Replace(alt, "\n", " ", -1)
50 doDocs := func(names []*ast.Ident, docs []*ast.CommentGroup) {
51 alt := extractDeprecatedMessage(docs)
56 for _, name := range names {
57 obj := pass.TypesInfo.ObjectOf(name)
58 pass.ExportObjectFact(obj, &IsDeprecated{alt})
62 var docs []*ast.CommentGroup
63 for _, f := range pass.Files {
64 docs = append(docs, f.Doc)
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})
77 for _, f := range pass.Files {
78 fn := func(node ast.Node) bool {
83 switch node := node.(type) {
86 case token.TYPE, token.CONST, token.VAR:
87 docs = append(docs, node.Doc)
93 docs = append(docs, node.Doc)
94 names = []*ast.Ident{node.Name}
97 docs = append(docs, node.Doc)
98 names = []*ast.Ident{node.Name}
101 docs = append(docs, node.Doc)
106 case *ast.StructType:
107 for _, field := range node.Fields.List {
108 doDocs(field.Names, []*ast.CommentGroup{field.Doc})
111 case *ast.InterfaceType:
112 for _, field := range node.Methods.List {
113 doDocs(field.Names, []*ast.CommentGroup{field.Doc})
119 if len(names) == 0 || len(docs) == 0 {
131 out := DeprecatedResult{
132 Objects: map[types.Object]*IsDeprecated{},
133 Packages: map[*types.Package]*IsDeprecated{},
136 for _, fact := range pass.AllObjectFacts() {
137 out.Objects[fact.Object] = fact.Fact.(*IsDeprecated)
139 for _, fact := range pass.AllPackageFacts() {
140 out.Packages[fact.Package] = fact.Fact.(*IsDeprecated)