.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / analysis / passes / buildtag / buildtag_old.go
1 // Copyright 2013 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 // TODO(rsc): Delete this file once Go 1.17 comes out and we can retire Go 1.15 support.
6
7 //go:build !go1.16
8 // +build !go1.16
9
10 // Package buildtag defines an Analyzer that checks build tags.
11 package buildtag
12
13 import (
14         "bytes"
15         "fmt"
16         "go/ast"
17         "go/parser"
18         "strings"
19         "unicode"
20
21         "golang.org/x/tools/go/analysis"
22         "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
23 )
24
25 const Doc = "check that +build tags are well-formed and correctly located"
26
27 var Analyzer = &analysis.Analyzer{
28         Name: "buildtag",
29         Doc:  Doc,
30         Run:  runBuildTag,
31 }
32
33 func runBuildTag(pass *analysis.Pass) (interface{}, error) {
34         for _, f := range pass.Files {
35                 checkGoFile(pass, f)
36         }
37         for _, name := range pass.OtherFiles {
38                 if err := checkOtherFile(pass, name); err != nil {
39                         return nil, err
40                 }
41         }
42         for _, name := range pass.IgnoredFiles {
43                 if strings.HasSuffix(name, ".go") {
44                         f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments)
45                         if err != nil {
46                                 // Not valid Go source code - not our job to diagnose, so ignore.
47                                 return nil, nil
48                         }
49                         checkGoFile(pass, f)
50                 } else {
51                         if err := checkOtherFile(pass, name); err != nil {
52                                 return nil, err
53                         }
54                 }
55         }
56         return nil, nil
57 }
58
59 func checkGoFile(pass *analysis.Pass, f *ast.File) {
60         pastCutoff := false
61         for _, group := range f.Comments {
62                 // A +build comment is ignored after or adjoining the package declaration.
63                 if group.End()+1 >= f.Package {
64                         pastCutoff = true
65                 }
66
67                 // "+build" is ignored within or after a /*...*/ comment.
68                 if !strings.HasPrefix(group.List[0].Text, "//") {
69                         pastCutoff = true
70                         continue
71                 }
72
73                 // Check each line of a //-comment.
74                 for _, c := range group.List {
75                         if !strings.Contains(c.Text, "+build") {
76                                 continue
77                         }
78                         if err := checkLine(c.Text, pastCutoff); err != nil {
79                                 pass.Reportf(c.Pos(), "%s", err)
80                         }
81                 }
82         }
83 }
84
85 func checkOtherFile(pass *analysis.Pass, filename string) error {
86         content, tf, err := analysisutil.ReadFile(pass.Fset, filename)
87         if err != nil {
88                 return err
89         }
90
91         // We must look at the raw lines, as build tags may appear in non-Go
92         // files such as assembly files.
93         lines := bytes.SplitAfter(content, nl)
94
95         // Determine cutpoint where +build comments are no longer valid.
96         // They are valid in leading // comments in the file followed by
97         // a blank line.
98         //
99         // This must be done as a separate pass because of the
100         // requirement that the comment be followed by a blank line.
101         var cutoff int
102         for i, line := range lines {
103                 line = bytes.TrimSpace(line)
104                 if !bytes.HasPrefix(line, slashSlash) {
105                         if len(line) > 0 {
106                                 break
107                         }
108                         cutoff = i
109                 }
110         }
111
112         for i, line := range lines {
113                 line = bytes.TrimSpace(line)
114                 if !bytes.HasPrefix(line, slashSlash) {
115                         continue
116                 }
117                 if !bytes.Contains(line, []byte("+build")) {
118                         continue
119                 }
120                 if err := checkLine(string(line), i >= cutoff); err != nil {
121                         pass.Reportf(analysisutil.LineStart(tf, i+1), "%s", err)
122                         continue
123                 }
124         }
125         return nil
126 }
127
128 // checkLine checks a line that starts with "//" and contains "+build".
129 func checkLine(line string, pastCutoff bool) error {
130         line = strings.TrimPrefix(line, "//")
131         line = strings.TrimSpace(line)
132
133         if strings.HasPrefix(line, "+build") {
134                 fields := strings.Fields(line)
135                 if fields[0] != "+build" {
136                         // Comment is something like +buildasdf not +build.
137                         return fmt.Errorf("possible malformed +build comment")
138                 }
139                 if pastCutoff {
140                         return fmt.Errorf("+build comment must appear before package clause and be followed by a blank line")
141                 }
142                 if err := checkArguments(fields); err != nil {
143                         return err
144                 }
145         } else {
146                 // Comment with +build but not at beginning.
147                 if !pastCutoff {
148                         return fmt.Errorf("possible malformed +build comment")
149                 }
150         }
151         return nil
152 }
153
154 func checkArguments(fields []string) error {
155         for _, arg := range fields[1:] {
156                 for _, elem := range strings.Split(arg, ",") {
157                         if strings.HasPrefix(elem, "!!") {
158                                 return fmt.Errorf("invalid double negative in build constraint: %s", arg)
159                         }
160                         elem = strings.TrimPrefix(elem, "!")
161                         for _, c := range elem {
162                                 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
163                                         return fmt.Errorf("invalid non-alphanumeric build constraint: %s", arg)
164                                 }
165                         }
166                 }
167         }
168         return nil
169 }
170
171 var (
172         nl         = []byte("\n")
173         slashSlash = []byte("//")
174 )