Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / analysis / passes / buildtag / buildtag.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/passes/buildtag/buildtag.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/passes/buildtag/buildtag.go
new file mode 100644 (file)
index 0000000..841b928
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package buildtag defines an Analyzer that checks build tags.
+package buildtag
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "strings"
+       "unicode"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
+)
+
+const Doc = "check that +build tags are well-formed and correctly located"
+
+var Analyzer = &analysis.Analyzer{
+       Name: "buildtag",
+       Doc:  Doc,
+       Run:  runBuildTag,
+}
+
+func runBuildTag(pass *analysis.Pass) (interface{}, error) {
+       for _, f := range pass.Files {
+               checkGoFile(pass, f)
+       }
+       for _, name := range pass.OtherFiles {
+               if err := checkOtherFile(pass, name); err != nil {
+                       return nil, err
+               }
+       }
+       for _, name := range pass.IgnoredFiles {
+               if strings.HasSuffix(name, ".go") {
+                       f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments)
+                       if err != nil {
+                               // Not valid Go source code - not our job to diagnose, so ignore.
+                               return nil, nil
+                       }
+                       checkGoFile(pass, f)
+               } else {
+                       if err := checkOtherFile(pass, name); err != nil {
+                               return nil, err
+                       }
+               }
+       }
+       return nil, nil
+}
+
+func checkGoFile(pass *analysis.Pass, f *ast.File) {
+       pastCutoff := false
+       for _, group := range f.Comments {
+               // A +build comment is ignored after or adjoining the package declaration.
+               if group.End()+1 >= f.Package {
+                       pastCutoff = true
+               }
+
+               // "+build" is ignored within or after a /*...*/ comment.
+               if !strings.HasPrefix(group.List[0].Text, "//") {
+                       pastCutoff = true
+                       continue
+               }
+
+               // Check each line of a //-comment.
+               for _, c := range group.List {
+                       if !strings.Contains(c.Text, "+build") {
+                               continue
+                       }
+                       if err := checkLine(c.Text, pastCutoff); err != nil {
+                               pass.Reportf(c.Pos(), "%s", err)
+                       }
+               }
+       }
+}
+
+func checkOtherFile(pass *analysis.Pass, filename string) error {
+       content, tf, err := analysisutil.ReadFile(pass.Fset, filename)
+       if err != nil {
+               return err
+       }
+
+       // We must look at the raw lines, as build tags may appear in non-Go
+       // files such as assembly files.
+       lines := bytes.SplitAfter(content, nl)
+
+       // Determine cutpoint where +build comments are no longer valid.
+       // They are valid in leading // comments in the file followed by
+       // a blank line.
+       //
+       // This must be done as a separate pass because of the
+       // requirement that the comment be followed by a blank line.
+       var cutoff int
+       for i, line := range lines {
+               line = bytes.TrimSpace(line)
+               if !bytes.HasPrefix(line, slashSlash) {
+                       if len(line) > 0 {
+                               break
+                       }
+                       cutoff = i
+               }
+       }
+
+       for i, line := range lines {
+               line = bytes.TrimSpace(line)
+               if !bytes.HasPrefix(line, slashSlash) {
+                       continue
+               }
+               if !bytes.Contains(line, []byte("+build")) {
+                       continue
+               }
+               if err := checkLine(string(line), i >= cutoff); err != nil {
+                       pass.Reportf(analysisutil.LineStart(tf, i+1), "%s", err)
+                       continue
+               }
+       }
+       return nil
+}
+
+// checkLine checks a line that starts with "//" and contains "+build".
+func checkLine(line string, pastCutoff bool) error {
+       line = strings.TrimPrefix(line, "//")
+       line = strings.TrimSpace(line)
+
+       if strings.HasPrefix(line, "+build") {
+               fields := strings.Fields(line)
+               if fields[0] != "+build" {
+                       // Comment is something like +buildasdf not +build.
+                       return fmt.Errorf("possible malformed +build comment")
+               }
+               if pastCutoff {
+                       return fmt.Errorf("+build comment must appear before package clause and be followed by a blank line")
+               }
+               if err := checkArguments(fields); err != nil {
+                       return err
+               }
+       } else {
+               // Comment with +build but not at beginning.
+               if !pastCutoff {
+                       return fmt.Errorf("possible malformed +build comment")
+               }
+       }
+       return nil
+}
+
+func checkArguments(fields []string) error {
+       for _, arg := range fields[1:] {
+               for _, elem := range strings.Split(arg, ",") {
+                       if strings.HasPrefix(elem, "!!") {
+                               return fmt.Errorf("invalid double negative in build constraint: %s", arg)
+                       }
+                       elem = strings.TrimPrefix(elem, "!")
+                       for _, c := range elem {
+                               if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
+                                       return fmt.Errorf("invalid non-alphanumeric build constraint: %s", arg)
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+var (
+       nl         = []byte("\n")
+       slashSlash = []byte("//")
+)