...

Source file src/golang.org/x/tools/copyright/copyright.go

Documentation: golang.org/x/tools/copyright

     1  // Copyright 2020 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 go1.18
     6  // +build go1.18
     7  
     8  // Package copyright checks that files have the correct copyright notices.
     9  package copyright
    10  
    11  import (
    12  	"go/ast"
    13  	"go/parser"
    14  	"go/token"
    15  	"io/fs"
    16  	"io/ioutil"
    17  	"path/filepath"
    18  	"regexp"
    19  	"strings"
    20  )
    21  
    22  func checkCopyright(dir string) ([]string, error) {
    23  	var files []string
    24  	err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
    25  		if err != nil {
    26  			return err
    27  		}
    28  		if d.IsDir() {
    29  			// Skip directories like ".git".
    30  			if strings.HasPrefix(d.Name(), ".") {
    31  				return filepath.SkipDir
    32  			}
    33  			// Skip any directory that starts with an underscore, as the go
    34  			// command would.
    35  			if strings.HasPrefix(d.Name(), "_") {
    36  				return filepath.SkipDir
    37  			}
    38  			return nil
    39  		}
    40  		needsCopyright, err := checkFile(dir, path)
    41  		if err != nil {
    42  			return err
    43  		}
    44  		if needsCopyright {
    45  			files = append(files, path)
    46  		}
    47  		return nil
    48  	})
    49  	return files, err
    50  }
    51  
    52  var copyrightRe = regexp.MustCompile(`Copyright \d{4} The Go Authors. All rights reserved.
    53  Use of this source code is governed by a BSD-style
    54  license that can be found in the LICENSE file.`)
    55  
    56  func checkFile(toolsDir, filename string) (bool, error) {
    57  	// Only check Go files.
    58  	if !strings.HasSuffix(filename, "go") {
    59  		return false, nil
    60  	}
    61  	// Don't check testdata files.
    62  	normalized := strings.TrimPrefix(filepath.ToSlash(filename), filepath.ToSlash(toolsDir))
    63  	if strings.Contains(normalized, "/testdata/") {
    64  		return false, nil
    65  	}
    66  	// goyacc is the only file with a different copyright header.
    67  	if strings.HasSuffix(normalized, "cmd/goyacc/yacc.go") {
    68  		return false, nil
    69  	}
    70  	content, err := ioutil.ReadFile(filename)
    71  	if err != nil {
    72  		return false, err
    73  	}
    74  	fset := token.NewFileSet()
    75  	parsed, err := parser.ParseFile(fset, filename, content, parser.ParseComments)
    76  	if err != nil {
    77  		return false, err
    78  	}
    79  	// Don't require headers on generated files.
    80  	if isGenerated(fset, parsed) {
    81  		return false, nil
    82  	}
    83  	shouldAddCopyright := true
    84  	for _, c := range parsed.Comments {
    85  		// The copyright should appear before the package declaration.
    86  		if c.Pos() > parsed.Package {
    87  			break
    88  		}
    89  		if copyrightRe.MatchString(c.Text()) {
    90  			shouldAddCopyright = false
    91  			break
    92  		}
    93  	}
    94  	return shouldAddCopyright, nil
    95  }
    96  
    97  // Copied from golang.org/x/tools/gopls/internal/lsp/source/util.go.
    98  // Matches cgo generated comment as well as the proposed standard:
    99  //
   100  //	https://golang.org/s/generatedcode
   101  var generatedRx = regexp.MustCompile(`// .*DO NOT EDIT\.?`)
   102  
   103  func isGenerated(fset *token.FileSet, file *ast.File) bool {
   104  	for _, commentGroup := range file.Comments {
   105  		for _, comment := range commentGroup.List {
   106  			if matched := generatedRx.MatchString(comment.Text); !matched {
   107  				continue
   108  			}
   109  			// Check if comment is at the beginning of the line in source.
   110  			if pos := fset.Position(comment.Slash); pos.Column == 1 {
   111  				return true
   112  			}
   113  		}
   114  	}
   115  	return false
   116  }
   117  

View as plain text