This repository has been archived by the owner on Dec 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
deprecatedComment_checker.go
145 lines (126 loc) · 4.02 KB
/
deprecatedComment_checker.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package checkers
import (
"go/ast"
"regexp"
"strings"
"github.com/go-lintpack/lintpack"
"github.com/go-lintpack/lintpack/astwalk"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "deprecatedComment"
info.Tags = []string{"diagnostic", "experimental"}
info.Summary = "Detects malformed 'deprecated' doc-comments"
info.Before = `
// deprecated, use FuncNew instead
func FuncOld() int`
info.After = `
// Deprecated: use FuncNew instead
func FuncOld() int`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
c := &deprecatedCommentChecker{ctx: ctx}
c.commonPatterns = []*regexp.Regexp{
regexp.MustCompile(`(?i)this (?:function|type) is deprecated`),
regexp.MustCompile(`(?i)deprecated[.!]? use \S* instead`),
// TODO(quasilyte): more of these?
}
// TODO(quasilyte): may want to generate this list programmatically.
//
// TODO(quasilyte): currently it only handles a single missing letter.
// Might want to handle other kinds of common misspell/typo kinds.
c.commonTypos = []string{
"Dprecated: ",
"Derecated: ",
"Depecated: ",
"Deprcated: ",
"Depreated: ",
"Deprected: ",
"Deprecaed: ",
"Deprecatd: ",
"Deprecate: ",
"Derpecate: ",
"Derpecated: ",
}
for i := range c.commonTypos {
c.commonTypos[i] = strings.ToUpper(c.commonTypos[i])
}
return astwalk.WalkerForDocComment(c)
})
}
type deprecatedCommentChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
commonPatterns []*regexp.Regexp
commonTypos []string
}
func (c *deprecatedCommentChecker) VisitDocComment(doc *ast.CommentGroup) {
// There are 3 accepted forms of deprecation comments:
//
// 1. inline, that can't be handled with a DocCommentVisitor.
// Note that "Deprecated: " may not even be the comment prefix there.
// Example: "The line number in the input. Deprecated: Kept for compatibility."
// TODO(quasilyte): fix it.
//
// 2. Longer form-1. It's a doc-comment that only contains "deprecation" notice.
//
// 3. Like form-2, but may also include doc-comment text.
// Distinguished by an empty line.
//
// See https://github.com/golang/go/issues/10909#issuecomment-136492606.
//
// It's desirable to see how people make mistakes with the format,
// this is why there is currently no special treatment for these cases.
// TODO(quasilyte): do more audits and grow the negative tests suite.
//
// TODO(quasilyte): there are also multi-line deprecation comments.
for _, comment := range doc.List {
if strings.HasPrefix(comment.Text, "/*") {
// TODO(quasilyte): handle multi-line doc comments.
continue
}
l := comment.Text[len("//"):]
if len(l) < len("Deprecated: ") {
continue
}
l = strings.TrimSpace(l)
// Check whether someone messed up with a prefix casing.
upcase := strings.ToUpper(l)
if strings.HasPrefix(upcase, "DEPRECATED: ") && !strings.HasPrefix(l, "Deprecated: ") {
c.warnCasing(comment, l)
return
}
// Check is someone used comma instead of a colon.
if strings.HasPrefix(l, "Deprecated, ") {
c.warnComma(comment)
return
}
// Check for other commonly used patterns.
for _, pat := range c.commonPatterns {
if pat.MatchString(l) {
c.warnPattern(comment)
return
}
}
// Detect some simple typos.
for _, prefixWithTypo := range c.commonTypos {
if strings.HasPrefix(upcase, prefixWithTypo) {
c.warnTypo(comment, l)
return
}
}
}
}
func (c *deprecatedCommentChecker) warnCasing(cause ast.Node, line string) {
prefix := line[:len("DEPRECATED: ")]
c.ctx.Warn(cause, "use `Deprecated: ` (note the casing) instead of `%s`", prefix)
}
func (c *deprecatedCommentChecker) warnPattern(cause ast.Node) {
c.ctx.Warn(cause, "the proper format is `Deprecated: <text>`")
}
func (c *deprecatedCommentChecker) warnComma(cause ast.Node) {
c.ctx.Warn(cause, "use `:` instead of `,` in `Deprecated, `")
}
func (c *deprecatedCommentChecker) warnTypo(cause ast.Node, line string) {
word := strings.Split(line, ":")[0]
c.ctx.Warn(cause, "typo in `%s`; should be `Deprecated`", word)
}