Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/doc/headscan.go

Documentation: go/doc

     1  // Copyright 2011 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  //go:build ignore
     6  // +build ignore
     7  
     8  /*
     9  	The headscan command extracts comment headings from package files;
    10  	it is used to detect false positives which may require an adjustment
    11  	to the comment formatting heuristics in comment.go.
    12  
    13  	Usage: headscan [-root root_directory]
    14  
    15  	By default, the $GOROOT/src directory is scanned.
    16  */
    17  package main
    18  
    19  import (
    20  	"bytes"
    21  	"flag"
    22  	"fmt"
    23  	"go/doc"
    24  	"go/parser"
    25  	"go/token"
    26  	"internal/lazyregexp"
    27  	"io/fs"
    28  	"os"
    29  	"path/filepath"
    30  	"runtime"
    31  	"strings"
    32  )
    33  
    34  var (
    35  	root    = flag.String("root", filepath.Join(runtime.GOROOT(), "src"), "root of filesystem tree to scan")
    36  	verbose = flag.Bool("v", false, "verbose mode")
    37  )
    38  
    39  // ToHTML in comment.go assigns a (possibly blank) ID to each heading
    40  var html_h = lazyregexp.New(`<h3 id="[^"]*">`)
    41  
    42  const html_endh = "</h3>\n"
    43  
    44  func isGoFile(fi fs.FileInfo) bool {
    45  	return strings.HasSuffix(fi.Name(), ".go") &&
    46  		!strings.HasSuffix(fi.Name(), "_test.go")
    47  }
    48  
    49  func appendHeadings(list []string, comment string) []string {
    50  	var buf bytes.Buffer
    51  	doc.ToHTML(&buf, comment, nil)
    52  	for s := buf.String(); ; {
    53  		loc := html_h.FindStringIndex(s)
    54  		if len(loc) == 0 {
    55  			break
    56  		}
    57  		i := loc[1]
    58  		j := strings.Index(s, html_endh)
    59  		if j < 0 {
    60  			list = append(list, s[i:]) // incorrect HTML
    61  			break
    62  		}
    63  		list = append(list, s[i:j])
    64  		s = s[j+len(html_endh):]
    65  	}
    66  	return list
    67  }
    68  
    69  func main() {
    70  	flag.Parse()
    71  	fset := token.NewFileSet()
    72  	nheadings := 0
    73  	err := filepath.WalkDir(*root, func(path string, info fs.DirEntry, err error) error {
    74  		if !info.IsDir() {
    75  			return nil
    76  		}
    77  		pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)
    78  		if err != nil {
    79  			if *verbose {
    80  				fmt.Fprintln(os.Stderr, err)
    81  			}
    82  			return nil
    83  		}
    84  		for _, pkg := range pkgs {
    85  			d := doc.New(pkg, path, doc.Mode(0))
    86  			list := appendHeadings(nil, d.Doc)
    87  			for _, d := range d.Consts {
    88  				list = appendHeadings(list, d.Doc)
    89  			}
    90  			for _, d := range d.Types {
    91  				list = appendHeadings(list, d.Doc)
    92  			}
    93  			for _, d := range d.Vars {
    94  				list = appendHeadings(list, d.Doc)
    95  			}
    96  			for _, d := range d.Funcs {
    97  				list = appendHeadings(list, d.Doc)
    98  			}
    99  			if len(list) > 0 {
   100  				// directories may contain multiple packages;
   101  				// print path and package name
   102  				fmt.Printf("%s (package %s)\n", path, pkg.Name)
   103  				for _, h := range list {
   104  					fmt.Printf("\t%s\n", h)
   105  				}
   106  				nheadings += len(list)
   107  			}
   108  		}
   109  		return nil
   110  	})
   111  	if err != nil {
   112  		fmt.Fprintln(os.Stderr, err)
   113  		os.Exit(1)
   114  	}
   115  	fmt.Println(nheadings, "headings found")
   116  }
   117  

View as plain text