Source file src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
1 // Copyright 2025 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package astutil 6 7 import ( 8 "go/ast" 9 "go/token" 10 "iter" 11 "strings" 12 ) 13 14 // Deprecation returns the paragraph of the doc comment that starts with the 15 // conventional "Deprecation: " marker, as defined by 16 // https://go.dev/wiki/Deprecated, or "" if the documented symbol is not 17 // deprecated. 18 func Deprecation(doc *ast.CommentGroup) string { 19 for p := range strings.SplitSeq(doc.Text(), "\n\n") { 20 // There is still some ambiguity for deprecation message. This function 21 // only returns the paragraph introduced by "Deprecated: ". More 22 // information related to the deprecation may follow in additional 23 // paragraphs, but the deprecation message should be able to stand on 24 // its own. See golang/go#38743. 25 if strings.HasPrefix(p, "Deprecated: ") { 26 return p 27 } 28 } 29 return "" 30 } 31 32 // -- plundered from the future (CL 605517, issue #68021) -- 33 34 // TODO(adonovan): replace with ast.Directive after go1.25 (#68021). 35 // Beware of our local mods to handle analysistest 36 // "want" comments on the same line. 37 38 // A directive is a comment line with special meaning to the Go 39 // toolchain or another tool. It has the form: 40 // 41 // //tool:name args 42 // 43 // The "tool:" portion is missing for the three directives named 44 // line, extern, and export. 45 // 46 // See https://go.dev/doc/comment#Syntax for details of Go comment 47 // syntax and https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives 48 // for details of directives used by the Go compiler. 49 type Directive struct { 50 Pos token.Pos // of preceding "//" 51 Tool string 52 Name string 53 Args string // may contain internal spaces 54 } 55 56 // isDirective reports whether c is a comment directive. 57 // This code is also in go/printer. 58 func isDirective(c string) bool { 59 // "//line " is a line directive. 60 // "//extern " is for gccgo. 61 // "//export " is for cgo. 62 // (The // has been removed.) 63 if strings.HasPrefix(c, "line ") || strings.HasPrefix(c, "extern ") || strings.HasPrefix(c, "export ") { 64 return true 65 } 66 67 // "//[a-z0-9]+:[a-z0-9]" 68 // (The // has been removed.) 69 colon := strings.Index(c, ":") 70 if colon <= 0 || colon+1 >= len(c) { 71 return false 72 } 73 for i := 0; i <= colon+1; i++ { 74 if i == colon { 75 continue 76 } 77 b := c[i] 78 if !('a' <= b && b <= 'z' || '0' <= b && b <= '9') { 79 return false 80 } 81 } 82 return true 83 } 84 85 // Directives returns the directives within the comment. 86 func Directives(g *ast.CommentGroup) (res []*Directive) { 87 if g != nil { 88 // Avoid (*ast.CommentGroup).Text() as it swallows directives. 89 for _, c := range g.List { 90 if len(c.Text) > 2 && 91 c.Text[1] == '/' && 92 c.Text[2] != ' ' && 93 isDirective(c.Text[2:]) { 94 95 tool, nameargs, ok := strings.Cut(c.Text[2:], ":") 96 if !ok { 97 // Must be one of {line,extern,export}. 98 tool, nameargs = "", tool 99 } 100 name, args, _ := strings.Cut(nameargs, " ") // tab?? 101 // Permit an additional line comment after the args, chiefly to support 102 // [golang.org/x/tools/go/analysis/analysistest]. 103 args, _, _ = strings.Cut(args, "//") 104 res = append(res, &Directive{ 105 Pos: c.Slash, 106 Tool: tool, 107 Name: name, 108 Args: strings.TrimSpace(args), 109 }) 110 } 111 } 112 } 113 return 114 } 115 116 // Comments returns an iterator over the comments overlapping the specified interval. 117 func Comments(file *ast.File, start, end token.Pos) iter.Seq[*ast.Comment] { 118 // TODO(adonovan): optimize use binary O(log n) instead of linear O(n) search. 119 return func(yield func(*ast.Comment) bool) { 120 for _, cg := range file.Comments { 121 for _, co := range cg.List { 122 if co.Pos() > end { 123 return 124 } 125 if co.End() < start { 126 continue 127 } 128 129 if !yield(co) { 130 return 131 } 132 } 133 } 134 } 135 } 136