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  

View as plain text