Skip to content

Commit c882cb8

Browse files
authored
exported: correctly report deprecation-only comments (#1295)
1 parent 2442da0 commit c882cb8

File tree

3 files changed

+78
-12
lines changed

3 files changed

+78
-12
lines changed

rule/exported.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) {
182182
return
183183
}
184184

185-
if !hasTextComment(fn.Doc) {
185+
if !hasDocComment(fn.Doc) {
186186
w.onFailure(lint.Failure{
187187
Node: fn,
188188
Confidence: 1,
@@ -247,7 +247,7 @@ func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
247247
return
248248
}
249249

250-
if !hasTextComment(doc) {
250+
if !hasDocComment(doc) {
251251
w.onFailure(lint.Failure{
252252
Node: t,
253253
Confidence: 1,
@@ -314,7 +314,7 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
314314
return
315315
}
316316

317-
if !hasTextComment(vs.Doc) && !hasTextComment(gd.Doc) {
317+
if !hasDocComment(vs.Doc) && !hasDocComment(gd.Doc) {
318318
if genDeclMissingComments[gd] {
319319
return
320320
}
@@ -332,16 +332,16 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
332332
return
333333
}
334334
// If this GenDecl has parens and a comment, we don't check its comment form.
335-
if hasTextComment(gd.Doc) && gd.Lparen.IsValid() {
335+
if hasDocComment(gd.Doc) && gd.Lparen.IsValid() {
336336
return
337337
}
338338
// The relevant text to check will be on either vs.Doc or gd.Doc.
339339
// Use vs.Doc preferentially.
340340
var doc *ast.CommentGroup
341341
switch {
342-
case hasTextComment(vs.Doc):
342+
case hasDocComment(vs.Doc):
343343
doc = vs.Doc
344-
case hasTextComment(vs.Comment) && !hasTextComment(gd.Doc):
344+
case hasDocComment(vs.Comment) && !hasDocComment(gd.Doc):
345345
doc = vs.Comment
346346
default:
347347
doc = gd.Doc
@@ -359,17 +359,26 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD
359359
}
360360
}
361361

362-
// hasTextComment returns true if the comment contains a text comment
362+
// hasDocComment reports whether the comment group contains a documentation comment,
363+
// excluding directive comments and those consisting solely of a deprecation notice.
363364
// e.g. //go:embed foo.txt a directive comment, not a text comment
364365
// e.g. //nolint:whatever is a directive comment, not a text comment
365-
func hasTextComment(comment *ast.CommentGroup) bool {
366+
// e.g. // Deprecated: this is a deprecation comment
367+
func hasDocComment(comment *ast.CommentGroup) bool {
366368
if comment == nil {
367369
return false
368370
}
369371

370372
// a comment could be directive and not a text comment
371-
text := comment.Text()
372-
return text != ""
373+
text := comment.Text() // removes directives from the comment block
374+
return text != "" && !isOnlyDeprecationComment(text)
375+
}
376+
377+
// isOnlyDeprecationComment returns true if the comment starts with a standard deprecation notice.
378+
// It considers all paragraphs following the deprecation notice as part of the deprecation comment.
379+
// Assumes the comment is following the general ordering convention: (doc comment + deprecation)
380+
func isOnlyDeprecationComment(comment string) bool {
381+
return strings.HasPrefix(comment, "Deprecated: ")
373382
}
374383

375384
// normalizeText is a helper function that normalizes comment strings by:
@@ -401,7 +410,7 @@ func (w *lintExported) Visit(n ast.Node) ast.Visitor {
401410
case *ast.TypeSpec:
402411
// inside a GenDecl, which usually has the doc
403412
doc := v.Doc
404-
if !hasTextComment(doc) {
413+
if !hasDocComment(doc) {
405414
doc = w.lastGen.Doc
406415
}
407416
w.lintTypeDoc(v, doc)
@@ -437,7 +446,7 @@ func (w *lintExported) lintInterfaceMethod(typeName string, m *ast.Field) {
437446
return
438447
}
439448
name := m.Names[0].Name
440-
if !hasTextComment(m.Doc) {
449+
if !hasDocComment(m.Doc) {
441450
w.onFailure(lint.Failure{
442451
Node: m,
443452
Confidence: 1,

test/exported_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ func TestCheckDisablingOnDeclarationTypes(t *testing.T) {
4343
func TestCheckDirectiveComment(t *testing.T) {
4444
testRule(t, "exported_issue_1202", &rule.ExportedRule{}, &lint.RuleConfig{})
4545
}
46+
47+
func TestCheckDeprecationComment(t *testing.T) {
48+
testRule(t, "exported_issue_1231", &rule.ExportedRule{}, &lint.RuleConfig{})
49+
}

testdata/exported_issue_1231.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package golint
2+
3+
// Deprecated: this is deprecated, use math.PI instead
4+
const PI = 3.14 // MATCH /exported const PI should have comment or be unexported/
5+
6+
// Deprecated: this is deprecated
7+
var Buffer []byte // MATCH /exported var Buffer should have comment or be unexported/
8+
9+
// Eq returns true if a == b, false otherwise.
10+
// Deprecated: this is deprecated
11+
func Eq(a, b int) bool {
12+
return a == b
13+
}
14+
15+
// Deprecated: this is deprecated, use min instead
16+
// Min returns a if a <= b, b otherwise.
17+
func Min(a, b int) int { // MATCH /exported function Min should have comment or be unexported/
18+
if a < b {
19+
return a
20+
}
21+
return b
22+
}
23+
24+
// Maximum returns a if a >= b, b otherwise.
25+
// Deprecated: this is deprecated, use max instead
26+
func Max(a, b int) int { // MATCH:24 /comment on exported function Max should be of the form "Max ..."/
27+
if a > b {
28+
return a
29+
}
30+
return b
31+
}
32+
33+
// Deprecated: this is deprecated
34+
type Number float64 // MATCH /exported type Number should have comment or be unexported/
35+
36+
// Name is a type that represents a name.
37+
type Name string
38+
39+
// Greet returns a greeting for the name.
40+
func (n Name) Greet() string {
41+
return "Hello, " + string(n)
42+
}
43+
44+
// Deprecated: this is deprecated, use Name.ToString instead
45+
func (n Name) ToString() string { // MATCH /exported method Name.ToString should have comment or be unexported/
46+
return string(n)
47+
}
48+
49+
// String returns the string representation of the name.
50+
// Deprecated: this is deprecated, use Name.Greet instead
51+
func (n Name) String() string {
52+
return string(n)
53+
}

0 commit comments

Comments
 (0)