├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── builtin.go ├── doc.go ├── go.mod ├── go.sum ├── ident.go ├── ident_test.go ├── main.go ├── main_test.go ├── modified_test.go ├── pkg.go ├── pkg_test.go ├── testdata ├── interface-decls │ └── rabbit.go ├── issue52 │ ├── first │ │ ├── first.go │ │ └── second │ │ │ └── second.go │ └── main.go ├── package-doc │ └── main.go ├── package │ ├── const.go │ ├── embed.go │ ├── idents.go │ └── issue20.go └── withvendor │ ├── main.go │ └── vendor │ └── github.com │ └── zmb3 │ └── vp │ └── vp.go ├── unexported.go └── vendor ├── golang.org └── x │ └── tools │ ├── AUTHORS │ ├── CONTRIBUTORS │ ├── LICENSE │ ├── PATENTS │ ├── go │ ├── ast │ │ └── astutil │ │ │ ├── enclosing.go │ │ │ ├── imports.go │ │ │ ├── rewrite.go │ │ │ └── util.go │ ├── buildutil │ │ ├── allpackages.go │ │ ├── fakecontext.go │ │ ├── overlay.go │ │ ├── tags.go │ │ └── util.go │ ├── expect │ │ ├── expect.go │ │ └── extract.go │ ├── gcexportdata │ │ ├── gcexportdata.go │ │ ├── importer.go │ │ └── main.go │ ├── internal │ │ ├── cgo │ │ │ ├── cgo.go │ │ │ └── cgo_pkgconfig.go │ │ └── gcimporter │ │ │ ├── bexport.go │ │ │ ├── bimport.go │ │ │ ├── exportdata.go │ │ │ ├── gcimporter.go │ │ │ ├── iimport.go │ │ │ ├── newInterface10.go │ │ │ └── newInterface11.go │ └── packages │ │ ├── doc.go │ │ ├── external.go │ │ ├── golist.go │ │ ├── golist_fallback.go │ │ ├── golist_fallback_testmain.go │ │ ├── golist_overlay.go │ │ ├── packages.go │ │ ├── packagestest │ │ ├── expect.go │ │ ├── export.go │ │ ├── gopath.go │ │ ├── modules.go │ │ └── modules_111.go │ │ └── visit.go │ └── internal │ ├── fastwalk │ ├── fastwalk.go │ ├── fastwalk_dirent_fileno.go │ ├── fastwalk_dirent_ino.go │ ├── fastwalk_dirent_namlen_bsd.go │ ├── fastwalk_dirent_namlen_linux.go │ ├── fastwalk_portable.go │ └── fastwalk_unix.go │ ├── gopathwalk │ └── walk.go │ └── semver │ └── semver.go └── modules.txt /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Before submitting an issue, please make sure: 2 | - [ ] You're running Go 1.6 or later 3 | - [ ] You've tried installing with `go get -u` to update dependencies 4 | 5 | If you see the following error, you need to update to Go 1.6+: 6 | ``` 7 | $ go get github.com/zmb3/gogetdoc 8 | # github.com/zmb3/gogetdoc 9 | ./ident.go:142: c.Val().ExactString undefined (type constant.Value has no field or method ExactString) 10 | ``` 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | testdata/package/pkg/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.10.x 5 | - 1.11.x 6 | - master 7 | 8 | stages: 9 | - lint 10 | - test 11 | - build 12 | 13 | jobs: 14 | include: 15 | - stage: lint 16 | script: 17 | - go get -u golang.org/x/lint/golint 18 | - golint -set_exit_status 19 | - go vet -v 20 | - stage: test 21 | script: 22 | - go test -v 23 | - stage: build 24 | script: 25 | - go build 26 | 27 | matrix: 28 | allow_failures: 29 | - go: master 30 | fast_finish: true 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Zac Bergquist 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of gogetdoc nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gogetdoc 2 | 3 | [![Build Status](https://travis-ci.org/zmb3/gogetdoc.svg?branch=master)](https://travis-ci.org/zmb3/gogetdoc) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/zmb3/gogetdoc)](https://goreportcard.com/report/github.com/zmb3/gogetdoc) 5 | 6 | Retrieve documentation for items in Go source code. 7 | 8 | Go has a variety of tools that make it easy to lookup documentation. 9 | There's the `godoc` HTTP server, the `go doc` command line tool, and https://godoc.org. 10 | 11 | These tools are great, but in many cases one may find it valuable to lookup 12 | documentation right from their editor. The problem with all of these tools 13 | is that they are all meant to be used by a person who knows what they are 14 | looking for. This makes editor integration difficult, as there isn't an easy way 15 | to say "get me the documentation for this item here." 16 | 17 | The `gogetdoc` tool aims to make it easier for editors to provide access to 18 | Go documentation. Simply give it a filename and offset within the file and 19 | it will figure out what you're referring to and find the documentation 20 | for it. 21 | 22 | ## Usage 23 | 24 | Simply specify a filename and _byte_ offset with the `pos` flag: 25 | 26 | ``` 27 | $ gogetdoc -pos "$(go env GOROOT)/src/fmt/format.go:#2351" 28 | import "unicode/utf8" 29 | 30 | func RuneCountInString(s string) (n int) 31 | 32 | RuneCountInString is like RuneCount but its input is a string. 33 | ``` 34 | 35 | The `-json` flag can be used to enable the extended JSON output. 36 | In this mode, a JSON object will be written to stdout instead of the raw doc. 37 | 38 | ```javascript 39 | { 40 | "name": "RuneCountInString", 41 | "import": "unicode/utf8", 42 | "pkg": "utf8", 43 | "decl": "func RuneCountInString(s string) (n int)", 44 | "doc": "RuneCountInString is like RuneCount but its input is a string.\n", 45 | "pos": "/usr/local/Cellar/go/1.9/libexec/src/unicode/utf8/utf8.go:412:6" 46 | } 47 | ``` 48 | 49 | ### Unsaved files 50 | 51 | `gogetdoc` supports the same archive format as `guru` (formerly `oracle`). 52 | Editors can supply `gogetdoc` with the contents of unsaved buffers by 53 | using the `-modified` flag and writing an archive to stdin. 54 | Files in the archive will be preferred over those on disk. 55 | 56 | Each archive entry consists of: 57 | 58 | - the file name, followed by a newline 59 | - the (decimal) file size, followed by a newline 60 | - the contents of the file 61 | 62 | ## Editor Support 63 | 64 | The following editor plugins are known to support `gogetdoc`: 65 | 66 | - Atom: go-plus https://github.com/joefitzgerald/go-plus 67 | - VS Code: vscode-go https://github.com/Microsoft/vscode-go 68 | - Vim: vim-go https://github.com/fatih/vim-go 69 | - Emacs: go-mode https://github.com/dominikh/go-mode.el 70 | 71 | ## Contributions 72 | 73 | Are more than welcome! For small changes feel free to open a pull request. 74 | For larger changes or major features please open an issue to discuss. 75 | 76 | ## Credits 77 | 78 | The following resources served as both inspiration for starting this tool 79 | and help coming up with the implementation. 80 | 81 | - Alan Donovan's GothamGo talk "Using `go/types` for Code Comprehension 82 | and Refactoring Tools" https://youtu.be/p_cz7AxVdfg 83 | - Fatih Arslan's talk at dotGo 2015 "Tools for working with Go Code" 84 | - The `go/types` example repository: https://github.com/golang/example/tree/master/gotypes 85 | 86 | ## License 87 | 88 | `gogetdoc` is licensed under the 3-Clause BSD license - see the LICENSE file for details. 89 | 90 | Portions of this code are borrowed from the Go project and are Copyright 2015 The Go Authors. 91 | -------------------------------------------------------------------------------- /builtin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/ast" 5 | "go/doc" 6 | "go/parser" 7 | "go/token" 8 | "go/types" 9 | "log" 10 | 11 | "golang.org/x/tools/go/packages" 12 | ) 13 | 14 | func builtinPackage() *doc.Package { 15 | pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadFiles}, "builtin") 16 | if err != nil { 17 | log.Fatalf("error getting metadata of builtin: %v", err) 18 | } 19 | pkg := pkgs[0] 20 | 21 | fs := token.NewFileSet() 22 | fileMap := make(map[string]*ast.File) 23 | for _, filename := range pkg.GoFiles { 24 | file, err := parser.ParseFile(fs, filename, nil, parser.ParseComments) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | fileMap[filename] = file 29 | } 30 | 31 | astPkg := &ast.Package{ 32 | Name: pkg.Name, 33 | Files: fileMap, 34 | } 35 | return doc.New(astPkg, "builtin", doc.AllDecls) 36 | } 37 | 38 | // findInBuiltin searches for an identifier in the builtin package. 39 | // It searches in the following order: funcs, constants and variables, 40 | // and finally types. 41 | func findInBuiltin(name string, obj types.Object, prog *packages.Package) (docstring, decl string) { 42 | pkg := builtinPackage() 43 | 44 | consts := make([]*doc.Value, 0, 2*len(pkg.Consts)) 45 | vars := make([]*doc.Value, 0, 2*len(pkg.Vars)) 46 | funcs := make([]*doc.Func, 0, 2*len(pkg.Funcs)) 47 | 48 | consts = append(consts, pkg.Consts...) 49 | vars = append(vars, pkg.Vars...) 50 | funcs = append(funcs, pkg.Funcs...) 51 | 52 | for _, t := range pkg.Types { 53 | funcs = append(funcs, t.Funcs...) 54 | consts = append(consts, t.Consts...) 55 | vars = append(vars, t.Vars...) 56 | } 57 | 58 | // funcs 59 | for _, f := range funcs { 60 | if f.Name == name { 61 | return f.Doc, formatNode(f.Decl, obj, prog) 62 | } 63 | } 64 | 65 | // consts/vars 66 | for _, v := range consts { 67 | for _, n := range v.Names { 68 | if n == name { 69 | return v.Doc, "" 70 | } 71 | } 72 | } 73 | 74 | for _, v := range vars { 75 | for _, n := range v.Names { 76 | if n == name { 77 | return v.Doc, "" 78 | } 79 | } 80 | } 81 | 82 | // types 83 | for _, t := range pkg.Types { 84 | if t.Name == name { 85 | return t.Doc, formatNode(t.Decl, obj, prog) 86 | } 87 | } 88 | 89 | return "", "" 90 | } 91 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/doc" 7 | ) 8 | 9 | const ( 10 | indent = "" 11 | preIndent = " " 12 | ) 13 | 14 | // Doc holds the resulting documentation for a particular item. 15 | type Doc struct { 16 | Name string `json:"name"` 17 | Import string `json:"import"` 18 | Pkg string `json:"pkg"` 19 | Decl string `json:"decl"` 20 | Doc string `json:"doc"` 21 | Pos string `json:"pos"` 22 | } 23 | 24 | func (d *Doc) String() string { 25 | buf := &bytes.Buffer{} 26 | if d.Import != "" { 27 | fmt.Fprintf(buf, "import \"%s\"\n\n", d.Import) 28 | } 29 | fmt.Fprintf(buf, "%s\n\n", d.Decl) 30 | if d.Doc == "" { 31 | d.Doc = "Undocumented." 32 | } 33 | doc.ToText(buf, d.Doc, indent, preIndent, *linelength) 34 | return buf.String() 35 | } 36 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/zmb3/gogetdoc 2 | 3 | require golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393 h1:0P8IF6+RwCumULxvjp9EtJryUs46MgLIgeHbCt7NU4Q= 2 | golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 3 | -------------------------------------------------------------------------------- /ident.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/ast" 7 | "go/printer" 8 | "go/token" 9 | "go/types" 10 | "strings" 11 | 12 | "golang.org/x/tools/go/ast/astutil" 13 | "golang.org/x/tools/go/packages" 14 | ) 15 | 16 | func findTypeSpec(decl *ast.GenDecl, pos token.Pos) *ast.TypeSpec { 17 | for _, spec := range decl.Specs { 18 | typeSpec := spec.(*ast.TypeSpec) 19 | if typeSpec.Pos() == pos { 20 | return typeSpec 21 | } 22 | } 23 | return nil 24 | } 25 | 26 | func findVarSpec(decl *ast.GenDecl, pos token.Pos) *ast.ValueSpec { 27 | for _, spec := range decl.Specs { 28 | varSpec := spec.(*ast.ValueSpec) 29 | for _, ident := range varSpec.Names { 30 | if ident.Pos() == pos { 31 | return varSpec 32 | } 33 | } 34 | } 35 | return nil 36 | } 37 | 38 | func formatNode(n ast.Node, obj types.Object, prog *packages.Package) string { 39 | // fmt.Printf("formatting %T node\n", n) 40 | qual := func(p *types.Package) string { return "" } 41 | 42 | // We'd like to use types.ObjectString(obj, qual) where we can, 43 | // but there are several cases where we must render a copy of the AST 44 | // node with no documentation (we emit that ourselves). 45 | // 1) FuncDecl: ObjectString won't give us the decl for builtins 46 | // 2) TypeSpec: ObjectString does not allow us to trim unexported fields 47 | // 3) GenDecl: we need to find the inner {Type|Var}Spec 48 | var nc ast.Node 49 | switch n := n.(type) { 50 | case *ast.FuncDecl: 51 | cp := *n 52 | cp.Doc = nil 53 | cp.Body = nil // Don't print the whole function body 54 | nc = &cp 55 | case *ast.TypeSpec: 56 | specCp := *n 57 | if !*showUnexportedFields { 58 | trimUnexportedElems(&specCp) 59 | } 60 | specCp.Doc = nil 61 | typeSpec := ast.GenDecl{ 62 | Tok: token.TYPE, 63 | Specs: []ast.Spec{&specCp}, 64 | } 65 | nc = &typeSpec 66 | case *ast.GenDecl: 67 | cp := *n 68 | cp.Doc = nil 69 | if len(n.Specs) > 0 { 70 | // Only print this one type, not all the types in the gendecl 71 | switch n.Specs[0].(type) { 72 | case *ast.TypeSpec: 73 | spec := findTypeSpec(n, obj.Pos()) 74 | if spec != nil { 75 | specCp := *spec 76 | if !*showUnexportedFields { 77 | trimUnexportedElems(&specCp) 78 | } 79 | specCp.Doc = nil 80 | cp.Specs = []ast.Spec{&specCp} 81 | } 82 | cp.Lparen = 0 83 | cp.Rparen = 0 84 | case *ast.ValueSpec: 85 | spec := findVarSpec(n, obj.Pos()) 86 | if spec != nil { 87 | specCp := *spec 88 | specCp.Doc = nil 89 | cp.Specs = []ast.Spec{&specCp} 90 | } 91 | cp.Lparen = 0 92 | cp.Rparen = 0 93 | } 94 | } 95 | nc = &cp 96 | 97 | case *ast.Field: 98 | return types.ObjectString(obj, qual) 99 | default: 100 | return types.ObjectString(obj, qual) 101 | } 102 | 103 | buf := &bytes.Buffer{} 104 | cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} 105 | err := cfg.Fprint(buf, prog.Fset, nc) 106 | if err != nil { 107 | return obj.String() 108 | } 109 | 110 | return stripVendorFromImportPath(buf.String()) 111 | } 112 | 113 | // IdentDoc attempts to get the documentation for a *ast.Ident. 114 | func IdentDoc(id *ast.Ident, info *types.Info, pkg *packages.Package) (*Doc, error) { 115 | // get definition of identifier 116 | obj := info.ObjectOf(id) 117 | 118 | // for anonymous fields, we want the type definition, not the field 119 | if v, ok := obj.(*types.Var); ok && v.Anonymous() { 120 | obj = info.Uses[id] 121 | } 122 | 123 | var pos string 124 | if p := obj.Pos(); p.IsValid() { 125 | pos = pkg.Fset.Position(p).String() 126 | } 127 | 128 | pkgPath, pkgName := "", "" 129 | if op := obj.Pkg(); op != nil { 130 | pkgPath = op.Path() 131 | pkgName = op.Name() 132 | } 133 | 134 | // handle packages imported under a different name 135 | if p, ok := obj.(*types.PkgName); ok { 136 | return PackageDoc(pkg, p.Imported().Path()) 137 | } 138 | 139 | nodes := pathEnclosingInterval(pkg, obj.Pos(), obj.Pos()) 140 | if len(nodes) == 0 { 141 | // special case - builtins 142 | doc, decl := findInBuiltin(obj.Name(), obj, pkg) 143 | if doc != "" { 144 | return &Doc{ 145 | Import: "builtin", 146 | Pkg: "builtin", 147 | Name: obj.Name(), 148 | Doc: doc, 149 | Decl: decl, 150 | Pos: pos, 151 | }, nil 152 | } 153 | return nil, fmt.Errorf("no documentation found for %s", obj.Name()) 154 | } 155 | var doc *Doc 156 | for _, node := range nodes { 157 | switch node.(type) { 158 | case *ast.Ident: 159 | // continue ascending AST (searching for parent node of the identifier) 160 | continue 161 | case *ast.FuncDecl, *ast.GenDecl, *ast.Field, *ast.TypeSpec, *ast.ValueSpec: 162 | // found the parent node 163 | default: 164 | break 165 | } 166 | doc = &Doc{ 167 | Import: stripVendorFromImportPath(pkgPath), 168 | Pkg: pkgName, 169 | Name: obj.Name(), 170 | Decl: formatNode(node, obj, pkg), 171 | Pos: pos, 172 | } 173 | break 174 | } 175 | if doc == nil { 176 | // This shouldn't happen 177 | return nil, fmt.Errorf("no documentation found for %s", obj.Name()) 178 | } 179 | 180 | for _, node := range nodes { 181 | //fmt.Printf("for %s: found %T\n%#v\n", id.Name, node, node) 182 | switch n := node.(type) { 183 | case *ast.Ident: 184 | continue 185 | case *ast.FuncDecl: 186 | doc.Doc = n.Doc.Text() 187 | return doc, nil 188 | case *ast.Field: 189 | if n.Doc != nil { 190 | doc.Doc = n.Doc.Text() 191 | } else if n.Comment != nil { 192 | doc.Doc = n.Comment.Text() 193 | } 194 | return doc, nil 195 | case *ast.TypeSpec: 196 | if n.Doc != nil { 197 | doc.Doc = n.Doc.Text() 198 | return doc, nil 199 | } 200 | if n.Comment != nil { 201 | doc.Doc = n.Comment.Text() 202 | return doc, nil 203 | } 204 | case *ast.ValueSpec: 205 | if n.Doc != nil { 206 | doc.Doc = n.Doc.Text() 207 | return doc, nil 208 | } 209 | if n.Comment != nil { 210 | doc.Doc = n.Comment.Text() 211 | return doc, nil 212 | } 213 | case *ast.GenDecl: 214 | constValue := "" 215 | if c, ok := obj.(*types.Const); ok { 216 | constValue = c.Val().ExactString() 217 | } 218 | if doc.Doc == "" && n.Doc != nil { 219 | doc.Doc = n.Doc.Text() 220 | } 221 | if constValue != "" { 222 | doc.Doc += fmt.Sprintf("\nConstant Value: %s", constValue) 223 | } 224 | return doc, nil 225 | default: 226 | return doc, nil 227 | } 228 | } 229 | return doc, nil 230 | } 231 | 232 | // pathEnclosingInterval returns ast.Node of the package that 233 | // contain source interval [start, end), and all the node's ancestors 234 | // up to the AST root. It searches the ast.Files of initPkg and 235 | // the packages it imports recursively until something is found. 236 | // 237 | // Modified from golang.org/x/tools/go/loader. 238 | func pathEnclosingInterval(initPkg *packages.Package, start, end token.Pos) []ast.Node { 239 | for _, f := range initPkg.Syntax { 240 | if f.Pos() == token.NoPos { 241 | // This can happen if the parser saw 242 | // too many errors and bailed out. 243 | // (Use parser.AllErrors to prevent that.) 244 | continue 245 | } 246 | if !tokenFileContainsPos(initPkg.Fset.File(f.Pos()), start) { 247 | continue 248 | } 249 | if path, _ := astutil.PathEnclosingInterval(f, start, end); path != nil { 250 | return path 251 | } 252 | } 253 | 254 | for _, p := range initPkg.Imports { 255 | if path := pathEnclosingInterval(p, start, end); path != nil { 256 | return path 257 | } 258 | } 259 | 260 | return nil 261 | } 262 | 263 | func tokenFileContainsPos(f *token.File, pos token.Pos) bool { 264 | p := int(pos) 265 | base := f.Base() 266 | return base <= p && p < base+f.Size() 267 | } 268 | 269 | func stripVendorFromImportPath(ip string) string { 270 | vendor := "/vendor/" 271 | l := len(vendor) 272 | if i := strings.LastIndex(ip, vendor); i != -1 { 273 | return ip[i+l:] 274 | } 275 | return ip 276 | } 277 | -------------------------------------------------------------------------------- /ident_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/token" 5 | "path/filepath" 6 | "runtime" 7 | "strings" 8 | "testing" 9 | 10 | "golang.org/x/tools/go/packages/packagestest" 11 | ) 12 | 13 | func TestIdent(t *testing.T) { 14 | dir := filepath.Join(".", "testdata", "package") 15 | mods := []packagestest.Module{ 16 | {Name: "somepkg", Files: packagestest.MustCopyFileTree(dir)}, 17 | } 18 | 19 | packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { 20 | if exporter == packagestest.Modules && !modulesSupported() { 21 | t.Skip("Skipping modules test on", runtime.Version()) 22 | } 23 | exported := packagestest.Export(t, exporter, mods) 24 | defer exported.Cleanup() 25 | 26 | teardown := setup(exported.Config) 27 | defer teardown() 28 | 29 | getDoc := func(p token.Position) *Doc { 30 | t.Helper() 31 | doc, docErr := Run(p.Filename, p.Offset, nil) 32 | if docErr != nil { 33 | t.Fatal(docErr) 34 | } 35 | return doc 36 | } 37 | 38 | pcmp := func(want, got string) { 39 | t.Helper() 40 | if !strings.HasPrefix(got, want) { 41 | if len(got) > 64 { 42 | got = got[:64] 43 | } 44 | t.Errorf("expected prefix %q in %q", want, got) 45 | } 46 | } 47 | 48 | cmp := func(want, got string) { 49 | t.Helper() 50 | if got != want { 51 | t.Errorf("want %q, got %q", want, got) 52 | } 53 | } 54 | 55 | if expectErr := exported.Expect(map[string]interface{}{ 56 | "doc": func(p token.Position, doc string) { pcmp(doc, getDoc(p).Doc) }, 57 | "pkg": func(p token.Position, pkg string) { cmp(pkg, getDoc(p).Pkg) }, 58 | "decl": func(p token.Position, decl string) { cmp(decl, getDoc(p).Decl) }, 59 | "const": func(p token.Position, val string) { 60 | d := getDoc(p) 61 | needle := "Constant Value: " + val 62 | if !strings.Contains(d.Doc, needle) { 63 | t.Errorf("Expected %q in %q", needle, d.Doc) 64 | } 65 | }, 66 | "exported": func(p token.Position) { 67 | for _, showUnexported := range []bool{true, false} { 68 | *showUnexportedFields = showUnexported 69 | d := getDoc(p) 70 | hasUnexportedField := strings.Contains(d.Decl, "notVisible") 71 | if hasUnexportedField != *showUnexportedFields { 72 | t.Errorf("show unexported fields is %v, but got %q", showUnexported, d.Decl) 73 | } 74 | } 75 | }, 76 | }); expectErr != nil { 77 | t.Fatal(expectErr) 78 | } 79 | }) 80 | } 81 | 82 | func TestVendoredCode(t *testing.T) { 83 | dir := filepath.Join(".", "testdata", "withvendor") 84 | mods := []packagestest.Module{ 85 | {Name: "main", Files: packagestest.MustCopyFileTree(dir)}, 86 | } 87 | 88 | exported := packagestest.Export(t, packagestest.GOPATH, mods) 89 | defer exported.Cleanup() 90 | 91 | teardown := setup(exported.Config) 92 | defer teardown() 93 | 94 | filename := exported.File("main", "main.go") 95 | getDoc := func(p token.Position) *Doc { 96 | t.Helper() 97 | doc, docErr := Run(filename, p.Offset, nil) 98 | if docErr != nil { 99 | t.Fatal(docErr) 100 | } 101 | return doc 102 | } 103 | 104 | compare := func(want, got string) { 105 | if want != got { 106 | t.Errorf("want %q, got %q", want, got) 107 | } 108 | } 109 | 110 | if expectErr := exported.Expect(map[string]interface{}{ 111 | "import": func(p token.Position, path string) { compare(path, getDoc(p).Import) }, 112 | "decl": func(p token.Position, decl string) { compare(decl, getDoc(p).Decl) }, 113 | "doc": func(p token.Position, doc string) { compare(doc, getDoc(p).Doc) }, 114 | }); expectErr != nil { 115 | t.Fatal(expectErr) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // gogetdoc gets documentation for Go objects given their locations in the source code 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "flag" 9 | "fmt" 10 | "go/ast" 11 | "go/build" 12 | "go/parser" 13 | "go/token" 14 | "io" 15 | "io/ioutil" 16 | "log" 17 | "os" 18 | "runtime/debug" 19 | "runtime/pprof" 20 | "strconv" 21 | "strings" 22 | 23 | "golang.org/x/tools/go/ast/astutil" 24 | "golang.org/x/tools/go/buildutil" 25 | "golang.org/x/tools/go/packages" 26 | ) 27 | 28 | var ( 29 | cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") 30 | pos = flag.String("pos", "", "Filename and byte offset of item to document, e.g. foo.go:#123") 31 | modified = flag.Bool("modified", false, "read an archive of modified files from standard input") 32 | linelength = flag.Int("linelength", 80, "maximum length of a line in the output (in Unicode code points)") 33 | jsonOutput = flag.Bool("json", false, "enable extended JSON output") 34 | showUnexportedFields = flag.Bool("u", false, "show unexported fields") 35 | ) 36 | 37 | var archiveReader io.Reader = os.Stdin 38 | 39 | const modifiedUsage = ` 40 | The archive format for the -modified flag consists of the file name, followed 41 | by a newline, the decimal file size, another newline, and the contents of the file. 42 | 43 | This allows editors to supply gogetdoc with the contents of their unsaved buffers. 44 | ` 45 | 46 | const debugAST = false 47 | 48 | func fatal(args ...interface{}) { 49 | fmt.Fprintln(os.Stderr, args...) 50 | os.Exit(1) 51 | } 52 | 53 | func main() { 54 | // disable GC as gogetdoc is a short-lived program 55 | debug.SetGCPercent(-1) 56 | 57 | log.SetOutput(ioutil.Discard) 58 | 59 | flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc) 60 | flag.Usage = func() { 61 | fmt.Fprintf(os.Stderr, "Usage of %s\n", os.Args[0]) 62 | flag.PrintDefaults() 63 | fmt.Fprintf(os.Stderr, modifiedUsage) 64 | } 65 | flag.Parse() 66 | if *cpuprofile != "" { 67 | f, err := os.Create(*cpuprofile) 68 | if err != nil { 69 | fatal(err) 70 | } 71 | if err := pprof.StartCPUProfile(f); err != nil { 72 | fatal(err) 73 | } 74 | defer pprof.StopCPUProfile() 75 | } 76 | filename, offset, err := parsePos(*pos) 77 | if err != nil { 78 | fatal(err) 79 | } 80 | 81 | var overlay map[string][]byte 82 | if *modified { 83 | overlay, err = buildutil.ParseOverlayArchive(archiveReader) 84 | if err != nil { 85 | fatal(fmt.Errorf("invalid archive: %v", err)) 86 | } 87 | } 88 | 89 | d, err := Run(filename, offset, overlay) 90 | if err != nil { 91 | fatal(err) 92 | } 93 | 94 | if *jsonOutput { 95 | json.NewEncoder(os.Stdout).Encode(d) 96 | } else { 97 | fmt.Println(d.String()) 98 | } 99 | } 100 | 101 | // Load loads the package containing the specified file and returns the AST file 102 | // containing the search position. It can optionally load modified files from 103 | // an overlay archive. 104 | func Load(filename string, offset int, overlay map[string][]byte) (*packages.Package, []ast.Node, error) { 105 | type result struct { 106 | nodes []ast.Node 107 | err error 108 | } 109 | ch := make(chan result, 1) 110 | 111 | // Adapted from: https://github.com/ianthehat/godef 112 | fstat, fstatErr := os.Stat(filename) 113 | parseFile := func(fset *token.FileSet, fname string, src []byte) (*ast.File, error) { 114 | var ( 115 | err error 116 | s os.FileInfo 117 | ) 118 | isInputFile := false 119 | if filename == fname { 120 | isInputFile = true 121 | } else if fstatErr != nil { 122 | isInputFile = false 123 | } else if s, err = os.Stat(fname); err == nil { 124 | isInputFile = os.SameFile(fstat, s) 125 | } 126 | 127 | mode := parser.ParseComments 128 | if isInputFile && debugAST { 129 | mode |= parser.Trace 130 | } 131 | file, err := parser.ParseFile(fset, fname, src, mode) 132 | if file == nil { 133 | if isInputFile { 134 | ch <- result{nil, err} 135 | } 136 | return nil, err 137 | } 138 | var keepFunc *ast.FuncDecl 139 | if isInputFile { 140 | // find the start of the file (which may be before file.Pos() if there are 141 | // comments before the package clause) 142 | start := file.Pos() 143 | if len(file.Comments) > 0 && file.Comments[0].Pos() < start { 144 | start = file.Comments[0].Pos() 145 | } 146 | 147 | pos := start + token.Pos(offset) 148 | if pos > file.End() { 149 | err := fmt.Errorf("cursor %d is beyond end of file %s (%d)", offset, fname, file.End()-file.Pos()) 150 | ch <- result{nil, err} 151 | return file, err 152 | } 153 | path, _ := astutil.PathEnclosingInterval(file, pos, pos) 154 | if len(path) < 1 { 155 | err := fmt.Errorf("offset was not a valid token") 156 | ch <- result{nil, err} 157 | return nil, err 158 | } 159 | 160 | // if we are inside a function, we need to retain that function body 161 | // start from the top not the bottom 162 | for i := len(path) - 1; i >= 0; i-- { 163 | if f, ok := path[i].(*ast.FuncDecl); ok { 164 | keepFunc = f 165 | break 166 | } 167 | } 168 | ch <- result{path, nil} 169 | } 170 | // and drop all function bodies that are not relevant so they don't get 171 | // type checked 172 | for _, decl := range file.Decls { 173 | if f, ok := decl.(*ast.FuncDecl); ok && f != keepFunc { 174 | f.Body = nil 175 | } 176 | } 177 | return file, err 178 | } 179 | cfg := &packages.Config{ 180 | Overlay: overlay, 181 | Mode: packages.LoadAllSyntax, 182 | ParseFile: parseFile, 183 | Tests: strings.HasSuffix(filename, "_test.go"), 184 | } 185 | pkgs, err := packages.Load(cfg, fmt.Sprintf("file=%s", filename)) 186 | if err != nil { 187 | return nil, nil, fmt.Errorf("cannot load package containing %s: %v", filename, err) 188 | } 189 | if len(pkgs) == 0 { 190 | return nil, nil, fmt.Errorf("no package containing file %s", filename) 191 | } 192 | // Arbitrarily return the first package if there are multiple. 193 | // TODO: should the user be able to specify which one? 194 | if len(pkgs) > 1 { 195 | log.Printf("packages not processed: %v\n", pkgs[1:]) 196 | } 197 | 198 | r := <-ch 199 | if r.err != nil { 200 | return nil, nil, err 201 | } 202 | return pkgs[0], r.nodes, nil 203 | } 204 | 205 | // Run is a wrapper for the gogetdoc command. It is broken out of main for easier testing. 206 | func Run(filename string, offset int, overlay map[string][]byte) (*Doc, error) { 207 | pkg, nodes, err := Load(filename, offset, overlay) 208 | if err != nil { 209 | return nil, err 210 | } 211 | return DocFromNodes(pkg, nodes) 212 | } 213 | 214 | // DocFromNodes gets the documentation from the AST node(s) in the specified package. 215 | func DocFromNodes(pkg *packages.Package, nodes []ast.Node) (*Doc, error) { 216 | for _, node := range nodes { 217 | // log.Printf("node is a %T\n", node) 218 | switch node := node.(type) { 219 | case *ast.ImportSpec: 220 | return PackageDoc(pkg, ImportPath(node)) 221 | case *ast.Ident: 222 | // if we can't find the object denoted by the identifier, keep searching) 223 | if obj := pkg.TypesInfo.ObjectOf(node); obj == nil { 224 | continue 225 | } 226 | return IdentDoc(node, pkg.TypesInfo, pkg) 227 | default: 228 | break 229 | } 230 | } 231 | return nil, errors.New("gogetdoc: no documentation found") 232 | } 233 | 234 | // parsePos parses the search position as provided on the command line. 235 | // It should be of the form: foo.go:#123 236 | func parsePos(p string) (filename string, offset int, err error) { 237 | if p == "" { 238 | return "", 0, errors.New("missing required -pos flag") 239 | } 240 | sep := strings.LastIndex(p, ":") 241 | // need at least 2 characters after the ':' 242 | // (the # sign and the offset) 243 | if sep == -1 || sep > len(p)-2 || p[sep+1] != '#' { 244 | return "", 0, fmt.Errorf("invalid option: -pos=%s", p) 245 | } 246 | filename = p[:sep] 247 | off, err := strconv.ParseInt(p[sep+2:], 10, 32) 248 | return filename, int(off), err 249 | } 250 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/token" 5 | "os" 6 | "path/filepath" 7 | "runtime" 8 | "strconv" 9 | "strings" 10 | "testing" 11 | 12 | "golang.org/x/tools/go/packages" 13 | "golang.org/x/tools/go/packages/packagestest" 14 | ) 15 | 16 | func TestParseValidPos(t *testing.T) { 17 | fname, offset, err := parsePos("foo.go:#123") 18 | if fname != "foo.go" { 19 | t.Errorf("want foo.go, got %v", fname) 20 | } 21 | if offset != 123 { 22 | t.Errorf("want 123, got %v", 123) 23 | } 24 | if err != nil { 25 | t.Error(err) 26 | } 27 | } 28 | 29 | func TestParseEmptyPos(t *testing.T) { 30 | _, _, err := parsePos("") 31 | if err == nil { 32 | t.Error("expected error") 33 | } 34 | } 35 | 36 | func TestParseInvalidPos(t *testing.T) { 37 | for _, input := range []string{ 38 | "foo.go:123", 39 | "foo.go#123", 40 | "foo.go#:123", 41 | "123", 42 | "foo.go::123", 43 | "foo.go##123", 44 | "#:123", 45 | } { 46 | if _, _, err := parsePos(input); err == nil { 47 | t.Errorf("expected %v to be invalid", input) 48 | } 49 | } 50 | } 51 | 52 | func TestRunInvalidPos(t *testing.T) { 53 | dir := filepath.Join(".", "testdata", "package") 54 | mods := []packagestest.Module{ 55 | {Name: "somepkg", Files: packagestest.MustCopyFileTree(dir)}, 56 | } 57 | packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { 58 | if exporter == packagestest.Modules && !modulesSupported() { 59 | t.Skip("Skipping modules test on", runtime.Version()) 60 | } 61 | exported := packagestest.Export(t, exporter, mods) 62 | defer exported.Cleanup() 63 | 64 | teardown := setup(exported.Config) 65 | defer teardown() 66 | 67 | filename := exported.File("somepkg", "idents.go") 68 | _, err := Run(filename, 5000, nil) 69 | if err == nil { 70 | t.Fatal("expected invalid pos error") 71 | } 72 | }) 73 | } 74 | 75 | // github.com/zmb3/gogetdoc/issues/44 76 | func TestInterfaceDecls(t *testing.T) { 77 | mods := []packagestest.Module{ 78 | { 79 | Name: "rabbit", 80 | Files: packagestest.MustCopyFileTree(filepath.Join(".", "testdata", "interface-decls")), 81 | }, 82 | } 83 | // TODO: convert to packagestest.TestAll 84 | exported := packagestest.Export(t, packagestest.GOPATH, mods) 85 | defer exported.Cleanup() 86 | 87 | teardown := setup(exported.Config) 88 | defer teardown() 89 | 90 | filename := exported.File("rabbit", "rabbit.go") 91 | 92 | if expectErr := exported.Expect(map[string]interface{}{ 93 | "decl": func(p token.Position, decl string) { 94 | doc, err := Run(filename, p.Offset, nil) 95 | if err != nil { 96 | t.Error(err) 97 | } 98 | if doc.Decl != decl { 99 | t.Errorf("bad decl, want %q, got %q", decl, doc.Decl) 100 | } 101 | }, 102 | }); expectErr != nil { 103 | t.Fatal(expectErr) 104 | } 105 | } 106 | 107 | func modulesSupported() bool { 108 | v := strings.TrimPrefix(runtime.Version(), "go") 109 | parts := strings.Split(v, ".") 110 | if len(parts) < 2 { 111 | return false 112 | } 113 | minor, err := strconv.Atoi(parts[1]) 114 | if err != nil { 115 | return false 116 | } 117 | return minor >= 11 118 | } 119 | 120 | func setup(cfg *packages.Config) func() { 121 | originalDir, err := os.Getwd() 122 | if err != nil { 123 | panic(err) 124 | } 125 | err = os.Chdir(cfg.Dir) 126 | if err != nil { 127 | panic(err) 128 | } 129 | 130 | setEnv := func(env []string) { 131 | for _, assignment := range env { 132 | if i := strings.Index(assignment, "="); i > 0 { 133 | os.Setenv(assignment[:i], assignment[i+1:]) 134 | } 135 | } 136 | } 137 | originalEnv := os.Environ() 138 | setEnv(cfg.Env) 139 | os.Setenv("PWD", cfg.Dir) // https://go-review.googlesource.com/c/tools/+/143517/ 140 | 141 | return func() { 142 | os.Chdir(originalDir) 143 | setEnv(originalEnv) 144 | } 145 | } 146 | 147 | func TestIssue52(t *testing.T) { 148 | dir := filepath.Join(".", "testdata", "issue52") 149 | mods := []packagestest.Module{ 150 | {Name: "issue52", Files: packagestest.MustCopyFileTree(dir)}, 151 | } 152 | packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { 153 | if exporter == packagestest.Modules && !modulesSupported() { 154 | t.Skip("Skipping modules test on", runtime.Version()) 155 | } 156 | exported := packagestest.Export(t, exporter, mods) 157 | defer exported.Cleanup() 158 | 159 | teardown := setup(exported.Config) 160 | defer teardown() 161 | 162 | filename := exported.File("issue52", "main.go") 163 | 164 | for _, test := range []struct { 165 | Pos int 166 | Doc string 167 | }{ 168 | {64, "V this works\n"}, 169 | {66, "Foo this doesn't work but should\n"}, 170 | } { 171 | doc, err := Run(filename, test.Pos, nil) 172 | if err != nil { 173 | t.Fatalf("issue52, pos %d: %v", test.Pos, err) 174 | } 175 | if doc.Doc != test.Doc { 176 | t.Errorf("issue52, pos %d, invalid decl: want %q, got %q", test.Pos, test.Doc, doc.Doc) 177 | } 178 | } 179 | }) 180 | } 181 | -------------------------------------------------------------------------------- /modified_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "path/filepath" 6 | "runtime" 7 | "strings" 8 | "testing" 9 | 10 | "golang.org/x/tools/go/buildutil" 11 | "golang.org/x/tools/go/packages/packagestest" 12 | ) 13 | 14 | const contents = `package somepkg 15 | 16 | import "fmt" 17 | 18 | const ( 19 | Zero = iota 20 | One 21 | Two 22 | ) 23 | 24 | const Three = 3 25 | 26 | func main() { 27 | fmt.Println(Zero, Three, Two, Three) 28 | } 29 | ` 30 | 31 | func TestModified(t *testing.T) { 32 | dir := filepath.Join(".", "testdata", "package") 33 | mods := []packagestest.Module{ 34 | {Name: "somepkg", Files: packagestest.MustCopyFileTree(dir)}, 35 | } 36 | 37 | packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { 38 | if exporter == packagestest.Modules && !modulesSupported() { 39 | t.Skip("Skipping modules test on", runtime.Version()) 40 | } 41 | exported := packagestest.Export(t, exporter, mods) 42 | defer exported.Cleanup() 43 | 44 | teardown := setup(exported.Config) 45 | defer teardown() 46 | 47 | path := exported.File("somepkg", "const.go") 48 | archive := fmt.Sprintf("%s\n%d\n%s", path, len(contents), contents) 49 | overlay, err := buildutil.ParseOverlayArchive(strings.NewReader(archive)) 50 | if err != nil { 51 | t.Fatalf("couldn't parse overlay: %v", err) 52 | } 53 | 54 | d, err := Run(path, 114, overlay) 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | if n := d.Name; n != "Three" { 59 | t.Errorf("got const %s, want Three", n) 60 | } 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /pkg.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "go/ast" 7 | "go/doc" 8 | 9 | "golang.org/x/tools/go/packages" 10 | ) 11 | 12 | // ImportPath gets the import path from an ImportSpec. 13 | func ImportPath(is *ast.ImportSpec) string { 14 | s := is.Path.Value 15 | l := len(s) 16 | // trim the quotation marks 17 | return s[1 : l-1] 18 | } 19 | 20 | // PackageDoc gets the documentation for the package with the specified import 21 | // path and writes it to out. 22 | func PackageDoc(from *packages.Package, importPath string) (*Doc, error) { 23 | pkg := from.Imports[importPath] 24 | if pkg == nil { 25 | return nil, fmt.Errorf("package %s not in import map of packages %v", importPath, from) 26 | } 27 | if len(pkg.Syntax) == 0 { 28 | return nil, errors.New("no documentation found for " + pkg.Name) 29 | } 30 | 31 | fileMap := make(map[string]*ast.File) 32 | for _, file := range pkg.Syntax { 33 | fileMap[pkg.Fset.File(file.Pos()).Name()] = file 34 | } 35 | astPkg := &ast.Package{ 36 | Name: pkg.Name, 37 | Files: fileMap, 38 | } 39 | 40 | docPkg := doc.New(astPkg, importPath, 0) 41 | // TODO: we could also include package-level constants, vars, and functions (like the go doc command) 42 | return &Doc{ 43 | Name: pkg.Name, 44 | Decl: "package " + pkg.Name, 45 | Doc: docPkg.Doc, 46 | Import: importPath, 47 | Pkg: docPkg.Name, 48 | }, nil 49 | } 50 | -------------------------------------------------------------------------------- /pkg_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/token" 5 | "path/filepath" 6 | "runtime" 7 | "strings" 8 | "testing" 9 | 10 | "golang.org/x/tools/go/packages/packagestest" 11 | ) 12 | 13 | func TestPackageDoc(t *testing.T) { 14 | dir := filepath.Join(".", "testdata", "package-doc") 15 | mods := []packagestest.Module{ 16 | {Name: "pkgdoc", Files: packagestest.MustCopyFileTree(dir)}, 17 | } 18 | 19 | packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) { 20 | if exporter == packagestest.Modules && !modulesSupported() { 21 | t.Skip("Skipping modules test on", runtime.Version()) 22 | } 23 | exported := packagestest.Export(t, exporter, mods) 24 | defer exported.Cleanup() 25 | 26 | teardown := setup(exported.Config) 27 | defer teardown() 28 | 29 | filename := exported.File("pkgdoc", "main.go") 30 | if expectErr := exported.Expect(map[string]interface{}{ 31 | "pkgdoc": func(p token.Position, doc string) { 32 | d, err := Run(filename, p.Offset, nil) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | if !strings.HasPrefix(d.Doc, doc) { 37 | t.Errorf("expected %q, got %q", doc, d.Doc) 38 | } 39 | if !strings.HasPrefix(d.Decl, "package") { 40 | t.Errorf("expected %q to begin with 'package'", d.Decl) 41 | } 42 | }, 43 | }); expectErr != nil { 44 | t.Fatal(expectErr) 45 | } 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /testdata/interface-decls/rabbit.go: -------------------------------------------------------------------------------- 1 | package rabbit 2 | 3 | type Thing interface { 4 | Do(s Stuff) Stuff //@decl("Do", "func (Thing).Do(s Stuff) Stuff") 5 | DoWithError(s Stuff) (Stuff, error) //@decl("hError", "func (Thing).DoWithError(s Stuff) (Stuff, error)") 6 | DoWithNoArgs() //@decl("WithNoArgs", "func (Thing).DoWithNoArgs()") 7 | NamedReturns() (s string, err error) //@decl("medReturns", "func (Thing).NamedReturns() (s string, err error)") 8 | SameTypeParams(x, y string) //@decl("TypeParams", "func (Thing).SameTypeParams(x string, y string)") 9 | } 10 | 11 | type Stuff struct{} 12 | type ThingImplemented struct{} 13 | 14 | func (ti *ThingImplemented) Do(s Stuff) Stuff { //@decl("tuff", "type Stuff struct{}") 15 | return s 16 | } 17 | -------------------------------------------------------------------------------- /testdata/issue52/first/first.go: -------------------------------------------------------------------------------- 1 | package first 2 | 3 | import "issue52/first/second" 4 | 5 | //V this works 6 | var V second.T 7 | -------------------------------------------------------------------------------- /testdata/issue52/first/second/second.go: -------------------------------------------------------------------------------- 1 | package second 2 | 3 | type T struct{} 4 | 5 | //Foo this doesn't work but should 6 | func (t T) Foo() {} 7 | -------------------------------------------------------------------------------- /testdata/issue52/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "issue52/first" 5 | ) 6 | 7 | func main() { 8 | first.V.Foo() 9 | } 10 | -------------------------------------------------------------------------------- /testdata/package-doc/main.go: -------------------------------------------------------------------------------- 1 | // LICENSE TEXT 2 | 3 | // Package main is an example package. 4 | package main 5 | 6 | // superfluous comment 7 | 8 | import ( 9 | "fmt" 10 | mth "math" //@pkgdoc("th", "Package math provides"), pkgdoc("ath", "Package math provides") 11 | ) 12 | 13 | func main() { 14 | fmt.Println(mth.IsNaN(1.23)) //@pkgdoc("th.IsNaN", "Package math provides") 15 | fmt.Println("Goodbye") //@pkgdoc("mt.", "\tPackage fmt implements formatted I/O") 16 | } 17 | -------------------------------------------------------------------------------- /testdata/package/const.go: -------------------------------------------------------------------------------- 1 | package somepkg 2 | 3 | import "fmt" 4 | 5 | const ( 6 | Zero = iota 7 | One 8 | Two 9 | ) 10 | 11 | const Three = 3 12 | 13 | func main() { 14 | fmt.Println(Zero, One, Two, Three) //@const("Zero", "0"), const("One", "1"), const("Three", "3") 15 | } 16 | -------------------------------------------------------------------------------- /testdata/package/embed.go: -------------------------------------------------------------------------------- 1 | package somepkg 2 | 3 | // foo doc 4 | type foo struct { 5 | i int 6 | } 7 | 8 | type bar1 struct { 9 | foo //@doc("foo", "foo doc"), pkg("foo", "somepkg") 10 | f1 foo 11 | } 12 | 13 | type bar2 struct { 14 | *foo //@doc("foo", "foo doc"), pkg("foo", "somepkg") 15 | f1 *foo //@doc("foo", "foo doc"), pkg("foo", "somepkg") 16 | } 17 | -------------------------------------------------------------------------------- /testdata/package/idents.go: -------------------------------------------------------------------------------- 1 | package somepkg 2 | 3 | import ( 4 | "fmt" 5 | mth "math" 6 | ) 7 | 8 | type X struct{} 9 | 10 | // SayHello says hello. 11 | func (X) SayHello() { 12 | fmt.Println("Hello, World", mth.IsNaN(1.23)) //@doc("IsNaN", "IsNaN reports whether f") 13 | } 14 | 15 | func Baz() { 16 | var x X //@decl("X", "type X struct{}") 17 | x.SayHello() //@decl("ayHello", "func (X) SayHello()") 18 | SayGoodbye() //@doc("ayGood", "SayGoodbye says goodbye."), decl("ayGood", "func SayGoodbye() (string, error)") 19 | } 20 | 21 | // SayGoodbye says goodbye. 22 | func SayGoodbye() (string, error) { 23 | fmt.Println("Goodbye") 24 | fmt.Println(Message, fmt.Sprintf("The answer is %d", Answer)) //@const("Answer", "42"), doc("printf", "Sprintf formats according to a"), doc("Message", "Message is a message."), decl("Message", "var Message string") 25 | return "", nil 26 | } 27 | 28 | // Message is a message. 29 | var Message = "This is a test." 30 | 31 | // Answer is the answer to life the universe and everything. 32 | const Answer = 42 33 | 34 | type Foo struct { 35 | // FieldA has doc 36 | FieldA string 37 | FieldB string // FieldB has a comment 38 | } 39 | 40 | func (f Foo) Print() { 41 | fmt.Println(f.FieldA, f.FieldB) //@doc("FieldA", "FieldA has doc"), doc("FieldB", "FieldB has a comment"), decl("FieldA", "field FieldA string") 42 | } 43 | 44 | var slice = []int{0, 1, 2} 45 | 46 | func addInt(i int) { 47 | slice = append(slice, i) //@doc("append", "The append built-in function appends elements") 48 | if f := float32(i); f > 42 { //@doc("loat32", "float32 is the set of all IEEE-754 32-bit") 49 | fmt.Println("foo") 50 | } 51 | } 52 | 53 | const ( 54 | A = iota //@doc("iota", "iota is a predeclared identifier representing the untyped integer ordinal") 55 | B 56 | C 57 | ) 58 | 59 | var slice2 = []*Foo{nil, nil, nil} //@doc("nil", "nil is a predeclared identifier representing the zero") 60 | 61 | func test() { 62 | c := make(chan int) 63 | if l := len(slice2); l > 0 { //@doc("len", "The len built-in function returns") 64 | c <- l 65 | } 66 | close(c) //@doc("close", "The close built-in function closes") 67 | } 68 | 69 | func test2() error { //@doc("rror", "The error built-in interface type is the conventional") 70 | return nil 71 | } 72 | 73 | var ( 74 | // Alpha doc 75 | Alpha = 0 //@decl("lpha", "var Alpha int") 76 | Bravo = 1 // Bravo comment 77 | Charlie = 2 78 | Delta = Bravo //@doc("ravo", "Bravo comment"), decl("ravo", "var Bravo int") 79 | ) 80 | 81 | type HasUnexported struct { //@exported("Unexported") 82 | Visible string // Visible is an exported field 83 | notVisible string // notVisible is an unexported field 84 | } 85 | 86 | type NewString string 87 | 88 | var ns NewString //@decl("String", "type NewString string") 89 | -------------------------------------------------------------------------------- /testdata/package/issue20.go: -------------------------------------------------------------------------------- 1 | package somepkg 2 | 3 | import "fmt" 4 | 5 | // Foo is a test function. 6 | func Foo() { 7 | words := []string{} 8 | for _, word := range words { //@decl("rds", "var words []string") 9 | fmt.Println(word) 10 | } 11 | } 12 | 13 | func Bar() { 14 | tests := []struct { 15 | Name string 16 | args string 17 | }{ 18 | {"Test1", "a b c"}, 19 | {"Test2", "a b c"}, 20 | } 21 | for _, test := range tests { //@decl("tests", "var tests []struct{Name string; args string}") 22 | fmt.Println(test.Name) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testdata/withvendor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/zmb3/vp" //@import(".com", "github.com/zmb3/vp"), decl(".com", "package vp") 7 | ) 8 | 9 | func main() { 10 | vp.Hello() //@import("ello", "github.com/zmb3/vp"), doc("ello", "Hello says hello.\n") 11 | fmt.Println(vp.Foo) //@decl("Foo", "const Foo untyped string") 12 | } 13 | -------------------------------------------------------------------------------- /testdata/withvendor/vendor/github.com/zmb3/vp/vp.go: -------------------------------------------------------------------------------- 1 | // Package vp is an example vendored package. 2 | package vp 3 | 4 | import "fmt" 5 | 6 | // Hello says hello. 7 | func Hello() { 8 | fmt.Println("Hello") 9 | } 10 | 11 | const Foo = "bar" 12 | -------------------------------------------------------------------------------- /unexported.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "log" 7 | "unicode" 8 | "unicode/utf8" 9 | ) 10 | 11 | // Note: the code in this file is borrowed from the Go project. 12 | // It is licensed under a BSD-style license that is available 13 | // at https://golang.org/LICENSE. 14 | // 15 | // Copyright 2015 The Go Authors. All rights reserved. 16 | // Use of this source code is governed by a BSD-style 17 | // license that can be found in the LICENSE file. 18 | 19 | // trimUnexportedElems modifies spec in place to elide unexported fields from 20 | // structs and methods from interfaces (unless the unexported flag is set). 21 | func trimUnexportedElems(spec *ast.TypeSpec) { 22 | switch typ := spec.Type.(type) { 23 | case *ast.StructType: 24 | typ.Fields = trimUnexportedFields(typ.Fields, false) 25 | case *ast.InterfaceType: 26 | typ.Methods = trimUnexportedFields(typ.Methods, true) 27 | } 28 | } 29 | 30 | // trimUnexportedFields returns the field list trimmed of unexported fields. 31 | func trimUnexportedFields(fields *ast.FieldList, isInterface bool) *ast.FieldList { 32 | what := "methods" 33 | if !isInterface { 34 | what = "fields" 35 | } 36 | 37 | trimmed := false 38 | list := make([]*ast.Field, 0, len(fields.List)) 39 | for _, field := range fields.List { 40 | names := field.Names 41 | if len(names) == 0 { 42 | // Embedded type. Use the name of the type. It must be of type ident or *ident. 43 | // Nothing else is allowed. 44 | switch ident := field.Type.(type) { 45 | case *ast.Ident: 46 | if isInterface && ident.Name == "error" && ident.Obj == nil { 47 | // For documentation purposes, we consider the builtin error 48 | // type special when embedded in an interface, such that it 49 | // always gets shown publicly. 50 | list = append(list, field) 51 | continue 52 | } 53 | names = []*ast.Ident{ident} 54 | case *ast.StarExpr: 55 | // Must have the form *identifier. 56 | // This is only valid on embedded types in structs. 57 | if ident, ok := ident.X.(*ast.Ident); ok && !isInterface { 58 | names = []*ast.Ident{ident} 59 | } 60 | case *ast.SelectorExpr: 61 | // An embedded type may refer to a type in another package. 62 | names = []*ast.Ident{ident.Sel} 63 | } 64 | if names == nil { 65 | // Can only happen if AST is incorrect. Safe to continue with a nil list. 66 | log.Print("invalid program: unexpected type for embedded field") 67 | } 68 | } 69 | // Trims if any is unexported. Good enough in practice. 70 | ok := true 71 | for _, name := range names { 72 | if !isUpper(name.Name) { 73 | trimmed = true 74 | ok = false 75 | break 76 | } 77 | } 78 | if ok { 79 | list = append(list, field) 80 | } 81 | } 82 | if !trimmed { 83 | return fields 84 | } 85 | unexportedField := &ast.Field{ 86 | Type: &ast.Ident{ 87 | // Hack: printer will treat this as a field with a named type. 88 | // Setting Name and NamePos to ("", fields.Closing-1) ensures that 89 | // when Pos and End are called on this field, they return the 90 | // position right before closing '}' character. 91 | Name: "", 92 | NamePos: fields.Closing - 1, 93 | }, 94 | Comment: &ast.CommentGroup{ 95 | List: []*ast.Comment{{Text: fmt.Sprintf("// Has unexported %s.\n", what)}}, 96 | }, 97 | } 98 | return &ast.FieldList{ 99 | Opening: fields.Opening, 100 | List: append(list, unexportedField), 101 | Closing: fields.Closing, 102 | } 103 | } 104 | 105 | // isUpper reports whether the name starts with an upper case letter. 106 | func isUpper(name string) bool { 107 | ch, _ := utf8.DecodeRuneInString(name) 108 | return unicode.IsUpper(ch) 109 | } 110 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/ast/astutil/rewrite.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 | "fmt" 9 | "go/ast" 10 | "reflect" 11 | "sort" 12 | ) 13 | 14 | // An ApplyFunc is invoked by Apply for each node n, even if n is nil, 15 | // before and/or after the node's children, using a Cursor describing 16 | // the current node and providing operations on it. 17 | // 18 | // The return value of ApplyFunc controls the syntax tree traversal. 19 | // See Apply for details. 20 | type ApplyFunc func(*Cursor) bool 21 | 22 | // Apply traverses a syntax tree recursively, starting with root, 23 | // and calling pre and post for each node as described below. 24 | // Apply returns the syntax tree, possibly modified. 25 | // 26 | // If pre is not nil, it is called for each node before the node's 27 | // children are traversed (pre-order). If pre returns false, no 28 | // children are traversed, and post is not called for that node. 29 | // 30 | // If post is not nil, and a prior call of pre didn't return false, 31 | // post is called for each node after its children are traversed 32 | // (post-order). If post returns false, traversal is terminated and 33 | // Apply returns immediately. 34 | // 35 | // Only fields that refer to AST nodes are considered children; 36 | // i.e., token.Pos, Scopes, Objects, and fields of basic types 37 | // (strings, etc.) are ignored. 38 | // 39 | // Children are traversed in the order in which they appear in the 40 | // respective node's struct definition. A package's files are 41 | // traversed in the filenames' alphabetical order. 42 | // 43 | func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { 44 | parent := &struct{ ast.Node }{root} 45 | defer func() { 46 | if r := recover(); r != nil && r != abort { 47 | panic(r) 48 | } 49 | result = parent.Node 50 | }() 51 | a := &application{pre: pre, post: post} 52 | a.apply(parent, "Node", nil, root) 53 | return 54 | } 55 | 56 | var abort = new(int) // singleton, to signal termination of Apply 57 | 58 | // A Cursor describes a node encountered during Apply. 59 | // Information about the node and its parent is available 60 | // from the Node, Parent, Name, and Index methods. 61 | // 62 | // If p is a variable of type and value of the current parent node 63 | // c.Parent(), and f is the field identifier with name c.Name(), 64 | // the following invariants hold: 65 | // 66 | // p.f == c.Node() if c.Index() < 0 67 | // p.f[c.Index()] == c.Node() if c.Index() >= 0 68 | // 69 | // The methods Replace, Delete, InsertBefore, and InsertAfter 70 | // can be used to change the AST without disrupting Apply. 71 | type Cursor struct { 72 | parent ast.Node 73 | name string 74 | iter *iterator // valid if non-nil 75 | node ast.Node 76 | } 77 | 78 | // Node returns the current Node. 79 | func (c *Cursor) Node() ast.Node { return c.node } 80 | 81 | // Parent returns the parent of the current Node. 82 | func (c *Cursor) Parent() ast.Node { return c.parent } 83 | 84 | // Name returns the name of the parent Node field that contains the current Node. 85 | // If the parent is a *ast.Package and the current Node is a *ast.File, Name returns 86 | // the filename for the current Node. 87 | func (c *Cursor) Name() string { return c.name } 88 | 89 | // Index reports the index >= 0 of the current Node in the slice of Nodes that 90 | // contains it, or a value < 0 if the current Node is not part of a slice. 91 | // The index of the current node changes if InsertBefore is called while 92 | // processing the current node. 93 | func (c *Cursor) Index() int { 94 | if c.iter != nil { 95 | return c.iter.index 96 | } 97 | return -1 98 | } 99 | 100 | // field returns the current node's parent field value. 101 | func (c *Cursor) field() reflect.Value { 102 | return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) 103 | } 104 | 105 | // Replace replaces the current Node with n. 106 | // The replacement node is not walked by Apply. 107 | func (c *Cursor) Replace(n ast.Node) { 108 | if _, ok := c.node.(*ast.File); ok { 109 | file, ok := n.(*ast.File) 110 | if !ok { 111 | panic("attempt to replace *ast.File with non-*ast.File") 112 | } 113 | c.parent.(*ast.Package).Files[c.name] = file 114 | return 115 | } 116 | 117 | v := c.field() 118 | if i := c.Index(); i >= 0 { 119 | v = v.Index(i) 120 | } 121 | v.Set(reflect.ValueOf(n)) 122 | } 123 | 124 | // Delete deletes the current Node from its containing slice. 125 | // If the current Node is not part of a slice, Delete panics. 126 | // As a special case, if the current node is a package file, 127 | // Delete removes it from the package's Files map. 128 | func (c *Cursor) Delete() { 129 | if _, ok := c.node.(*ast.File); ok { 130 | delete(c.parent.(*ast.Package).Files, c.name) 131 | return 132 | } 133 | 134 | i := c.Index() 135 | if i < 0 { 136 | panic("Delete node not contained in slice") 137 | } 138 | v := c.field() 139 | l := v.Len() 140 | reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) 141 | v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) 142 | v.SetLen(l - 1) 143 | c.iter.step-- 144 | } 145 | 146 | // InsertAfter inserts n after the current Node in its containing slice. 147 | // If the current Node is not part of a slice, InsertAfter panics. 148 | // Apply does not walk n. 149 | func (c *Cursor) InsertAfter(n ast.Node) { 150 | i := c.Index() 151 | if i < 0 { 152 | panic("InsertAfter node not contained in slice") 153 | } 154 | v := c.field() 155 | v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 156 | l := v.Len() 157 | reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) 158 | v.Index(i + 1).Set(reflect.ValueOf(n)) 159 | c.iter.step++ 160 | } 161 | 162 | // InsertBefore inserts n before the current Node in its containing slice. 163 | // If the current Node is not part of a slice, InsertBefore panics. 164 | // Apply will not walk n. 165 | func (c *Cursor) InsertBefore(n ast.Node) { 166 | i := c.Index() 167 | if i < 0 { 168 | panic("InsertBefore node not contained in slice") 169 | } 170 | v := c.field() 171 | v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 172 | l := v.Len() 173 | reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) 174 | v.Index(i).Set(reflect.ValueOf(n)) 175 | c.iter.index++ 176 | } 177 | 178 | // application carries all the shared data so we can pass it around cheaply. 179 | type application struct { 180 | pre, post ApplyFunc 181 | cursor Cursor 182 | iter iterator 183 | } 184 | 185 | func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { 186 | // convert typed nil into untyped nil 187 | if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { 188 | n = nil 189 | } 190 | 191 | // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead 192 | saved := a.cursor 193 | a.cursor.parent = parent 194 | a.cursor.name = name 195 | a.cursor.iter = iter 196 | a.cursor.node = n 197 | 198 | if a.pre != nil && !a.pre(&a.cursor) { 199 | a.cursor = saved 200 | return 201 | } 202 | 203 | // walk children 204 | // (the order of the cases matches the order of the corresponding node types in go/ast) 205 | switch n := n.(type) { 206 | case nil: 207 | // nothing to do 208 | 209 | // Comments and fields 210 | case *ast.Comment: 211 | // nothing to do 212 | 213 | case *ast.CommentGroup: 214 | if n != nil { 215 | a.applyList(n, "List") 216 | } 217 | 218 | case *ast.Field: 219 | a.apply(n, "Doc", nil, n.Doc) 220 | a.applyList(n, "Names") 221 | a.apply(n, "Type", nil, n.Type) 222 | a.apply(n, "Tag", nil, n.Tag) 223 | a.apply(n, "Comment", nil, n.Comment) 224 | 225 | case *ast.FieldList: 226 | a.applyList(n, "List") 227 | 228 | // Expressions 229 | case *ast.BadExpr, *ast.Ident, *ast.BasicLit: 230 | // nothing to do 231 | 232 | case *ast.Ellipsis: 233 | a.apply(n, "Elt", nil, n.Elt) 234 | 235 | case *ast.FuncLit: 236 | a.apply(n, "Type", nil, n.Type) 237 | a.apply(n, "Body", nil, n.Body) 238 | 239 | case *ast.CompositeLit: 240 | a.apply(n, "Type", nil, n.Type) 241 | a.applyList(n, "Elts") 242 | 243 | case *ast.ParenExpr: 244 | a.apply(n, "X", nil, n.X) 245 | 246 | case *ast.SelectorExpr: 247 | a.apply(n, "X", nil, n.X) 248 | a.apply(n, "Sel", nil, n.Sel) 249 | 250 | case *ast.IndexExpr: 251 | a.apply(n, "X", nil, n.X) 252 | a.apply(n, "Index", nil, n.Index) 253 | 254 | case *ast.SliceExpr: 255 | a.apply(n, "X", nil, n.X) 256 | a.apply(n, "Low", nil, n.Low) 257 | a.apply(n, "High", nil, n.High) 258 | a.apply(n, "Max", nil, n.Max) 259 | 260 | case *ast.TypeAssertExpr: 261 | a.apply(n, "X", nil, n.X) 262 | a.apply(n, "Type", nil, n.Type) 263 | 264 | case *ast.CallExpr: 265 | a.apply(n, "Fun", nil, n.Fun) 266 | a.applyList(n, "Args") 267 | 268 | case *ast.StarExpr: 269 | a.apply(n, "X", nil, n.X) 270 | 271 | case *ast.UnaryExpr: 272 | a.apply(n, "X", nil, n.X) 273 | 274 | case *ast.BinaryExpr: 275 | a.apply(n, "X", nil, n.X) 276 | a.apply(n, "Y", nil, n.Y) 277 | 278 | case *ast.KeyValueExpr: 279 | a.apply(n, "Key", nil, n.Key) 280 | a.apply(n, "Value", nil, n.Value) 281 | 282 | // Types 283 | case *ast.ArrayType: 284 | a.apply(n, "Len", nil, n.Len) 285 | a.apply(n, "Elt", nil, n.Elt) 286 | 287 | case *ast.StructType: 288 | a.apply(n, "Fields", nil, n.Fields) 289 | 290 | case *ast.FuncType: 291 | a.apply(n, "Params", nil, n.Params) 292 | a.apply(n, "Results", nil, n.Results) 293 | 294 | case *ast.InterfaceType: 295 | a.apply(n, "Methods", nil, n.Methods) 296 | 297 | case *ast.MapType: 298 | a.apply(n, "Key", nil, n.Key) 299 | a.apply(n, "Value", nil, n.Value) 300 | 301 | case *ast.ChanType: 302 | a.apply(n, "Value", nil, n.Value) 303 | 304 | // Statements 305 | case *ast.BadStmt: 306 | // nothing to do 307 | 308 | case *ast.DeclStmt: 309 | a.apply(n, "Decl", nil, n.Decl) 310 | 311 | case *ast.EmptyStmt: 312 | // nothing to do 313 | 314 | case *ast.LabeledStmt: 315 | a.apply(n, "Label", nil, n.Label) 316 | a.apply(n, "Stmt", nil, n.Stmt) 317 | 318 | case *ast.ExprStmt: 319 | a.apply(n, "X", nil, n.X) 320 | 321 | case *ast.SendStmt: 322 | a.apply(n, "Chan", nil, n.Chan) 323 | a.apply(n, "Value", nil, n.Value) 324 | 325 | case *ast.IncDecStmt: 326 | a.apply(n, "X", nil, n.X) 327 | 328 | case *ast.AssignStmt: 329 | a.applyList(n, "Lhs") 330 | a.applyList(n, "Rhs") 331 | 332 | case *ast.GoStmt: 333 | a.apply(n, "Call", nil, n.Call) 334 | 335 | case *ast.DeferStmt: 336 | a.apply(n, "Call", nil, n.Call) 337 | 338 | case *ast.ReturnStmt: 339 | a.applyList(n, "Results") 340 | 341 | case *ast.BranchStmt: 342 | a.apply(n, "Label", nil, n.Label) 343 | 344 | case *ast.BlockStmt: 345 | a.applyList(n, "List") 346 | 347 | case *ast.IfStmt: 348 | a.apply(n, "Init", nil, n.Init) 349 | a.apply(n, "Cond", nil, n.Cond) 350 | a.apply(n, "Body", nil, n.Body) 351 | a.apply(n, "Else", nil, n.Else) 352 | 353 | case *ast.CaseClause: 354 | a.applyList(n, "List") 355 | a.applyList(n, "Body") 356 | 357 | case *ast.SwitchStmt: 358 | a.apply(n, "Init", nil, n.Init) 359 | a.apply(n, "Tag", nil, n.Tag) 360 | a.apply(n, "Body", nil, n.Body) 361 | 362 | case *ast.TypeSwitchStmt: 363 | a.apply(n, "Init", nil, n.Init) 364 | a.apply(n, "Assign", nil, n.Assign) 365 | a.apply(n, "Body", nil, n.Body) 366 | 367 | case *ast.CommClause: 368 | a.apply(n, "Comm", nil, n.Comm) 369 | a.applyList(n, "Body") 370 | 371 | case *ast.SelectStmt: 372 | a.apply(n, "Body", nil, n.Body) 373 | 374 | case *ast.ForStmt: 375 | a.apply(n, "Init", nil, n.Init) 376 | a.apply(n, "Cond", nil, n.Cond) 377 | a.apply(n, "Post", nil, n.Post) 378 | a.apply(n, "Body", nil, n.Body) 379 | 380 | case *ast.RangeStmt: 381 | a.apply(n, "Key", nil, n.Key) 382 | a.apply(n, "Value", nil, n.Value) 383 | a.apply(n, "X", nil, n.X) 384 | a.apply(n, "Body", nil, n.Body) 385 | 386 | // Declarations 387 | case *ast.ImportSpec: 388 | a.apply(n, "Doc", nil, n.Doc) 389 | a.apply(n, "Name", nil, n.Name) 390 | a.apply(n, "Path", nil, n.Path) 391 | a.apply(n, "Comment", nil, n.Comment) 392 | 393 | case *ast.ValueSpec: 394 | a.apply(n, "Doc", nil, n.Doc) 395 | a.applyList(n, "Names") 396 | a.apply(n, "Type", nil, n.Type) 397 | a.applyList(n, "Values") 398 | a.apply(n, "Comment", nil, n.Comment) 399 | 400 | case *ast.TypeSpec: 401 | a.apply(n, "Doc", nil, n.Doc) 402 | a.apply(n, "Name", nil, n.Name) 403 | a.apply(n, "Type", nil, n.Type) 404 | a.apply(n, "Comment", nil, n.Comment) 405 | 406 | case *ast.BadDecl: 407 | // nothing to do 408 | 409 | case *ast.GenDecl: 410 | a.apply(n, "Doc", nil, n.Doc) 411 | a.applyList(n, "Specs") 412 | 413 | case *ast.FuncDecl: 414 | a.apply(n, "Doc", nil, n.Doc) 415 | a.apply(n, "Recv", nil, n.Recv) 416 | a.apply(n, "Name", nil, n.Name) 417 | a.apply(n, "Type", nil, n.Type) 418 | a.apply(n, "Body", nil, n.Body) 419 | 420 | // Files and packages 421 | case *ast.File: 422 | a.apply(n, "Doc", nil, n.Doc) 423 | a.apply(n, "Name", nil, n.Name) 424 | a.applyList(n, "Decls") 425 | // Don't walk n.Comments; they have either been walked already if 426 | // they are Doc comments, or they can be easily walked explicitly. 427 | 428 | case *ast.Package: 429 | // collect and sort names for reproducible behavior 430 | var names []string 431 | for name := range n.Files { 432 | names = append(names, name) 433 | } 434 | sort.Strings(names) 435 | for _, name := range names { 436 | a.apply(n, name, nil, n.Files[name]) 437 | } 438 | 439 | default: 440 | panic(fmt.Sprintf("Apply: unexpected node type %T", n)) 441 | } 442 | 443 | if a.post != nil && !a.post(&a.cursor) { 444 | panic(abort) 445 | } 446 | 447 | a.cursor = saved 448 | } 449 | 450 | // An iterator controls iteration over a slice of nodes. 451 | type iterator struct { 452 | index, step int 453 | } 454 | 455 | func (a *application) applyList(parent ast.Node, name string) { 456 | // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead 457 | saved := a.iter 458 | a.iter.index = 0 459 | for { 460 | // must reload parent.name each time, since cursor modifications might change it 461 | v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) 462 | if a.iter.index >= v.Len() { 463 | break 464 | } 465 | 466 | // element x may be nil in a bad AST - be cautious 467 | var x ast.Node 468 | if e := v.Index(a.iter.index); e.IsValid() { 469 | x = e.Interface().(ast.Node) 470 | } 471 | 472 | a.iter.step = 1 473 | a.apply(parent, name, &a.iter, x) 474 | a.iter.index += a.iter.step 475 | } 476 | a.iter = saved 477 | } 478 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/ast/astutil/util.go: -------------------------------------------------------------------------------- 1 | package astutil 2 | 3 | import "go/ast" 4 | 5 | // Unparen returns e with any enclosing parentheses stripped. 6 | func Unparen(e ast.Expr) ast.Expr { 7 | for { 8 | p, ok := e.(*ast.ParenExpr) 9 | if !ok { 10 | return e 11 | } 12 | e = p.X 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/buildutil/allpackages.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 buildutil provides utilities related to the go/build 6 | // package in the standard library. 7 | // 8 | // All I/O is done via the build.Context file system interface, which must 9 | // be concurrency-safe. 10 | package buildutil // import "golang.org/x/tools/go/buildutil" 11 | 12 | import ( 13 | "go/build" 14 | "os" 15 | "path/filepath" 16 | "sort" 17 | "strings" 18 | "sync" 19 | ) 20 | 21 | // AllPackages returns the package path of each Go package in any source 22 | // directory of the specified build context (e.g. $GOROOT or an element 23 | // of $GOPATH). Errors are ignored. The results are sorted. 24 | // All package paths are canonical, and thus may contain "/vendor/". 25 | // 26 | // The result may include import paths for directories that contain no 27 | // *.go files, such as "archive" (in $GOROOT/src). 28 | // 29 | // All I/O is done via the build.Context file system interface, 30 | // which must be concurrency-safe. 31 | // 32 | func AllPackages(ctxt *build.Context) []string { 33 | var list []string 34 | ForEachPackage(ctxt, func(pkg string, _ error) { 35 | list = append(list, pkg) 36 | }) 37 | sort.Strings(list) 38 | return list 39 | } 40 | 41 | // ForEachPackage calls the found function with the package path of 42 | // each Go package it finds in any source directory of the specified 43 | // build context (e.g. $GOROOT or an element of $GOPATH). 44 | // All package paths are canonical, and thus may contain "/vendor/". 45 | // 46 | // If the package directory exists but could not be read, the second 47 | // argument to the found function provides the error. 48 | // 49 | // All I/O is done via the build.Context file system interface, 50 | // which must be concurrency-safe. 51 | // 52 | func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) { 53 | ch := make(chan item) 54 | 55 | var wg sync.WaitGroup 56 | for _, root := range ctxt.SrcDirs() { 57 | root := root 58 | wg.Add(1) 59 | go func() { 60 | allPackages(ctxt, root, ch) 61 | wg.Done() 62 | }() 63 | } 64 | go func() { 65 | wg.Wait() 66 | close(ch) 67 | }() 68 | 69 | // All calls to found occur in the caller's goroutine. 70 | for i := range ch { 71 | found(i.importPath, i.err) 72 | } 73 | } 74 | 75 | type item struct { 76 | importPath string 77 | err error // (optional) 78 | } 79 | 80 | // We use a process-wide counting semaphore to limit 81 | // the number of parallel calls to ReadDir. 82 | var ioLimit = make(chan bool, 20) 83 | 84 | func allPackages(ctxt *build.Context, root string, ch chan<- item) { 85 | root = filepath.Clean(root) + string(os.PathSeparator) 86 | 87 | var wg sync.WaitGroup 88 | 89 | var walkDir func(dir string) 90 | walkDir = func(dir string) { 91 | // Avoid .foo, _foo, and testdata directory trees. 92 | base := filepath.Base(dir) 93 | if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" { 94 | return 95 | } 96 | 97 | pkg := filepath.ToSlash(strings.TrimPrefix(dir, root)) 98 | 99 | // Prune search if we encounter any of these import paths. 100 | switch pkg { 101 | case "builtin": 102 | return 103 | } 104 | 105 | ioLimit <- true 106 | files, err := ReadDir(ctxt, dir) 107 | <-ioLimit 108 | if pkg != "" || err != nil { 109 | ch <- item{pkg, err} 110 | } 111 | for _, fi := range files { 112 | fi := fi 113 | if fi.IsDir() { 114 | wg.Add(1) 115 | go func() { 116 | walkDir(filepath.Join(dir, fi.Name())) 117 | wg.Done() 118 | }() 119 | } 120 | } 121 | } 122 | 123 | walkDir(root) 124 | wg.Wait() 125 | } 126 | 127 | // ExpandPatterns returns the set of packages matched by patterns, 128 | // which may have the following forms: 129 | // 130 | // golang.org/x/tools/cmd/guru # a single package 131 | // golang.org/x/tools/... # all packages beneath dir 132 | // ... # the entire workspace. 133 | // 134 | // Order is significant: a pattern preceded by '-' removes matching 135 | // packages from the set. For example, these patterns match all encoding 136 | // packages except encoding/xml: 137 | // 138 | // encoding/... -encoding/xml 139 | // 140 | // A trailing slash in a pattern is ignored. (Path components of Go 141 | // package names are separated by slash, not the platform's path separator.) 142 | // 143 | func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool { 144 | // TODO(adonovan): support other features of 'go list': 145 | // - "std"/"cmd"/"all" meta-packages 146 | // - "..." not at the end of a pattern 147 | // - relative patterns using "./" or "../" prefix 148 | 149 | pkgs := make(map[string]bool) 150 | doPkg := func(pkg string, neg bool) { 151 | if neg { 152 | delete(pkgs, pkg) 153 | } else { 154 | pkgs[pkg] = true 155 | } 156 | } 157 | 158 | // Scan entire workspace if wildcards are present. 159 | // TODO(adonovan): opt: scan only the necessary subtrees of the workspace. 160 | var all []string 161 | for _, arg := range patterns { 162 | if strings.HasSuffix(arg, "...") { 163 | all = AllPackages(ctxt) 164 | break 165 | } 166 | } 167 | 168 | for _, arg := range patterns { 169 | if arg == "" { 170 | continue 171 | } 172 | 173 | neg := arg[0] == '-' 174 | if neg { 175 | arg = arg[1:] 176 | } 177 | 178 | if arg == "..." { 179 | // ... matches all packages 180 | for _, pkg := range all { 181 | doPkg(pkg, neg) 182 | } 183 | } else if dir := strings.TrimSuffix(arg, "/..."); dir != arg { 184 | // dir/... matches all packages beneath dir 185 | for _, pkg := range all { 186 | if strings.HasPrefix(pkg, dir) && 187 | (len(pkg) == len(dir) || pkg[len(dir)] == '/') { 188 | doPkg(pkg, neg) 189 | } 190 | } 191 | } else { 192 | // single package 193 | doPkg(strings.TrimSuffix(arg, "/"), neg) 194 | } 195 | } 196 | 197 | return pkgs 198 | } 199 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/buildutil/fakecontext.go: -------------------------------------------------------------------------------- 1 | package buildutil 2 | 3 | import ( 4 | "fmt" 5 | "go/build" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | "sort" 12 | "strings" 13 | "time" 14 | ) 15 | 16 | // FakeContext returns a build.Context for the fake file tree specified 17 | // by pkgs, which maps package import paths to a mapping from file base 18 | // names to contents. 19 | // 20 | // The fake Context has a GOROOT of "/go" and no GOPATH, and overrides 21 | // the necessary file access methods to read from memory instead of the 22 | // real file system. 23 | // 24 | // Unlike a real file tree, the fake one has only two levels---packages 25 | // and files---so ReadDir("/go/src/") returns all packages under 26 | // /go/src/ including, for instance, "math" and "math/big". 27 | // ReadDir("/go/src/math/big") would return all the files in the 28 | // "math/big" package. 29 | // 30 | func FakeContext(pkgs map[string]map[string]string) *build.Context { 31 | clean := func(filename string) string { 32 | f := path.Clean(filepath.ToSlash(filename)) 33 | // Removing "/go/src" while respecting segment 34 | // boundaries has this unfortunate corner case: 35 | if f == "/go/src" { 36 | return "" 37 | } 38 | return strings.TrimPrefix(f, "/go/src/") 39 | } 40 | 41 | ctxt := build.Default // copy 42 | ctxt.GOROOT = "/go" 43 | ctxt.GOPATH = "" 44 | ctxt.Compiler = "gc" 45 | ctxt.IsDir = func(dir string) bool { 46 | dir = clean(dir) 47 | if dir == "" { 48 | return true // needed by (*build.Context).SrcDirs 49 | } 50 | return pkgs[dir] != nil 51 | } 52 | ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) { 53 | dir = clean(dir) 54 | var fis []os.FileInfo 55 | if dir == "" { 56 | // enumerate packages 57 | for importPath := range pkgs { 58 | fis = append(fis, fakeDirInfo(importPath)) 59 | } 60 | } else { 61 | // enumerate files of package 62 | for basename := range pkgs[dir] { 63 | fis = append(fis, fakeFileInfo(basename)) 64 | } 65 | } 66 | sort.Sort(byName(fis)) 67 | return fis, nil 68 | } 69 | ctxt.OpenFile = func(filename string) (io.ReadCloser, error) { 70 | filename = clean(filename) 71 | dir, base := path.Split(filename) 72 | content, ok := pkgs[path.Clean(dir)][base] 73 | if !ok { 74 | return nil, fmt.Errorf("file not found: %s", filename) 75 | } 76 | return ioutil.NopCloser(strings.NewReader(content)), nil 77 | } 78 | ctxt.IsAbsPath = func(path string) bool { 79 | path = filepath.ToSlash(path) 80 | // Don't rely on the default (filepath.Path) since on 81 | // Windows, it reports virtual paths as non-absolute. 82 | return strings.HasPrefix(path, "/") 83 | } 84 | return &ctxt 85 | } 86 | 87 | type byName []os.FileInfo 88 | 89 | func (s byName) Len() int { return len(s) } 90 | func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 91 | func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } 92 | 93 | type fakeFileInfo string 94 | 95 | func (fi fakeFileInfo) Name() string { return string(fi) } 96 | func (fakeFileInfo) Sys() interface{} { return nil } 97 | func (fakeFileInfo) ModTime() time.Time { return time.Time{} } 98 | func (fakeFileInfo) IsDir() bool { return false } 99 | func (fakeFileInfo) Size() int64 { return 0 } 100 | func (fakeFileInfo) Mode() os.FileMode { return 0644 } 101 | 102 | type fakeDirInfo string 103 | 104 | func (fd fakeDirInfo) Name() string { return string(fd) } 105 | func (fakeDirInfo) Sys() interface{} { return nil } 106 | func (fakeDirInfo) ModTime() time.Time { return time.Time{} } 107 | func (fakeDirInfo) IsDir() bool { return true } 108 | func (fakeDirInfo) Size() int64 { return 0 } 109 | func (fakeDirInfo) Mode() os.FileMode { return 0755 } 110 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/buildutil/overlay.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 buildutil 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "fmt" 11 | "go/build" 12 | "io" 13 | "io/ioutil" 14 | "path/filepath" 15 | "strconv" 16 | "strings" 17 | ) 18 | 19 | // OverlayContext overlays a build.Context with additional files from 20 | // a map. Files in the map take precedence over other files. 21 | // 22 | // In addition to plain string comparison, two file names are 23 | // considered equal if their base names match and their directory 24 | // components point at the same directory on the file system. That is, 25 | // symbolic links are followed for directories, but not files. 26 | // 27 | // A common use case for OverlayContext is to allow editors to pass in 28 | // a set of unsaved, modified files. 29 | // 30 | // Currently, only the Context.OpenFile function will respect the 31 | // overlay. This may change in the future. 32 | func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Context { 33 | // TODO(dominikh): Implement IsDir, HasSubdir and ReadDir 34 | 35 | rc := func(data []byte) (io.ReadCloser, error) { 36 | return ioutil.NopCloser(bytes.NewBuffer(data)), nil 37 | } 38 | 39 | copy := *orig // make a copy 40 | ctxt := © 41 | ctxt.OpenFile = func(path string) (io.ReadCloser, error) { 42 | // Fast path: names match exactly. 43 | if content, ok := overlay[path]; ok { 44 | return rc(content) 45 | } 46 | 47 | // Slow path: check for same file under a different 48 | // alias, perhaps due to a symbolic link. 49 | for filename, content := range overlay { 50 | if sameFile(path, filename) { 51 | return rc(content) 52 | } 53 | } 54 | 55 | return OpenFile(orig, path) 56 | } 57 | return ctxt 58 | } 59 | 60 | // ParseOverlayArchive parses an archive containing Go files and their 61 | // contents. The result is intended to be used with OverlayContext. 62 | // 63 | // 64 | // Archive format 65 | // 66 | // The archive consists of a series of files. Each file consists of a 67 | // name, a decimal file size and the file contents, separated by 68 | // newlinews. No newline follows after the file contents. 69 | func ParseOverlayArchive(archive io.Reader) (map[string][]byte, error) { 70 | overlay := make(map[string][]byte) 71 | r := bufio.NewReader(archive) 72 | for { 73 | // Read file name. 74 | filename, err := r.ReadString('\n') 75 | if err != nil { 76 | if err == io.EOF { 77 | break // OK 78 | } 79 | return nil, fmt.Errorf("reading archive file name: %v", err) 80 | } 81 | filename = filepath.Clean(strings.TrimSpace(filename)) 82 | 83 | // Read file size. 84 | sz, err := r.ReadString('\n') 85 | if err != nil { 86 | return nil, fmt.Errorf("reading size of archive file %s: %v", filename, err) 87 | } 88 | sz = strings.TrimSpace(sz) 89 | size, err := strconv.ParseUint(sz, 10, 32) 90 | if err != nil { 91 | return nil, fmt.Errorf("parsing size of archive file %s: %v", filename, err) 92 | } 93 | 94 | // Read file content. 95 | content := make([]byte, size) 96 | if _, err := io.ReadFull(r, content); err != nil { 97 | return nil, fmt.Errorf("reading archive file %s: %v", filename, err) 98 | } 99 | overlay[filename] = content 100 | } 101 | 102 | return overlay, nil 103 | } 104 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/buildutil/tags.go: -------------------------------------------------------------------------------- 1 | package buildutil 2 | 3 | // This logic was copied from stringsFlag from $GOROOT/src/cmd/go/build.go. 4 | 5 | import "fmt" 6 | 7 | const TagsFlagDoc = "a list of `build tags` to consider satisfied during the build. " + 8 | "For more information about build tags, see the description of " + 9 | "build constraints in the documentation for the go/build package" 10 | 11 | // TagsFlag is an implementation of the flag.Value and flag.Getter interfaces that parses 12 | // a flag value in the same manner as go build's -tags flag and 13 | // populates a []string slice. 14 | // 15 | // See $GOROOT/src/go/build/doc.go for description of build tags. 16 | // See $GOROOT/src/cmd/go/doc.go for description of 'go build -tags' flag. 17 | // 18 | // Example: 19 | // flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc) 20 | type TagsFlag []string 21 | 22 | func (v *TagsFlag) Set(s string) error { 23 | var err error 24 | *v, err = splitQuotedFields(s) 25 | if *v == nil { 26 | *v = []string{} 27 | } 28 | return err 29 | } 30 | 31 | func (v *TagsFlag) Get() interface{} { return *v } 32 | 33 | func splitQuotedFields(s string) ([]string, error) { 34 | // Split fields allowing '' or "" around elements. 35 | // Quotes further inside the string do not count. 36 | var f []string 37 | for len(s) > 0 { 38 | for len(s) > 0 && isSpaceByte(s[0]) { 39 | s = s[1:] 40 | } 41 | if len(s) == 0 { 42 | break 43 | } 44 | // Accepted quoted string. No unescaping inside. 45 | if s[0] == '"' || s[0] == '\'' { 46 | quote := s[0] 47 | s = s[1:] 48 | i := 0 49 | for i < len(s) && s[i] != quote { 50 | i++ 51 | } 52 | if i >= len(s) { 53 | return nil, fmt.Errorf("unterminated %c string", quote) 54 | } 55 | f = append(f, s[:i]) 56 | s = s[i+1:] 57 | continue 58 | } 59 | i := 0 60 | for i < len(s) && !isSpaceByte(s[i]) { 61 | i++ 62 | } 63 | f = append(f, s[:i]) 64 | s = s[i:] 65 | } 66 | return f, nil 67 | } 68 | 69 | func (v *TagsFlag) String() string { 70 | return "" 71 | } 72 | 73 | func isSpaceByte(c byte) bool { 74 | return c == ' ' || c == '\t' || c == '\n' || c == '\r' 75 | } 76 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/buildutil/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 buildutil 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/build" 11 | "go/parser" 12 | "go/token" 13 | "io" 14 | "io/ioutil" 15 | "os" 16 | "path" 17 | "path/filepath" 18 | "strings" 19 | ) 20 | 21 | // ParseFile behaves like parser.ParseFile, 22 | // but uses the build context's file system interface, if any. 23 | // 24 | // If file is not absolute (as defined by IsAbsPath), the (dir, file) 25 | // components are joined using JoinPath; dir must be absolute. 26 | // 27 | // The displayPath function, if provided, is used to transform the 28 | // filename that will be attached to the ASTs. 29 | // 30 | // TODO(adonovan): call this from go/loader.parseFiles when the tree thaws. 31 | // 32 | func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) { 33 | if !IsAbsPath(ctxt, file) { 34 | file = JoinPath(ctxt, dir, file) 35 | } 36 | rd, err := OpenFile(ctxt, file) 37 | if err != nil { 38 | return nil, err 39 | } 40 | defer rd.Close() // ignore error 41 | if displayPath != nil { 42 | file = displayPath(file) 43 | } 44 | return parser.ParseFile(fset, file, rd, mode) 45 | } 46 | 47 | // ContainingPackage returns the package containing filename. 48 | // 49 | // If filename is not absolute, it is interpreted relative to working directory dir. 50 | // All I/O is via the build context's file system interface, if any. 51 | // 52 | // The '...Files []string' fields of the resulting build.Package are not 53 | // populated (build.FindOnly mode). 54 | // 55 | func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) { 56 | if !IsAbsPath(ctxt, filename) { 57 | filename = JoinPath(ctxt, dir, filename) 58 | } 59 | 60 | // We must not assume the file tree uses 61 | // "/" always, 62 | // `\` always, 63 | // or os.PathSeparator (which varies by platform), 64 | // but to make any progress, we are forced to assume that 65 | // paths will not use `\` unless the PathSeparator 66 | // is also `\`, thus we can rely on filepath.ToSlash for some sanity. 67 | 68 | dirSlash := path.Dir(filepath.ToSlash(filename)) + "/" 69 | 70 | // We assume that no source root (GOPATH[i] or GOROOT) contains any other. 71 | for _, srcdir := range ctxt.SrcDirs() { 72 | srcdirSlash := filepath.ToSlash(srcdir) + "/" 73 | if importPath, ok := HasSubdir(ctxt, srcdirSlash, dirSlash); ok { 74 | return ctxt.Import(importPath, dir, build.FindOnly) 75 | } 76 | } 77 | 78 | return nil, fmt.Errorf("can't find package containing %s", filename) 79 | } 80 | 81 | // -- Effective methods of file system interface ------------------------- 82 | 83 | // (go/build.Context defines these as methods, but does not export them.) 84 | 85 | // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses 86 | // the local file system to answer the question. 87 | func HasSubdir(ctxt *build.Context, root, dir string) (rel string, ok bool) { 88 | if f := ctxt.HasSubdir; f != nil { 89 | return f(root, dir) 90 | } 91 | 92 | // Try using paths we received. 93 | if rel, ok = hasSubdir(root, dir); ok { 94 | return 95 | } 96 | 97 | // Try expanding symlinks and comparing 98 | // expanded against unexpanded and 99 | // expanded against expanded. 100 | rootSym, _ := filepath.EvalSymlinks(root) 101 | dirSym, _ := filepath.EvalSymlinks(dir) 102 | 103 | if rel, ok = hasSubdir(rootSym, dir); ok { 104 | return 105 | } 106 | if rel, ok = hasSubdir(root, dirSym); ok { 107 | return 108 | } 109 | return hasSubdir(rootSym, dirSym) 110 | } 111 | 112 | func hasSubdir(root, dir string) (rel string, ok bool) { 113 | const sep = string(filepath.Separator) 114 | root = filepath.Clean(root) 115 | if !strings.HasSuffix(root, sep) { 116 | root += sep 117 | } 118 | 119 | dir = filepath.Clean(dir) 120 | if !strings.HasPrefix(dir, root) { 121 | return "", false 122 | } 123 | 124 | return filepath.ToSlash(dir[len(root):]), true 125 | } 126 | 127 | // FileExists returns true if the specified file exists, 128 | // using the build context's file system interface. 129 | func FileExists(ctxt *build.Context, path string) bool { 130 | if ctxt.OpenFile != nil { 131 | r, err := ctxt.OpenFile(path) 132 | if err != nil { 133 | return false 134 | } 135 | r.Close() // ignore error 136 | return true 137 | } 138 | _, err := os.Stat(path) 139 | return err == nil 140 | } 141 | 142 | // OpenFile behaves like os.Open, 143 | // but uses the build context's file system interface, if any. 144 | func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) { 145 | if ctxt.OpenFile != nil { 146 | return ctxt.OpenFile(path) 147 | } 148 | return os.Open(path) 149 | } 150 | 151 | // IsAbsPath behaves like filepath.IsAbs, 152 | // but uses the build context's file system interface, if any. 153 | func IsAbsPath(ctxt *build.Context, path string) bool { 154 | if ctxt.IsAbsPath != nil { 155 | return ctxt.IsAbsPath(path) 156 | } 157 | return filepath.IsAbs(path) 158 | } 159 | 160 | // JoinPath behaves like filepath.Join, 161 | // but uses the build context's file system interface, if any. 162 | func JoinPath(ctxt *build.Context, path ...string) string { 163 | if ctxt.JoinPath != nil { 164 | return ctxt.JoinPath(path...) 165 | } 166 | return filepath.Join(path...) 167 | } 168 | 169 | // IsDir behaves like os.Stat plus IsDir, 170 | // but uses the build context's file system interface, if any. 171 | func IsDir(ctxt *build.Context, path string) bool { 172 | if ctxt.IsDir != nil { 173 | return ctxt.IsDir(path) 174 | } 175 | fi, err := os.Stat(path) 176 | return err == nil && fi.IsDir() 177 | } 178 | 179 | // ReadDir behaves like ioutil.ReadDir, 180 | // but uses the build context's file system interface, if any. 181 | func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) { 182 | if ctxt.ReadDir != nil { 183 | return ctxt.ReadDir(path) 184 | } 185 | return ioutil.ReadDir(path) 186 | } 187 | 188 | // SplitPathList behaves like filepath.SplitList, 189 | // but uses the build context's file system interface, if any. 190 | func SplitPathList(ctxt *build.Context, s string) []string { 191 | if ctxt.SplitPathList != nil { 192 | return ctxt.SplitPathList(s) 193 | } 194 | return filepath.SplitList(s) 195 | } 196 | 197 | // sameFile returns true if x and y have the same basename and denote 198 | // the same file. 199 | // 200 | func sameFile(x, y string) bool { 201 | if path.Clean(x) == path.Clean(y) { 202 | return true 203 | } 204 | if filepath.Base(x) == filepath.Base(y) { // (optimisation) 205 | if xi, err := os.Stat(x); err == nil { 206 | if yi, err := os.Stat(y); err == nil { 207 | return os.SameFile(xi, yi) 208 | } 209 | } 210 | } 211 | return false 212 | } 213 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/expect/expect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | /* 6 | Package expect provides support for interpreting structured comments in Go 7 | source code as test expectations. 8 | 9 | This is primarily intended for writing tests of things that process Go source 10 | files, although it does not directly depend on the testing package. 11 | 12 | Collect notes with the Extract or Parse functions, and use the 13 | MatchBefore function to find matches within the lines the comments were on. 14 | 15 | The interpretation of the notes depends on the application. 16 | For example, the test suite for a static checking tool might 17 | use a @diag note to indicate an expected diagnostic: 18 | 19 | fmt.Printf("%s", 1) //@ diag("%s wants a string, got int") 20 | 21 | By contrast, the test suite for a source code navigation tool 22 | might use notes to indicate the positions of features of 23 | interest, the actions to be performed by the test, 24 | and their expected outcomes: 25 | 26 | var x = 1 //@ x_decl 27 | ... 28 | print(x) //@ definition("x", x_decl) 29 | print(x) //@ typeof("x", "int") 30 | 31 | 32 | Note comment syntax 33 | 34 | Note comments always start with the special marker @, which must be the 35 | very first character after the comment opening pair, so //@ or /*@ with no 36 | spaces. 37 | 38 | This is followed by a comma separated list of notes. 39 | 40 | A note always starts with an identifier, which is optionally followed by an 41 | argument list. The argument list is surrounded with parentheses and contains a 42 | comma-separated list of arguments. 43 | The empty parameter list and the missing parameter list are distinguishable if 44 | needed; they result in a nil or an empty list in the Args parameter respectively. 45 | 46 | Arguments are either identifiers or literals. 47 | The literals supported are the basic value literals, of string, float, integer 48 | true, false or nil. All the literals match the standard go conventions, with 49 | all bases of integers, and both quote and backtick strings. 50 | There is one extra literal type, which is a string literal preceded by the 51 | identifier "re" which is compiled to a regular expression. 52 | */ 53 | package expect 54 | 55 | import ( 56 | "bytes" 57 | "fmt" 58 | "go/token" 59 | "regexp" 60 | ) 61 | 62 | // Note is a parsed note from an expect comment. 63 | // It knows the position of the start of the comment, and the name and 64 | // arguments that make up the note. 65 | type Note struct { 66 | Pos token.Pos // The position at which the note identifier appears 67 | Name string // the name associated with the note 68 | Args []interface{} // the arguments for the note 69 | } 70 | 71 | // ReadFile is the type of a function that can provide file contents for a 72 | // given filename. 73 | // This is used in MatchBefore to look up the content of the file in order to 74 | // find the line to match the pattern against. 75 | type ReadFile func(filename string) ([]byte, error) 76 | 77 | // MatchBefore attempts to match a pattern in the line before the supplied pos. 78 | // It uses the FileSet and the ReadFile to work out the contents of the line 79 | // that end is part of, and then matches the pattern against the content of the 80 | // start of that line up to the supplied position. 81 | // The pattern may be either a simple string, []byte or a *regexp.Regexp. 82 | // MatchBefore returns the range of the line that matched the pattern, and 83 | // invalid positions if there was no match, or an error if the line could not be 84 | // found. 85 | func MatchBefore(fset *token.FileSet, readFile ReadFile, end token.Pos, pattern interface{}) (token.Pos, token.Pos, error) { 86 | f := fset.File(end) 87 | content, err := readFile(f.Name()) 88 | if err != nil { 89 | return token.NoPos, token.NoPos, fmt.Errorf("invalid file: %v", err) 90 | } 91 | position := f.Position(end) 92 | startOffset := f.Offset(lineStart(f, position.Line)) 93 | endOffset := f.Offset(end) 94 | line := content[startOffset:endOffset] 95 | matchStart, matchEnd := -1, -1 96 | switch pattern := pattern.(type) { 97 | case string: 98 | bytePattern := []byte(pattern) 99 | matchStart = bytes.Index(line, bytePattern) 100 | if matchStart >= 0 { 101 | matchEnd = matchStart + len(bytePattern) 102 | } 103 | case []byte: 104 | matchStart = bytes.Index(line, pattern) 105 | if matchStart >= 0 { 106 | matchEnd = matchStart + len(pattern) 107 | } 108 | case *regexp.Regexp: 109 | match := pattern.FindIndex(line) 110 | if len(match) > 0 { 111 | matchStart = match[0] 112 | matchEnd = match[1] 113 | } 114 | } 115 | if matchStart < 0 { 116 | return token.NoPos, token.NoPos, nil 117 | } 118 | return f.Pos(startOffset + matchStart), f.Pos(startOffset + matchEnd), nil 119 | } 120 | 121 | // this functionality was borrowed from the analysisutil package 122 | func lineStart(f *token.File, line int) token.Pos { 123 | // Use binary search to find the start offset of this line. 124 | // 125 | // TODO(adonovan): eventually replace this function with the 126 | // simpler and more efficient (*go/token.File).LineStart, added 127 | // in go1.12. 128 | 129 | min := 0 // inclusive 130 | max := f.Size() // exclusive 131 | for { 132 | offset := (min + max) / 2 133 | pos := f.Pos(offset) 134 | posn := f.Position(pos) 135 | if posn.Line == line { 136 | return pos - (token.Pos(posn.Column) - 1) 137 | } 138 | 139 | if min+1 >= max { 140 | return token.NoPos 141 | } 142 | 143 | if posn.Line < line { 144 | min = offset 145 | } else { 146 | max = offset 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/expect/extract.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 expect 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "go/token" 12 | "regexp" 13 | "strconv" 14 | "strings" 15 | "text/scanner" 16 | ) 17 | 18 | const ( 19 | commentStart = "@" 20 | ) 21 | 22 | // Identifier is the type for an identifier in an Note argument list. 23 | type Identifier string 24 | 25 | // Parse collects all the notes present in a file. 26 | // If content is nil, the filename specified is read and parsed, otherwise the 27 | // content is used and the filename is used for positions and error messages. 28 | // Each comment whose text starts with @ is parsed as a comma-separated 29 | // sequence of notes. 30 | // See the package documentation for details about the syntax of those 31 | // notes. 32 | func Parse(fset *token.FileSet, filename string, content []byte) ([]*Note, error) { 33 | var src interface{} 34 | if content != nil { 35 | src = content 36 | } 37 | // TODO: We should write this in terms of the scanner. 38 | // there are ways you can break the parser such that it will not add all the 39 | // comments to the ast, which may result in files where the tests are silently 40 | // not run. 41 | file, err := parser.ParseFile(fset, filename, src, parser.ParseComments) 42 | if file == nil { 43 | return nil, err 44 | } 45 | return Extract(fset, file) 46 | } 47 | 48 | // Extract collects all the notes present in an AST. 49 | // Each comment whose text starts with @ is parsed as a comma-separated 50 | // sequence of notes. 51 | // See the package documentation for details about the syntax of those 52 | // notes. 53 | func Extract(fset *token.FileSet, file *ast.File) ([]*Note, error) { 54 | var notes []*Note 55 | for _, g := range file.Comments { 56 | for _, c := range g.List { 57 | text := c.Text 58 | if strings.HasPrefix(text, "/*") { 59 | text = strings.TrimSuffix(text, "*/") 60 | } 61 | text = text[2:] // remove "//" or "/*" prefix 62 | if !strings.HasPrefix(text, commentStart) { 63 | continue 64 | } 65 | text = text[len(commentStart):] 66 | parsed, err := parse(fset, c.Pos()+4, text) 67 | if err != nil { 68 | return nil, err 69 | } 70 | notes = append(notes, parsed...) 71 | } 72 | } 73 | return notes, nil 74 | } 75 | 76 | const invalidToken rune = 0 77 | 78 | type tokens struct { 79 | scanner scanner.Scanner 80 | current rune 81 | err error 82 | base token.Pos 83 | } 84 | 85 | func (t *tokens) Init(base token.Pos, text string) *tokens { 86 | t.base = base 87 | t.scanner.Init(strings.NewReader(text)) 88 | t.scanner.Mode = scanner.GoTokens 89 | t.scanner.Whitespace ^= 1 << '\n' // don't skip new lines 90 | t.scanner.Error = func(s *scanner.Scanner, msg string) { 91 | t.Errorf("%v", msg) 92 | } 93 | return t 94 | } 95 | 96 | func (t *tokens) Consume() string { 97 | t.current = invalidToken 98 | return t.scanner.TokenText() 99 | } 100 | 101 | func (t *tokens) Token() rune { 102 | if t.err != nil { 103 | return scanner.EOF 104 | } 105 | if t.current == invalidToken { 106 | t.current = t.scanner.Scan() 107 | } 108 | return t.current 109 | } 110 | 111 | func (t *tokens) Skip(r rune) int { 112 | i := 0 113 | for t.Token() == '\n' { 114 | t.Consume() 115 | i++ 116 | } 117 | return i 118 | } 119 | 120 | func (t *tokens) TokenString() string { 121 | return scanner.TokenString(t.Token()) 122 | } 123 | 124 | func (t *tokens) Pos() token.Pos { 125 | return t.base + token.Pos(t.scanner.Position.Offset) 126 | } 127 | 128 | func (t *tokens) Errorf(msg string, args ...interface{}) { 129 | if t.err != nil { 130 | return 131 | } 132 | t.err = fmt.Errorf(msg, args...) 133 | } 134 | 135 | func parse(fset *token.FileSet, base token.Pos, text string) ([]*Note, error) { 136 | t := new(tokens).Init(base, text) 137 | notes := parseComment(t) 138 | if t.err != nil { 139 | return nil, fmt.Errorf("%v:%s", fset.Position(t.Pos()), t.err) 140 | } 141 | return notes, nil 142 | } 143 | 144 | func parseComment(t *tokens) []*Note { 145 | var notes []*Note 146 | for { 147 | t.Skip('\n') 148 | switch t.Token() { 149 | case scanner.EOF: 150 | return notes 151 | case scanner.Ident: 152 | notes = append(notes, parseNote(t)) 153 | default: 154 | t.Errorf("unexpected %s parsing comment, expect identifier", t.TokenString()) 155 | return nil 156 | } 157 | switch t.Token() { 158 | case scanner.EOF: 159 | return notes 160 | case ',', '\n': 161 | t.Consume() 162 | default: 163 | t.Errorf("unexpected %s parsing comment, expect separator", t.TokenString()) 164 | return nil 165 | } 166 | } 167 | } 168 | 169 | func parseNote(t *tokens) *Note { 170 | n := &Note{ 171 | Pos: t.Pos(), 172 | Name: t.Consume(), 173 | } 174 | 175 | switch t.Token() { 176 | case ',', '\n', scanner.EOF: 177 | // no argument list present 178 | return n 179 | case '(': 180 | n.Args = parseArgumentList(t) 181 | return n 182 | default: 183 | t.Errorf("unexpected %s parsing note", t.TokenString()) 184 | return nil 185 | } 186 | } 187 | 188 | func parseArgumentList(t *tokens) []interface{} { 189 | args := []interface{}{} // @name() is represented by a non-nil empty slice. 190 | t.Consume() // '(' 191 | t.Skip('\n') 192 | for t.Token() != ')' { 193 | args = append(args, parseArgument(t)) 194 | if t.Token() != ',' { 195 | break 196 | } 197 | t.Consume() 198 | t.Skip('\n') 199 | } 200 | if t.Token() != ')' { 201 | t.Errorf("unexpected %s parsing argument list", t.TokenString()) 202 | return nil 203 | } 204 | t.Consume() // ')' 205 | return args 206 | } 207 | 208 | func parseArgument(t *tokens) interface{} { 209 | switch t.Token() { 210 | case scanner.Ident: 211 | v := t.Consume() 212 | switch v { 213 | case "true": 214 | return true 215 | case "false": 216 | return false 217 | case "nil": 218 | return nil 219 | case "re": 220 | if t.Token() != scanner.String && t.Token() != scanner.RawString { 221 | t.Errorf("re must be followed by string, got %s", t.TokenString()) 222 | return nil 223 | } 224 | pattern, _ := strconv.Unquote(t.Consume()) // can't fail 225 | re, err := regexp.Compile(pattern) 226 | if err != nil { 227 | t.Errorf("invalid regular expression %s: %v", pattern, err) 228 | return nil 229 | } 230 | return re 231 | default: 232 | return Identifier(v) 233 | } 234 | 235 | case scanner.String, scanner.RawString: 236 | v, _ := strconv.Unquote(t.Consume()) // can't fail 237 | return v 238 | 239 | case scanner.Int: 240 | s := t.Consume() 241 | v, err := strconv.ParseInt(s, 0, 0) 242 | if err != nil { 243 | t.Errorf("cannot convert %v to int: %v", s, err) 244 | } 245 | return v 246 | 247 | case scanner.Float: 248 | s := t.Consume() 249 | v, err := strconv.ParseFloat(s, 64) 250 | if err != nil { 251 | t.Errorf("cannot convert %v to float: %v", s, err) 252 | } 253 | return v 254 | 255 | case scanner.Char: 256 | t.Errorf("unexpected char literal %s", t.Consume()) 257 | return nil 258 | 259 | default: 260 | t.Errorf("unexpected %s parsing argument", t.TokenString()) 261 | return nil 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 gcexportdata provides functions for locating, reading, and 6 | // writing export data files containing type information produced by the 7 | // gc compiler. This package supports go1.7 export data format and all 8 | // later versions. 9 | // 10 | // Although it might seem convenient for this package to live alongside 11 | // go/types in the standard library, this would cause version skew 12 | // problems for developer tools that use it, since they must be able to 13 | // consume the outputs of the gc compiler both before and after a Go 14 | // update such as from Go 1.7 to Go 1.8. Because this package lives in 15 | // golang.org/x/tools, sites can update their version of this repo some 16 | // time before the Go 1.8 release and rebuild and redeploy their 17 | // developer tools, which will then be able to consume both Go 1.7 and 18 | // Go 1.8 export data files, so they will work before and after the 19 | // Go update. (See discussion at https://golang.org/issue/15651.) 20 | // 21 | package gcexportdata // import "golang.org/x/tools/go/gcexportdata" 22 | 23 | import ( 24 | "bufio" 25 | "bytes" 26 | "fmt" 27 | "go/token" 28 | "go/types" 29 | "io" 30 | "io/ioutil" 31 | 32 | "golang.org/x/tools/go/internal/gcimporter" 33 | ) 34 | 35 | // Find returns the name of an object (.o) or archive (.a) file 36 | // containing type information for the specified import path, 37 | // using the workspace layout conventions of go/build. 38 | // If no file was found, an empty filename is returned. 39 | // 40 | // A relative srcDir is interpreted relative to the current working directory. 41 | // 42 | // Find also returns the package's resolved (canonical) import path, 43 | // reflecting the effects of srcDir and vendoring on importPath. 44 | func Find(importPath, srcDir string) (filename, path string) { 45 | return gcimporter.FindPkg(importPath, srcDir) 46 | } 47 | 48 | // NewReader returns a reader for the export data section of an object 49 | // (.o) or archive (.a) file read from r. The new reader may provide 50 | // additional trailing data beyond the end of the export data. 51 | func NewReader(r io.Reader) (io.Reader, error) { 52 | buf := bufio.NewReader(r) 53 | _, err := gcimporter.FindExportData(buf) 54 | // If we ever switch to a zip-like archive format with the ToC 55 | // at the end, we can return the correct portion of export data, 56 | // but for now we must return the entire rest of the file. 57 | return buf, err 58 | } 59 | 60 | // Read reads export data from in, decodes it, and returns type 61 | // information for the package. 62 | // The package name is specified by path. 63 | // File position information is added to fset. 64 | // 65 | // Read may inspect and add to the imports map to ensure that references 66 | // within the export data to other packages are consistent. The caller 67 | // must ensure that imports[path] does not exist, or exists but is 68 | // incomplete (see types.Package.Complete), and Read inserts the 69 | // resulting package into this map entry. 70 | // 71 | // On return, the state of the reader is undefined. 72 | func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { 73 | data, err := ioutil.ReadAll(in) 74 | if err != nil { 75 | return nil, fmt.Errorf("reading export data for %q: %v", path, err) 76 | } 77 | 78 | if bytes.HasPrefix(data, []byte("!")) { 79 | return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path) 80 | } 81 | 82 | // The App Engine Go runtime v1.6 uses the old export data format. 83 | // TODO(adonovan): delete once v1.7 has been around for a while. 84 | if bytes.HasPrefix(data, []byte("package ")) { 85 | return gcimporter.ImportData(imports, path, path, bytes.NewReader(data)) 86 | } 87 | 88 | // The indexed export format starts with an 'i'; the older 89 | // binary export format starts with a 'c', 'd', or 'v' 90 | // (from "version"). Select appropriate importer. 91 | if len(data) > 0 && data[0] == 'i' { 92 | _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) 93 | return pkg, err 94 | } 95 | 96 | _, pkg, err := gcimporter.BImportData(fset, imports, data, path) 97 | return pkg, err 98 | } 99 | 100 | // Write writes encoded type information for the specified package to out. 101 | // The FileSet provides file position information for named objects. 102 | func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error { 103 | b, err := gcimporter.BExportData(fset, pkg) 104 | if err != nil { 105 | return err 106 | } 107 | _, err = out.Write(b) 108 | return err 109 | } 110 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/gcexportdata/importer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 gcexportdata 6 | 7 | import ( 8 | "fmt" 9 | "go/token" 10 | "go/types" 11 | "os" 12 | ) 13 | 14 | // NewImporter returns a new instance of the types.Importer interface 15 | // that reads type information from export data files written by gc. 16 | // The Importer also satisfies types.ImporterFrom. 17 | // 18 | // Export data files are located using "go build" workspace conventions 19 | // and the build.Default context. 20 | // 21 | // Use this importer instead of go/importer.For("gc", ...) to avoid the 22 | // version-skew problems described in the documentation of this package, 23 | // or to control the FileSet or access the imports map populated during 24 | // package loading. 25 | // 26 | func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom { 27 | return importer{fset, imports} 28 | } 29 | 30 | type importer struct { 31 | fset *token.FileSet 32 | imports map[string]*types.Package 33 | } 34 | 35 | func (imp importer) Import(importPath string) (*types.Package, error) { 36 | return imp.ImportFrom(importPath, "", 0) 37 | } 38 | 39 | func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) { 40 | filename, path := Find(importPath, srcDir) 41 | if filename == "" { 42 | if importPath == "unsafe" { 43 | // Even for unsafe, call Find first in case 44 | // the package was vendored. 45 | return types.Unsafe, nil 46 | } 47 | return nil, fmt.Errorf("can't find import: %s", importPath) 48 | } 49 | 50 | if pkg, ok := imp.imports[path]; ok && pkg.Complete() { 51 | return pkg, nil // cache hit 52 | } 53 | 54 | // open file 55 | f, err := os.Open(filename) 56 | if err != nil { 57 | return nil, err 58 | } 59 | defer func() { 60 | f.Close() 61 | if err != nil { 62 | // add file name to error 63 | err = fmt.Errorf("reading export data: %s: %v", filename, err) 64 | } 65 | }() 66 | 67 | r, err := NewReader(f) 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | return Read(r, imp.fset, imp.imports, path) 73 | } 74 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/gcexportdata/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 | // +build ignore 6 | 7 | // The gcexportdata command is a diagnostic tool that displays the 8 | // contents of gc export data files. 9 | package main 10 | 11 | import ( 12 | "flag" 13 | "fmt" 14 | "go/token" 15 | "go/types" 16 | "log" 17 | "os" 18 | 19 | "golang.org/x/tools/go/gcexportdata" 20 | "golang.org/x/tools/go/types/typeutil" 21 | ) 22 | 23 | var packageFlag = flag.String("package", "", "alternative package to print") 24 | 25 | func main() { 26 | log.SetPrefix("gcexportdata: ") 27 | log.SetFlags(0) 28 | flag.Usage = func() { 29 | fmt.Fprintln(os.Stderr, "usage: gcexportdata [-package path] file.a") 30 | } 31 | flag.Parse() 32 | if flag.NArg() != 1 { 33 | flag.Usage() 34 | os.Exit(2) 35 | } 36 | filename := flag.Args()[0] 37 | 38 | f, err := os.Open(filename) 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | 43 | r, err := gcexportdata.NewReader(f) 44 | if err != nil { 45 | log.Fatalf("%s: %s", filename, err) 46 | } 47 | 48 | // Decode the package. 49 | const primary = "" 50 | imports := make(map[string]*types.Package) 51 | fset := token.NewFileSet() 52 | pkg, err := gcexportdata.Read(r, fset, imports, primary) 53 | if err != nil { 54 | log.Fatalf("%s: %s", filename, err) 55 | } 56 | 57 | // Optionally select an indirectly mentioned package. 58 | if *packageFlag != "" { 59 | pkg = imports[*packageFlag] 60 | if pkg == nil { 61 | fmt.Fprintf(os.Stderr, "export data file %s does not mention %s; has:\n", 62 | filename, *packageFlag) 63 | for p := range imports { 64 | if p != primary { 65 | fmt.Fprintf(os.Stderr, "\t%s\n", p) 66 | } 67 | } 68 | os.Exit(1) 69 | } 70 | } 71 | 72 | // Print all package-level declarations, including non-exported ones. 73 | fmt.Printf("package %s\n", pkg.Name()) 74 | for _, imp := range pkg.Imports() { 75 | fmt.Printf("import %q\n", imp.Path()) 76 | } 77 | qual := func(p *types.Package) string { 78 | if pkg == p { 79 | return "" 80 | } 81 | return p.Name() 82 | } 83 | scope := pkg.Scope() 84 | for _, name := range scope.Names() { 85 | obj := scope.Lookup(name) 86 | fmt.Printf("%s: %s\n", 87 | fset.Position(obj.Pos()), 88 | types.ObjectString(obj, qual)) 89 | 90 | // For types, print each method. 91 | if _, ok := obj.(*types.TypeName); ok { 92 | for _, method := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { 93 | fmt.Printf("%s: %s\n", 94 | fset.Position(method.Obj().Pos()), 95 | types.SelectionString(method, qual)) 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/internal/cgo/cgo.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 | package cgo 6 | 7 | // This file handles cgo preprocessing of files containing `import "C"`. 8 | // 9 | // DESIGN 10 | // 11 | // The approach taken is to run the cgo processor on the package's 12 | // CgoFiles and parse the output, faking the filenames of the 13 | // resulting ASTs so that the synthetic file containing the C types is 14 | // called "C" (e.g. "~/go/src/net/C") and the preprocessed files 15 | // have their original names (e.g. "~/go/src/net/cgo_unix.go"), 16 | // not the names of the actual temporary files. 17 | // 18 | // The advantage of this approach is its fidelity to 'go build'. The 19 | // downside is that the token.Position.Offset for each AST node is 20 | // incorrect, being an offset within the temporary file. Line numbers 21 | // should still be correct because of the //line comments. 22 | // 23 | // The logic of this file is mostly plundered from the 'go build' 24 | // tool, which also invokes the cgo preprocessor. 25 | // 26 | // 27 | // REJECTED ALTERNATIVE 28 | // 29 | // An alternative approach that we explored is to extend go/types' 30 | // Importer mechanism to provide the identity of the importing package 31 | // so that each time `import "C"` appears it resolves to a different 32 | // synthetic package containing just the objects needed in that case. 33 | // The loader would invoke cgo but parse only the cgo_types.go file 34 | // defining the package-level objects, discarding the other files 35 | // resulting from preprocessing. 36 | // 37 | // The benefit of this approach would have been that source-level 38 | // syntax information would correspond exactly to the original cgo 39 | // file, with no preprocessing involved, making source tools like 40 | // godoc, guru, and eg happy. However, the approach was rejected 41 | // due to the additional complexity it would impose on go/types. (It 42 | // made for a beautiful demo, though.) 43 | // 44 | // cgo files, despite their *.go extension, are not legal Go source 45 | // files per the specification since they may refer to unexported 46 | // members of package "C" such as C.int. Also, a function such as 47 | // C.getpwent has in effect two types, one matching its C type and one 48 | // which additionally returns (errno C.int). The cgo preprocessor 49 | // uses name mangling to distinguish these two functions in the 50 | // processed code, but go/types would need to duplicate this logic in 51 | // its handling of function calls, analogous to the treatment of map 52 | // lookups in which y=m[k] and y,ok=m[k] are both legal. 53 | 54 | import ( 55 | "fmt" 56 | "go/ast" 57 | "go/build" 58 | "go/parser" 59 | "go/token" 60 | "io/ioutil" 61 | "log" 62 | "os" 63 | "os/exec" 64 | "path/filepath" 65 | "regexp" 66 | "strings" 67 | ) 68 | 69 | // ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses 70 | // the output and returns the resulting ASTs. 71 | // 72 | func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) { 73 | tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C") 74 | if err != nil { 75 | return nil, err 76 | } 77 | defer os.RemoveAll(tmpdir) 78 | 79 | pkgdir := bp.Dir 80 | if DisplayPath != nil { 81 | pkgdir = DisplayPath(pkgdir) 82 | } 83 | 84 | cgoFiles, cgoDisplayFiles, err := Run(bp, pkgdir, tmpdir, false) 85 | if err != nil { 86 | return nil, err 87 | } 88 | var files []*ast.File 89 | for i := range cgoFiles { 90 | rd, err := os.Open(cgoFiles[i]) 91 | if err != nil { 92 | return nil, err 93 | } 94 | display := filepath.Join(bp.Dir, cgoDisplayFiles[i]) 95 | f, err := parser.ParseFile(fset, display, rd, mode) 96 | rd.Close() 97 | if err != nil { 98 | return nil, err 99 | } 100 | files = append(files, f) 101 | } 102 | return files, nil 103 | } 104 | 105 | var cgoRe = regexp.MustCompile(`[/\\:]`) 106 | 107 | // Run invokes the cgo preprocessor on bp.CgoFiles and returns two 108 | // lists of files: the resulting processed files (in temporary 109 | // directory tmpdir) and the corresponding names of the unprocessed files. 110 | // 111 | // Run is adapted from (*builder).cgo in 112 | // $GOROOT/src/cmd/go/build.go, but these features are unsupported: 113 | // Objective C, CGOPKGPATH, CGO_FLAGS. 114 | // 115 | // If useabs is set to true, absolute paths of the bp.CgoFiles will be passed in 116 | // to the cgo preprocessor. This in turn will set the // line comments 117 | // referring to those files to use absolute paths. This is needed for 118 | // go/packages using the legacy go list support so it is able to find 119 | // the original files. 120 | func Run(bp *build.Package, pkgdir, tmpdir string, useabs bool) (files, displayFiles []string, err error) { 121 | cgoCPPFLAGS, _, _, _ := cflags(bp, true) 122 | _, cgoexeCFLAGS, _, _ := cflags(bp, false) 123 | 124 | if len(bp.CgoPkgConfig) > 0 { 125 | pcCFLAGS, err := pkgConfigFlags(bp) 126 | if err != nil { 127 | return nil, nil, err 128 | } 129 | cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) 130 | } 131 | 132 | // Allows including _cgo_export.h from .[ch] files in the package. 133 | cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir) 134 | 135 | // _cgo_gotypes.go (displayed "C") contains the type definitions. 136 | files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go")) 137 | displayFiles = append(displayFiles, "C") 138 | for _, fn := range bp.CgoFiles { 139 | // "foo.cgo1.go" (displayed "foo.go") is the processed Go source. 140 | f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_") 141 | files = append(files, filepath.Join(tmpdir, f+"cgo1.go")) 142 | displayFiles = append(displayFiles, fn) 143 | } 144 | 145 | var cgoflags []string 146 | if bp.Goroot && bp.ImportPath == "runtime/cgo" { 147 | cgoflags = append(cgoflags, "-import_runtime_cgo=false") 148 | } 149 | if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" { 150 | cgoflags = append(cgoflags, "-import_syscall=false") 151 | } 152 | 153 | var cgoFiles []string = bp.CgoFiles 154 | if useabs { 155 | cgoFiles = make([]string, len(bp.CgoFiles)) 156 | for i := range cgoFiles { 157 | cgoFiles[i] = filepath.Join(pkgdir, bp.CgoFiles[i]) 158 | } 159 | } 160 | 161 | args := stringList( 162 | "go", "tool", "cgo", "-objdir", tmpdir, cgoflags, "--", 163 | cgoCPPFLAGS, cgoexeCFLAGS, cgoFiles, 164 | ) 165 | if false { 166 | log.Printf("Running cgo for package %q: %s (dir=%s)", bp.ImportPath, args, pkgdir) 167 | } 168 | cmd := exec.Command(args[0], args[1:]...) 169 | cmd.Dir = pkgdir 170 | cmd.Stdout = os.Stderr 171 | cmd.Stderr = os.Stderr 172 | if err := cmd.Run(); err != nil { 173 | return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err) 174 | } 175 | 176 | return files, displayFiles, nil 177 | } 178 | 179 | // -- unmodified from 'go build' --------------------------------------- 180 | 181 | // Return the flags to use when invoking the C or C++ compilers, or cgo. 182 | func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) { 183 | var defaults string 184 | if def { 185 | defaults = "-g -O2" 186 | } 187 | 188 | cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) 189 | cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) 190 | cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) 191 | ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) 192 | return 193 | } 194 | 195 | // envList returns the value of the given environment variable broken 196 | // into fields, using the default value when the variable is empty. 197 | func envList(key, def string) []string { 198 | v := os.Getenv(key) 199 | if v == "" { 200 | v = def 201 | } 202 | return strings.Fields(v) 203 | } 204 | 205 | // stringList's arguments should be a sequence of string or []string values. 206 | // stringList flattens them into a single []string. 207 | func stringList(args ...interface{}) []string { 208 | var x []string 209 | for _, arg := range args { 210 | switch arg := arg.(type) { 211 | case []string: 212 | x = append(x, arg...) 213 | case string: 214 | x = append(x, arg) 215 | default: 216 | panic("stringList: invalid argument") 217 | } 218 | } 219 | return x 220 | } 221 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.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 | package cgo 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "go/build" 11 | "os/exec" 12 | "strings" 13 | ) 14 | 15 | // pkgConfig runs pkg-config with the specified arguments and returns the flags it prints. 16 | func pkgConfig(mode string, pkgs []string) (flags []string, err error) { 17 | cmd := exec.Command("pkg-config", append([]string{mode}, pkgs...)...) 18 | out, err := cmd.CombinedOutput() 19 | if err != nil { 20 | s := fmt.Sprintf("%s failed: %v", strings.Join(cmd.Args, " "), err) 21 | if len(out) > 0 { 22 | s = fmt.Sprintf("%s: %s", s, out) 23 | } 24 | return nil, errors.New(s) 25 | } 26 | if len(out) > 0 { 27 | flags = strings.Fields(string(out)) 28 | } 29 | return 30 | } 31 | 32 | // pkgConfigFlags calls pkg-config if needed and returns the cflags 33 | // needed to build the package. 34 | func pkgConfigFlags(p *build.Package) (cflags []string, err error) { 35 | if len(p.CgoPkgConfig) == 0 { 36 | return nil, nil 37 | } 38 | return pkgConfig("--cflags", p.CgoPkgConfig) 39 | } 40 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go: -------------------------------------------------------------------------------- 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 | // This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go. 6 | 7 | // This file implements FindExportData. 8 | 9 | package gcimporter 10 | 11 | import ( 12 | "bufio" 13 | "fmt" 14 | "io" 15 | "strconv" 16 | "strings" 17 | ) 18 | 19 | func readGopackHeader(r *bufio.Reader) (name string, size int, err error) { 20 | // See $GOROOT/include/ar.h. 21 | hdr := make([]byte, 16+12+6+6+8+10+2) 22 | _, err = io.ReadFull(r, hdr) 23 | if err != nil { 24 | return 25 | } 26 | // leave for debugging 27 | if false { 28 | fmt.Printf("header: %s", hdr) 29 | } 30 | s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) 31 | size, err = strconv.Atoi(s) 32 | if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { 33 | err = fmt.Errorf("invalid archive header") 34 | return 35 | } 36 | name = strings.TrimSpace(string(hdr[:16])) 37 | return 38 | } 39 | 40 | // FindExportData positions the reader r at the beginning of the 41 | // export data section of an underlying GC-created object/archive 42 | // file by reading from it. The reader must be positioned at the 43 | // start of the file before calling this function. The hdr result 44 | // is the string before the export data, either "$$" or "$$B". 45 | // 46 | func FindExportData(r *bufio.Reader) (hdr string, err error) { 47 | // Read first line to make sure this is an object file. 48 | line, err := r.ReadSlice('\n') 49 | if err != nil { 50 | err = fmt.Errorf("can't find export data (%v)", err) 51 | return 52 | } 53 | 54 | if string(line) == "!\n" { 55 | // Archive file. Scan to __.PKGDEF. 56 | var name string 57 | if name, _, err = readGopackHeader(r); err != nil { 58 | return 59 | } 60 | 61 | // First entry should be __.PKGDEF. 62 | if name != "__.PKGDEF" { 63 | err = fmt.Errorf("go archive is missing __.PKGDEF") 64 | return 65 | } 66 | 67 | // Read first line of __.PKGDEF data, so that line 68 | // is once again the first line of the input. 69 | if line, err = r.ReadSlice('\n'); err != nil { 70 | err = fmt.Errorf("can't find export data (%v)", err) 71 | return 72 | } 73 | } 74 | 75 | // Now at __.PKGDEF in archive or still at beginning of file. 76 | // Either way, line should begin with "go object ". 77 | if !strings.HasPrefix(string(line), "go object ") { 78 | err = fmt.Errorf("not a Go object file") 79 | return 80 | } 81 | 82 | // Skip over object header to export data. 83 | // Begins after first line starting with $$. 84 | for line[0] != '$' { 85 | if line, err = r.ReadSlice('\n'); err != nil { 86 | err = fmt.Errorf("can't find export data (%v)", err) 87 | return 88 | } 89 | } 90 | hdr = string(line) 91 | 92 | return 93 | } 94 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // +build !go1.11 6 | 7 | package gcimporter 8 | 9 | import "go/types" 10 | 11 | func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { 12 | named := make([]*types.Named, len(embeddeds)) 13 | for i, e := range embeddeds { 14 | var ok bool 15 | named[i], ok = e.(*types.Named) 16 | if !ok { 17 | panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11") 18 | } 19 | } 20 | return types.NewInterface(methods, named) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // +build go1.11 6 | 7 | package gcimporter 8 | 9 | import "go/types" 10 | 11 | func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { 12 | return types.NewInterfaceType(methods, embeddeds) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | /* 6 | Package packages loads Go packages for inspection and analysis. 7 | 8 | Note: Though this package is ready for widespread use, we may make minor 9 | breaking changes if absolutely necessary. Any such change will be 10 | announced on golang-tools@ at least one week before it is committed. No 11 | more breaking changes will be made after December 1, 2018. 12 | 13 | The Load function takes as input a list of patterns and return a list of Package 14 | structs describing individual packages matched by those patterns. 15 | The LoadMode controls the amount of detail in the loaded packages. 16 | 17 | Load passes most patterns directly to the underlying build tool, 18 | but all patterns with the prefix "query=", where query is a 19 | non-empty string of letters from [a-z], are reserved and may be 20 | interpreted as query operators. 21 | 22 | Only two query operators are currently supported, "file" and "pattern". 23 | 24 | The query "file=path/to/file.go" matches the package or packages enclosing 25 | the Go source file path/to/file.go. For example "file=~/go/src/fmt/print.go" 26 | might returns the packages "fmt" and "fmt [fmt.test]". 27 | 28 | The query "pattern=string" causes "string" to be passed directly to 29 | the underlying build tool. In most cases this is unnecessary, 30 | but an application can use Load("pattern=" + x) as an escaping mechanism 31 | to ensure that x is not interpreted as a query operator if it contains '='. 32 | 33 | A third query "name=identifier" will be added soon. 34 | It will match packages whose package declaration contains the specified identifier. 35 | For example, "name=rand" would match the packages "math/rand" and "crypto/rand", 36 | and "name=main" would match all executables. 37 | 38 | All other query operators are reserved for future use and currently 39 | cause Load to report an error. 40 | 41 | The Package struct provides basic information about the package, including 42 | 43 | - ID, a unique identifier for the package in the returned set; 44 | - GoFiles, the names of the package's Go source files; 45 | - Imports, a map from source import strings to the Packages they name; 46 | - Types, the type information for the package's exported symbols; 47 | - Syntax, the parsed syntax trees for the package's source code; and 48 | - TypeInfo, the result of a complete type-check of the package syntax trees. 49 | 50 | (See the documentation for type Package for the complete list of fields 51 | and more detailed descriptions.) 52 | 53 | For example, 54 | 55 | Load(nil, "bytes", "unicode...") 56 | 57 | returns four Package structs describing the standard library packages 58 | bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern 59 | can match multiple packages and that a package might be matched by 60 | multiple patterns: in general it is not possible to determine which 61 | packages correspond to which patterns. 62 | 63 | Note that the list returned by Load contains only the packages matched 64 | by the patterns. Their dependencies can be found by walking the import 65 | graph using the Imports fields. 66 | 67 | The Load function can be configured by passing a pointer to a Config as 68 | the first argument. A nil Config is equivalent to the zero Config, which 69 | causes Load to run in LoadFiles mode, collecting minimal information. 70 | See the documentation for type Config for details. 71 | 72 | As noted earlier, the Config.Mode controls the amount of detail 73 | reported about the loaded packages, with each mode returning all the data of the 74 | previous mode with some extra added. See the documentation for type LoadMode 75 | for details. 76 | 77 | Most tools should pass their command-line arguments (after any flags) 78 | uninterpreted to the loader, so that the loader can interpret them 79 | according to the conventions of the underlying build system. 80 | See the Example function for typical usage. 81 | 82 | */ 83 | package packages // import "golang.org/x/tools/go/packages" 84 | 85 | /* 86 | 87 | Motivation and design considerations 88 | 89 | The new package's design solves problems addressed by two existing 90 | packages: go/build, which locates and describes packages, and 91 | golang.org/x/tools/go/loader, which loads, parses and type-checks them. 92 | The go/build.Package structure encodes too much of the 'go build' way 93 | of organizing projects, leaving us in need of a data type that describes a 94 | package of Go source code independent of the underlying build system. 95 | We wanted something that works equally well with go build and vgo, and 96 | also other build systems such as Bazel and Blaze, making it possible to 97 | construct analysis tools that work in all these environments. 98 | Tools such as errcheck and staticcheck were essentially unavailable to 99 | the Go community at Google, and some of Google's internal tools for Go 100 | are unavailable externally. 101 | This new package provides a uniform way to obtain package metadata by 102 | querying each of these build systems, optionally supporting their 103 | preferred command-line notations for packages, so that tools integrate 104 | neatly with users' build environments. The Metadata query function 105 | executes an external query tool appropriate to the current workspace. 106 | 107 | Loading packages always returns the complete import graph "all the way down", 108 | even if all you want is information about a single package, because the query 109 | mechanisms of all the build systems we currently support ({go,vgo} list, and 110 | blaze/bazel aspect-based query) cannot provide detailed information 111 | about one package without visiting all its dependencies too, so there is 112 | no additional asymptotic cost to providing transitive information. 113 | (This property might not be true of a hypothetical 5th build system.) 114 | 115 | In calls to TypeCheck, all initial packages, and any package that 116 | transitively depends on one of them, must be loaded from source. 117 | Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from 118 | source; D may be loaded from export data, and E may not be loaded at all 119 | (though it's possible that D's export data mentions it, so a 120 | types.Package may be created for it and exposed.) 121 | 122 | The old loader had a feature to suppress type-checking of function 123 | bodies on a per-package basis, primarily intended to reduce the work of 124 | obtaining type information for imported packages. Now that imports are 125 | satisfied by export data, the optimization no longer seems necessary. 126 | 127 | Despite some early attempts, the old loader did not exploit export data, 128 | instead always using the equivalent of WholeProgram mode. This was due 129 | to the complexity of mixing source and export data packages (now 130 | resolved by the upward traversal mentioned above), and because export data 131 | files were nearly always missing or stale. Now that 'go build' supports 132 | caching, all the underlying build systems can guarantee to produce 133 | export data in a reasonable (amortized) time. 134 | 135 | Test "main" packages synthesized by the build system are now reported as 136 | first-class packages, avoiding the need for clients (such as go/ssa) to 137 | reinvent this generation logic. 138 | 139 | One way in which go/packages is simpler than the old loader is in its 140 | treatment of in-package tests. In-package tests are packages that 141 | consist of all the files of the library under test, plus the test files. 142 | The old loader constructed in-package tests by a two-phase process of 143 | mutation called "augmentation": first it would construct and type check 144 | all the ordinary library packages and type-check the packages that 145 | depend on them; then it would add more (test) files to the package and 146 | type-check again. This two-phase approach had four major problems: 147 | 1) in processing the tests, the loader modified the library package, 148 | leaving no way for a client application to see both the test 149 | package and the library package; one would mutate into the other. 150 | 2) because test files can declare additional methods on types defined in 151 | the library portion of the package, the dispatch of method calls in 152 | the library portion was affected by the presence of the test files. 153 | This should have been a clue that the packages were logically 154 | different. 155 | 3) this model of "augmentation" assumed at most one in-package test 156 | per library package, which is true of projects using 'go build', 157 | but not other build systems. 158 | 4) because of the two-phase nature of test processing, all packages that 159 | import the library package had to be processed before augmentation, 160 | forcing a "one-shot" API and preventing the client from calling Load 161 | in several times in sequence as is now possible in WholeProgram mode. 162 | (TypeCheck mode has a similar one-shot restriction for a different reason.) 163 | 164 | Early drafts of this package supported "multi-shot" operation. 165 | Although it allowed clients to make a sequence of calls (or concurrent 166 | calls) to Load, building up the graph of Packages incrementally, 167 | it was of marginal value: it complicated the API 168 | (since it allowed some options to vary across calls but not others), 169 | it complicated the implementation, 170 | it cannot be made to work in Types mode, as explained above, 171 | and it was less efficient than making one combined call (when this is possible). 172 | Among the clients we have inspected, none made multiple calls to load 173 | but could not be easily and satisfactorily modified to make only a single call. 174 | However, applications changes may be required. 175 | For example, the ssadump command loads the user-specified packages 176 | and in addition the runtime package. It is tempting to simply append 177 | "runtime" to the user-provided list, but that does not work if the user 178 | specified an ad-hoc package such as [a.go b.go]. 179 | Instead, ssadump no longer requests the runtime package, 180 | but seeks it among the dependencies of the user-specified packages, 181 | and emits an error if it is not found. 182 | 183 | Overlays: the ParseFile hook in the API permits clients to vary the way 184 | in which ASTs are obtained from filenames; the default implementation is 185 | based on parser.ParseFile. This features enables editor-integrated tools 186 | that analyze the contents of modified but unsaved buffers: rather than 187 | read from the file system, a tool can read from an archive of modified 188 | buffers provided by the editor. 189 | This approach has its limits. Because package metadata is obtained by 190 | fork/execing an external query command for each build system, we can 191 | fake only the file contents seen by the parser, type-checker, and 192 | application, but not by the metadata query, so, for example: 193 | - additional imports in the fake file will not be described by the 194 | metadata, so the type checker will fail to load imports that create 195 | new dependencies. 196 | - in TypeCheck mode, because export data is produced by the query 197 | command, it will not reflect the fake file contents. 198 | - this mechanism cannot add files to a package without first saving them. 199 | 200 | Questions & Tasks 201 | 202 | - Add GOARCH/GOOS? 203 | They are not portable concepts, but could be made portable. 204 | Our goal has been to allow users to express themselves using the conventions 205 | of the underlying build system: if the build system honors GOARCH 206 | during a build and during a metadata query, then so should 207 | applications built atop that query mechanism. 208 | Conversely, if the target architecture of the build is determined by 209 | command-line flags, the application can pass the relevant 210 | flags through to the build system using a command such as: 211 | myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin" 212 | However, this approach is low-level, unwieldy, and non-portable. 213 | GOOS and GOARCH seem important enough to warrant a dedicated option. 214 | 215 | - How should we handle partial failures such as a mixture of good and 216 | malformed patterns, existing and non-existent packages, successful and 217 | failed builds, import failures, import cycles, and so on, in a call to 218 | Load? 219 | 220 | - Support bazel, blaze, and go1.10 list, not just go1.11 list. 221 | 222 | - Handle (and test) various partial success cases, e.g. 223 | a mixture of good packages and: 224 | invalid patterns 225 | nonexistent packages 226 | empty packages 227 | packages with malformed package or import declarations 228 | unreadable files 229 | import cycles 230 | other parse errors 231 | type errors 232 | Make sure we record errors at the correct place in the graph. 233 | 234 | - Missing packages among initial arguments are not reported. 235 | Return bogus packages for them, like golist does. 236 | 237 | - "undeclared name" errors (for example) are reported out of source file 238 | order. I suspect this is due to the breadth-first resolution now used 239 | by go/types. Is that a bug? Discuss with gri. 240 | 241 | */ 242 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/external.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // This file enables an external tool to intercept package requests. 6 | // If the tool is present then its results are used in preference to 7 | // the go list command. 8 | 9 | package packages 10 | 11 | import ( 12 | "bytes" 13 | "encoding/json" 14 | "fmt" 15 | "os/exec" 16 | "strings" 17 | ) 18 | 19 | // Driver 20 | type driverRequest struct { 21 | // TODO(matloob): Add a "command" option, so the "list" argument 22 | // to the command is instead supplied in the driverRequest? 23 | Mode LoadMode `json:"mode"` 24 | Env []string `json:"env"` 25 | BuildFlags []string `json:"build_flags"` 26 | Tests bool `json:"tests"` 27 | Overlay map[string][]byte `json:"overlay"` 28 | } 29 | 30 | // findExternalTool returns the file path of a tool that supplies 31 | // the build system package structure, or "" if not found." 32 | // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its 33 | // value, otherwise it searches for a binary named gopackagesdriver on the PATH. 34 | func findExternalDriver(cfg *Config) driver { 35 | const toolPrefix = "GOPACKAGESDRIVER=" 36 | tool := "" 37 | for _, env := range cfg.Env { 38 | if val := strings.TrimPrefix(env, toolPrefix); val != env { 39 | tool = val 40 | } 41 | } 42 | if tool != "" && tool == "off" { 43 | return nil 44 | } 45 | if tool == "" { 46 | var err error 47 | tool, err = exec.LookPath("gopackagesdriver") 48 | if err != nil { 49 | return nil 50 | } 51 | } 52 | return func(cfg *Config, words ...string) (*driverResponse, error) { 53 | req, err := json.Marshal(driverRequest{ 54 | Mode: cfg.Mode, 55 | Env: cfg.Env, 56 | BuildFlags: cfg.BuildFlags, 57 | Tests: cfg.Tests, 58 | Overlay: cfg.Overlay, 59 | }) 60 | if err != nil { 61 | return nil, fmt.Errorf("failed to encode message to driver tool: %v", err) 62 | } 63 | 64 | buf := new(bytes.Buffer) 65 | cmd := exec.CommandContext(cfg.Context, tool, words...) 66 | cmd.Dir = cfg.Dir 67 | cmd.Env = cfg.Env 68 | cmd.Stdin = bytes.NewReader(req) 69 | cmd.Stdout = buf 70 | cmd.Stderr = new(bytes.Buffer) 71 | if err := cmd.Run(); err != nil { 72 | return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr) 73 | } 74 | var response driverResponse 75 | if err := json.Unmarshal(buf.Bytes(), &response); err != nil { 76 | return nil, err 77 | } 78 | return &response, nil 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/golist_fallback_testmain.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // This file is largely based on the Go 1.10-era cmd/go/internal/test/test.go 6 | // testmain generation code. 7 | 8 | package packages 9 | 10 | import ( 11 | "errors" 12 | "fmt" 13 | "go/ast" 14 | "go/doc" 15 | "go/parser" 16 | "go/token" 17 | "os" 18 | "sort" 19 | "strings" 20 | "text/template" 21 | "unicode" 22 | "unicode/utf8" 23 | ) 24 | 25 | // TODO(matloob): Delete this file once Go 1.12 is released. 26 | 27 | // This file complements golist_fallback.go by providing 28 | // support for generating testmains. 29 | 30 | func generateTestmain(out string, testPkg, xtestPkg *Package) (extraimports, extradeps []string, err error) { 31 | testFuncs, err := loadTestFuncs(testPkg, xtestPkg) 32 | if err != nil { 33 | return nil, nil, err 34 | } 35 | extraimports = []string{"testing", "testing/internal/testdeps"} 36 | if testFuncs.TestMain == nil { 37 | extraimports = append(extraimports, "os") 38 | } 39 | // Transitive dependencies of ("testing", "testing/internal/testdeps"). 40 | // os is part of the transitive closure so it and its transitive dependencies are 41 | // included regardless of whether it's imported in the template below. 42 | extradeps = []string{ 43 | "errors", 44 | "internal/cpu", 45 | "unsafe", 46 | "internal/bytealg", 47 | "internal/race", 48 | "runtime/internal/atomic", 49 | "runtime/internal/sys", 50 | "runtime", 51 | "sync/atomic", 52 | "sync", 53 | "io", 54 | "unicode", 55 | "unicode/utf8", 56 | "bytes", 57 | "math", 58 | "syscall", 59 | "time", 60 | "internal/poll", 61 | "internal/syscall/unix", 62 | "internal/testlog", 63 | "os", 64 | "math/bits", 65 | "strconv", 66 | "reflect", 67 | "fmt", 68 | "sort", 69 | "strings", 70 | "flag", 71 | "runtime/debug", 72 | "context", 73 | "runtime/trace", 74 | "testing", 75 | "bufio", 76 | "regexp/syntax", 77 | "regexp", 78 | "compress/flate", 79 | "encoding/binary", 80 | "hash", 81 | "hash/crc32", 82 | "compress/gzip", 83 | "path/filepath", 84 | "io/ioutil", 85 | "text/tabwriter", 86 | "runtime/pprof", 87 | "testing/internal/testdeps", 88 | } 89 | return extraimports, extradeps, writeTestmain(out, testFuncs) 90 | } 91 | 92 | // The following is adapted from the cmd/go testmain generation code. 93 | 94 | // isTestFunc tells whether fn has the type of a testing function. arg 95 | // specifies the parameter type we look for: B, M or T. 96 | func isTestFunc(fn *ast.FuncDecl, arg string) bool { 97 | if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || 98 | fn.Type.Params.List == nil || 99 | len(fn.Type.Params.List) != 1 || 100 | len(fn.Type.Params.List[0].Names) > 1 { 101 | return false 102 | } 103 | ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr) 104 | if !ok { 105 | return false 106 | } 107 | // We can't easily check that the type is *testing.M 108 | // because we don't know how testing has been imported, 109 | // but at least check that it's *M or *something.M. 110 | // Same applies for B and T. 111 | if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg { 112 | return true 113 | } 114 | if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg { 115 | return true 116 | } 117 | return false 118 | } 119 | 120 | // isTest tells whether name looks like a test (or benchmark, according to prefix). 121 | // It is a Test (say) if there is a character after Test that is not a lower-case letter. 122 | // We don't want TesticularCancer. 123 | func isTest(name, prefix string) bool { 124 | if !strings.HasPrefix(name, prefix) { 125 | return false 126 | } 127 | if len(name) == len(prefix) { // "Test" is ok 128 | return true 129 | } 130 | rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) 131 | return !unicode.IsLower(rune) 132 | } 133 | 134 | // loadTestFuncs returns the testFuncs describing the tests that will be run. 135 | func loadTestFuncs(ptest, pxtest *Package) (*testFuncs, error) { 136 | t := &testFuncs{ 137 | TestPackage: ptest, 138 | XTestPackage: pxtest, 139 | } 140 | for _, file := range ptest.GoFiles { 141 | if !strings.HasSuffix(file, "_test.go") { 142 | continue 143 | } 144 | if err := t.load(file, "_test", &t.ImportTest, &t.NeedTest); err != nil { 145 | return nil, err 146 | } 147 | } 148 | if pxtest != nil { 149 | for _, file := range pxtest.GoFiles { 150 | if err := t.load(file, "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil { 151 | return nil, err 152 | } 153 | } 154 | } 155 | return t, nil 156 | } 157 | 158 | // writeTestmain writes the _testmain.go file for t to the file named out. 159 | func writeTestmain(out string, t *testFuncs) error { 160 | f, err := os.Create(out) 161 | if err != nil { 162 | return err 163 | } 164 | defer f.Close() 165 | 166 | if err := testmainTmpl.Execute(f, t); err != nil { 167 | return err 168 | } 169 | 170 | return nil 171 | } 172 | 173 | type testFuncs struct { 174 | Tests []testFunc 175 | Benchmarks []testFunc 176 | Examples []testFunc 177 | TestMain *testFunc 178 | TestPackage *Package 179 | XTestPackage *Package 180 | ImportTest bool 181 | NeedTest bool 182 | ImportXtest bool 183 | NeedXtest bool 184 | } 185 | 186 | // Tested returns the name of the package being tested. 187 | func (t *testFuncs) Tested() string { 188 | return t.TestPackage.Name 189 | } 190 | 191 | type testFunc struct { 192 | Package string // imported package name (_test or _xtest) 193 | Name string // function name 194 | Output string // output, for examples 195 | Unordered bool // output is allowed to be unordered. 196 | } 197 | 198 | func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { 199 | var fset = token.NewFileSet() 200 | 201 | f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) 202 | if err != nil { 203 | return errors.New("failed to parse test file " + filename) 204 | } 205 | for _, d := range f.Decls { 206 | n, ok := d.(*ast.FuncDecl) 207 | if !ok { 208 | continue 209 | } 210 | if n.Recv != nil { 211 | continue 212 | } 213 | name := n.Name.String() 214 | switch { 215 | case name == "TestMain": 216 | if isTestFunc(n, "T") { 217 | t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 218 | *doImport, *seen = true, true 219 | continue 220 | } 221 | err := checkTestFunc(fset, n, "M") 222 | if err != nil { 223 | return err 224 | } 225 | if t.TestMain != nil { 226 | return errors.New("multiple definitions of TestMain") 227 | } 228 | t.TestMain = &testFunc{pkg, name, "", false} 229 | *doImport, *seen = true, true 230 | case isTest(name, "Test"): 231 | err := checkTestFunc(fset, n, "T") 232 | if err != nil { 233 | return err 234 | } 235 | t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 236 | *doImport, *seen = true, true 237 | case isTest(name, "Benchmark"): 238 | err := checkTestFunc(fset, n, "B") 239 | if err != nil { 240 | return err 241 | } 242 | t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false}) 243 | *doImport, *seen = true, true 244 | } 245 | } 246 | ex := doc.Examples(f) 247 | sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order }) 248 | for _, e := range ex { 249 | *doImport = true // import test file whether executed or not 250 | if e.Output == "" && !e.EmptyOutput { 251 | // Don't run examples with no output. 252 | continue 253 | } 254 | t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered}) 255 | *seen = true 256 | } 257 | return nil 258 | } 259 | 260 | func checkTestFunc(fset *token.FileSet, fn *ast.FuncDecl, arg string) error { 261 | if !isTestFunc(fn, arg) { 262 | name := fn.Name.String() 263 | pos := fset.Position(fn.Pos()) 264 | return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg) 265 | } 266 | return nil 267 | } 268 | 269 | var testmainTmpl = template.Must(template.New("main").Parse(` 270 | package main 271 | 272 | import ( 273 | {{if not .TestMain}} 274 | "os" 275 | {{end}} 276 | "testing" 277 | "testing/internal/testdeps" 278 | 279 | {{if .ImportTest}} 280 | {{if .NeedTest}}_test{{else}}_{{end}} {{.TestPackage.PkgPath | printf "%q"}} 281 | {{end}} 282 | {{if .ImportXtest}} 283 | {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.XTestPackage.PkgPath | printf "%q"}} 284 | {{end}} 285 | ) 286 | 287 | var tests = []testing.InternalTest{ 288 | {{range .Tests}} 289 | {"{{.Name}}", {{.Package}}.{{.Name}}}, 290 | {{end}} 291 | } 292 | 293 | var benchmarks = []testing.InternalBenchmark{ 294 | {{range .Benchmarks}} 295 | {"{{.Name}}", {{.Package}}.{{.Name}}}, 296 | {{end}} 297 | } 298 | 299 | var examples = []testing.InternalExample{ 300 | {{range .Examples}} 301 | {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}}, 302 | {{end}} 303 | } 304 | 305 | func init() { 306 | testdeps.ImportPath = {{.TestPackage.PkgPath | printf "%q"}} 307 | } 308 | 309 | func main() { 310 | m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples) 311 | {{with .TestMain}} 312 | {{.Package}}.{{.Name}}(m) 313 | {{else}} 314 | os.Exit(m.Run()) 315 | {{end}} 316 | } 317 | 318 | `)) 319 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/golist_overlay.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "go/parser" 5 | "go/token" 6 | "path/filepath" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // processGolistOverlay provides rudimentary support for adding 12 | // files that don't exist on disk to an overlay. The results can be 13 | // sometimes incorrect. 14 | // TODO(matloob): Handle unsupported cases, including the following: 15 | // - test files 16 | // - adding test and non-test files to test variants of packages 17 | // - determining the correct package to add given a new import path 18 | // - creating packages that don't exist 19 | func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs, needPkgs []string, err error) { 20 | havePkgs := make(map[string]string) // importPath -> non-test package ID 21 | needPkgsSet := make(map[string]bool) 22 | modifiedPkgsSet := make(map[string]bool) 23 | 24 | for _, pkg := range response.Packages { 25 | // This is an approximation of import path to id. This can be 26 | // wrong for tests, vendored packages, and a number of other cases. 27 | havePkgs[pkg.PkgPath] = pkg.ID 28 | } 29 | 30 | outer: 31 | for path, contents := range cfg.Overlay { 32 | base := filepath.Base(path) 33 | if strings.HasSuffix(path, "_test.go") { 34 | // Overlays don't support adding new test files yet. 35 | // TODO(matloob): support adding new test files. 36 | continue 37 | } 38 | dir := filepath.Dir(path) 39 | for _, pkg := range response.Packages { 40 | var dirContains, fileExists bool 41 | for _, f := range pkg.GoFiles { 42 | if sameFile(filepath.Dir(f), dir) { 43 | dirContains = true 44 | } 45 | if filepath.Base(f) == base { 46 | fileExists = true 47 | } 48 | } 49 | if dirContains { 50 | if !fileExists { 51 | pkg.GoFiles = append(pkg.GoFiles, path) // TODO(matloob): should the file just be added to GoFiles? 52 | pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, path) 53 | modifiedPkgsSet[pkg.ID] = true 54 | } 55 | imports, err := extractImports(path, contents) 56 | if err != nil { 57 | // Let the parser or type checker report errors later. 58 | continue outer 59 | } 60 | for _, imp := range imports { 61 | _, found := pkg.Imports[imp] 62 | if !found { 63 | needPkgsSet[imp] = true 64 | // TODO(matloob): Handle cases when the following block isn't correct. 65 | // These include imports of test variants, imports of vendored packages, etc. 66 | id, ok := havePkgs[imp] 67 | if !ok { 68 | id = imp 69 | } 70 | pkg.Imports[imp] = &Package{ID: id} 71 | } 72 | } 73 | continue outer 74 | } 75 | } 76 | } 77 | 78 | needPkgs = make([]string, 0, len(needPkgsSet)) 79 | for pkg := range needPkgsSet { 80 | needPkgs = append(needPkgs, pkg) 81 | } 82 | modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) 83 | for pkg := range modifiedPkgsSet { 84 | modifiedPkgs = append(modifiedPkgs, pkg) 85 | } 86 | return modifiedPkgs, needPkgs, err 87 | } 88 | 89 | func extractImports(filename string, contents []byte) ([]string, error) { 90 | f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? 91 | if err != nil { 92 | return nil, err 93 | } 94 | var res []string 95 | for _, imp := range f.Imports { 96 | quotedPath := imp.Path.Value 97 | path, err := strconv.Unquote(quotedPath) 98 | if err != nil { 99 | return nil, err 100 | } 101 | res = append(res, path) 102 | } 103 | return res, nil 104 | } 105 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/packagestest/expect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 packagestest 6 | 7 | import ( 8 | "fmt" 9 | "go/token" 10 | "path/filepath" 11 | "reflect" 12 | "regexp" 13 | 14 | "golang.org/x/tools/go/expect" 15 | "golang.org/x/tools/go/packages" 16 | ) 17 | 18 | const ( 19 | markMethod = "mark" 20 | eofIdentifier = "EOF" 21 | ) 22 | 23 | // Expect invokes the supplied methods for all expectation notes found in 24 | // the exported source files. 25 | // 26 | // All exported go source files are parsed to collect the expectation 27 | // notes. 28 | // See the documentation for expect.Parse for how the notes are collected 29 | // and parsed. 30 | // 31 | // The methods are supplied as a map of name to function, and those functions 32 | // will be matched against the expectations by name. 33 | // Notes with no matching function will be skipped, and functions with no 34 | // matching notes will not be invoked. 35 | // If there are no registered markers yet, a special pass will be run first 36 | // which adds any markers declared with @mark(Name, pattern) or @name. These 37 | // call the Mark method to add the marker to the global set. 38 | // You can register the "mark" method to override these in your own call to 39 | // Expect. The bound Mark function is usable directly in your method map, so 40 | // exported.Expect(map[string]interface{}{"mark": exported.Mark}) 41 | // replicates the built in behavior. 42 | // 43 | // Method invocation 44 | // 45 | // When invoking a method the expressions in the parameter list need to be 46 | // converted to values to be passed to the method. 47 | // There are a very limited set of types the arguments are allowed to be. 48 | // expect.Comment : passed the Comment instance being evaluated. 49 | // string : can be supplied either a string literal or an identifier. 50 | // int : can only be supplied an integer literal. 51 | // *regexp.Regexp : can only be supplied a regular expression literal 52 | // token.Pos : has a file position calculated as described below. 53 | // token.Position : has a file position calculated as described below. 54 | // interface{} : will be passed any value 55 | // 56 | // Position calculation 57 | // 58 | // There is some extra handling when a parameter is being coerced into a 59 | // token.Pos, token.Position or Range type argument. 60 | // 61 | // If the parameter is an identifier, it will be treated as the name of an 62 | // marker to look up (as if markers were global variables). 63 | // 64 | // If it is a string or regular expression, then it will be passed to 65 | // expect.MatchBefore to look up a match in the line at which it was declared. 66 | // 67 | // It is safe to call this repeatedly with different method sets, but it is 68 | // not safe to call it concurrently. 69 | func (e *Exported) Expect(methods map[string]interface{}) error { 70 | if err := e.getNotes(); err != nil { 71 | return err 72 | } 73 | if err := e.getMarkers(); err != nil { 74 | return err 75 | } 76 | var err error 77 | ms := make(map[string]method, len(methods)) 78 | for name, f := range methods { 79 | mi := method{f: reflect.ValueOf(f)} 80 | mi.converters = make([]converter, mi.f.Type().NumIn()) 81 | for i := 0; i < len(mi.converters); i++ { 82 | mi.converters[i], err = e.buildConverter(mi.f.Type().In(i)) 83 | if err != nil { 84 | return fmt.Errorf("invalid method %v: %v", name, err) 85 | } 86 | } 87 | ms[name] = mi 88 | } 89 | for _, n := range e.notes { 90 | if n.Args == nil { 91 | // simple identifier form, convert to a call to mark 92 | n = &expect.Note{ 93 | Pos: n.Pos, 94 | Name: markMethod, 95 | Args: []interface{}{n.Name, n.Name}, 96 | } 97 | } 98 | mi, ok := ms[n.Name] 99 | if !ok { 100 | continue 101 | } 102 | params := make([]reflect.Value, len(mi.converters)) 103 | args := n.Args 104 | for i, convert := range mi.converters { 105 | params[i], args, err = convert(n, args) 106 | if err != nil { 107 | return fmt.Errorf("%v: %v", e.fset.Position(n.Pos), err) 108 | } 109 | } 110 | if len(args) > 0 { 111 | return fmt.Errorf("%v: unwanted args got %+v extra", e.fset.Position(n.Pos), args) 112 | } 113 | //TODO: catch the error returned from the method 114 | mi.f.Call(params) 115 | } 116 | return nil 117 | } 118 | 119 | type Range struct { 120 | Start token.Pos 121 | End token.Pos 122 | } 123 | 124 | // Mark adds a new marker to the known set. 125 | func (e *Exported) Mark(name string, r Range) { 126 | if e.markers == nil { 127 | e.markers = make(map[string]Range) 128 | } 129 | e.markers[name] = r 130 | } 131 | 132 | func (e *Exported) getNotes() error { 133 | if e.notes != nil { 134 | return nil 135 | } 136 | notes := []*expect.Note{} 137 | var dirs []string 138 | for _, module := range e.written { 139 | for _, filename := range module { 140 | dirs = append(dirs, filepath.Dir(filename)) 141 | } 142 | } 143 | pkgs, err := packages.Load(e.Config, dirs...) 144 | if err != nil { 145 | return fmt.Errorf("unable to load packages for directories %s: %v", dirs, err) 146 | } 147 | for _, pkg := range pkgs { 148 | for _, filename := range pkg.GoFiles { 149 | l, err := expect.Parse(e.fset, filename, nil) 150 | if err != nil { 151 | return fmt.Errorf("Failed to extract expectations: %v", err) 152 | } 153 | notes = append(notes, l...) 154 | } 155 | } 156 | e.notes = notes 157 | return nil 158 | } 159 | 160 | func (e *Exported) getMarkers() error { 161 | if e.markers != nil { 162 | return nil 163 | } 164 | // set markers early so that we don't call getMarkers again from Expect 165 | e.markers = make(map[string]Range) 166 | return e.Expect(map[string]interface{}{ 167 | markMethod: e.Mark, 168 | }) 169 | } 170 | 171 | var ( 172 | noteType = reflect.TypeOf((*expect.Note)(nil)) 173 | identifierType = reflect.TypeOf(expect.Identifier("")) 174 | posType = reflect.TypeOf(token.Pos(0)) 175 | positionType = reflect.TypeOf(token.Position{}) 176 | rangeType = reflect.TypeOf(Range{}) 177 | fsetType = reflect.TypeOf((*token.FileSet)(nil)) 178 | regexType = reflect.TypeOf((*regexp.Regexp)(nil)) 179 | ) 180 | 181 | // converter converts from a marker's argument parsed from the comment to 182 | // reflect values passed to the method during Invoke. 183 | // It takes the args remaining, and returns the args it did not consume. 184 | // This allows a converter to consume 0 args for well known types, or multiple 185 | // args for compound types. 186 | type converter func(*expect.Note, []interface{}) (reflect.Value, []interface{}, error) 187 | 188 | // method is used to track information about Invoke methods that is expensive to 189 | // calculate so that we can work it out once rather than per marker. 190 | type method struct { 191 | f reflect.Value // the reflect value of the passed in method 192 | converters []converter // the parameter converters for the method 193 | } 194 | 195 | // buildConverter works out what function should be used to go from an ast expressions to a reflect 196 | // value of the type expected by a method. 197 | // It is called when only the target type is know, it returns converters that are flexible across 198 | // all supported expression types for that target type. 199 | func (e *Exported) buildConverter(pt reflect.Type) (converter, error) { 200 | switch { 201 | case pt == noteType: 202 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 203 | return reflect.ValueOf(n), args, nil 204 | }, nil 205 | case pt == fsetType: 206 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 207 | return reflect.ValueOf(e.fset), args, nil 208 | }, nil 209 | case pt == posType: 210 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 211 | r, remains, err := e.rangeConverter(n, args) 212 | if err != nil { 213 | return reflect.Value{}, nil, err 214 | } 215 | return reflect.ValueOf(r.Start), remains, nil 216 | }, nil 217 | case pt == positionType: 218 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 219 | r, remains, err := e.rangeConverter(n, args) 220 | if err != nil { 221 | return reflect.Value{}, nil, err 222 | } 223 | return reflect.ValueOf(e.fset.Position(r.Start)), remains, nil 224 | }, nil 225 | case pt == rangeType: 226 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 227 | r, remains, err := e.rangeConverter(n, args) 228 | if err != nil { 229 | return reflect.Value{}, nil, err 230 | } 231 | return reflect.ValueOf(r), remains, nil 232 | }, nil 233 | case pt == identifierType: 234 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 235 | arg := args[0] 236 | args = args[1:] 237 | switch arg := arg.(type) { 238 | case expect.Identifier: 239 | return reflect.ValueOf(arg), args, nil 240 | default: 241 | return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to string", arg) 242 | } 243 | }, nil 244 | 245 | case pt == regexType: 246 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 247 | arg := args[0] 248 | args = args[1:] 249 | if _, ok := arg.(*regexp.Regexp); !ok { 250 | return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to *regexp.Regexp", arg) 251 | } 252 | return reflect.ValueOf(arg), args, nil 253 | }, nil 254 | 255 | case pt.Kind() == reflect.String: 256 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 257 | arg := args[0] 258 | args = args[1:] 259 | switch arg := arg.(type) { 260 | case expect.Identifier: 261 | return reflect.ValueOf(string(arg)), args, nil 262 | case string: 263 | return reflect.ValueOf(arg), args, nil 264 | default: 265 | return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to string", arg) 266 | } 267 | }, nil 268 | case pt.Kind() == reflect.Int64: 269 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 270 | arg := args[0] 271 | args = args[1:] 272 | switch arg := arg.(type) { 273 | case int64: 274 | return reflect.ValueOf(arg), args, nil 275 | default: 276 | return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to int", arg) 277 | } 278 | }, nil 279 | case pt.Kind() == reflect.Bool: 280 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 281 | arg := args[0] 282 | args = args[1:] 283 | b, ok := arg.(bool) 284 | if !ok { 285 | return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to bool", arg) 286 | } 287 | return reflect.ValueOf(b), args, nil 288 | }, nil 289 | case pt.Kind() == reflect.Slice: 290 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 291 | converter, err := e.buildConverter(pt.Elem()) 292 | if err != nil { 293 | return reflect.Value{}, nil, err 294 | } 295 | result := reflect.MakeSlice(reflect.SliceOf(pt.Elem()), 0, len(args)) 296 | for range args { 297 | value, remains, err := converter(n, args) 298 | if err != nil { 299 | return reflect.Value{}, nil, err 300 | } 301 | result = reflect.Append(result, value) 302 | args = remains 303 | } 304 | return result, args, nil 305 | }, nil 306 | default: 307 | if pt.Kind() == reflect.Interface && pt.NumMethod() == 0 { 308 | return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) { 309 | return reflect.ValueOf(args[0]), args[1:], nil 310 | }, nil 311 | } 312 | return nil, fmt.Errorf("param has unexpected type %v (kind %v)", pt, pt.Kind()) 313 | } 314 | } 315 | 316 | func (e *Exported) rangeConverter(n *expect.Note, args []interface{}) (Range, []interface{}, error) { 317 | if len(args) < 1 { 318 | return Range{}, nil, fmt.Errorf("missing argument") 319 | } 320 | arg := args[0] 321 | args = args[1:] 322 | switch arg := arg.(type) { 323 | case expect.Identifier: 324 | // handle the special identifiers 325 | switch arg { 326 | case eofIdentifier: 327 | // end of file identifier, look up the current file 328 | f := e.fset.File(n.Pos) 329 | eof := f.Pos(f.Size()) 330 | return Range{Start: eof, End: token.NoPos}, args, nil 331 | default: 332 | // look up an marker by name 333 | mark, ok := e.markers[string(arg)] 334 | if !ok { 335 | return Range{}, nil, fmt.Errorf("cannot find marker %v", arg) 336 | } 337 | return mark, args, nil 338 | } 339 | case string: 340 | start, end, err := expect.MatchBefore(e.fset, e.fileContents, n.Pos, arg) 341 | if err != nil { 342 | return Range{}, nil, err 343 | } 344 | if start == token.NoPos { 345 | return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg) 346 | } 347 | return Range{Start: start, End: end}, args, nil 348 | case *regexp.Regexp: 349 | start, end, err := expect.MatchBefore(e.fset, e.fileContents, n.Pos, arg) 350 | if err != nil { 351 | return Range{}, nil, err 352 | } 353 | if start == token.NoPos { 354 | return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg) 355 | } 356 | return Range{Start: start, End: end}, args, nil 357 | default: 358 | return Range{}, nil, fmt.Errorf("cannot convert %v to pos", arg) 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/packagestest/export.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | /* 6 | Package packagestest creates temporary projects on disk for testing go tools on. 7 | 8 | By changing the exporter used, you can create projects for multiple build 9 | systems from the same description, and run the same tests on them in many 10 | cases. 11 | */ 12 | package packagestest 13 | 14 | import ( 15 | "flag" 16 | "fmt" 17 | "go/token" 18 | "io/ioutil" 19 | "log" 20 | "os" 21 | "path/filepath" 22 | "strings" 23 | "testing" 24 | 25 | "golang.org/x/tools/go/expect" 26 | "golang.org/x/tools/go/packages" 27 | ) 28 | 29 | var ( 30 | skipCleanup = flag.Bool("skip-cleanup", false, "Do not delete the temporary export folders") // for debugging 31 | ) 32 | 33 | // Module is a representation of a go module. 34 | type Module struct { 35 | // Name is the base name of the module as it would be in the go.mod file. 36 | Name string 37 | // Files is the set of source files for all packages that make up the module. 38 | // The keys are the file fragment that follows the module name, the value can 39 | // be a string or byte slice, in which case it is the contents of the 40 | // file, otherwise it must be a Writer function. 41 | Files map[string]interface{} 42 | } 43 | 44 | // A Writer is a function that writes out a test file. 45 | // It is provided the name of the file to write, and may return an error if it 46 | // cannot write the file. 47 | // These are used as the content of the Files map in a Module. 48 | type Writer func(filename string) error 49 | 50 | // Exported is returned by the Export function to report the structure that was produced on disk. 51 | type Exported struct { 52 | // Config is a correctly configured packages.Config ready to be passed to packages.Load. 53 | // Exactly what it will contain varies depending on the Exporter being used. 54 | Config *packages.Config 55 | 56 | temp string // the temporary directory that was exported to 57 | primary string // the first non GOROOT module that was exported 58 | written map[string]map[string]string // the full set of exported files 59 | fset *token.FileSet // The file set used when parsing expectations 60 | notes []*expect.Note // The list of expectations extracted from go source files 61 | markers map[string]Range // The set of markers extracted from go source files 62 | contents map[string][]byte 63 | } 64 | 65 | // Exporter implementations are responsible for converting from the generic description of some 66 | // test data to a driver specific file layout. 67 | type Exporter interface { 68 | // Name reports the name of the exporter, used in logging and sub-test generation. 69 | Name() string 70 | // Filename reports the system filename for test data source file. 71 | // It is given the base directory, the module the file is part of and the filename fragment to 72 | // work from. 73 | Filename(exported *Exported, module, fragment string) string 74 | // Finalize is called once all files have been written to write any extra data needed and modify 75 | // the Config to match. It is handed the full list of modules that were encountered while writing 76 | // files. 77 | Finalize(exported *Exported) error 78 | } 79 | 80 | // All is the list of known exporters. 81 | // This is used by TestAll to run tests with all the exporters. 82 | var All []Exporter 83 | 84 | // TestAll invokes the testing function once for each exporter registered in 85 | // the All global. 86 | // Each exporter will be run as a sub-test named after the exporter being used. 87 | func TestAll(t *testing.T, f func(*testing.T, Exporter)) { 88 | t.Helper() 89 | for _, e := range All { 90 | t.Run(e.Name(), func(t *testing.T) { 91 | t.Helper() 92 | f(t, e) 93 | }) 94 | } 95 | } 96 | 97 | // BenchmarkAll invokes the testing function once for each exporter registered in 98 | // the All global. 99 | // Each exporter will be run as a sub-test named after the exporter being used. 100 | func BenchmarkAll(b *testing.B, f func(*testing.B, Exporter)) { 101 | b.Helper() 102 | for _, e := range All { 103 | b.Run(e.Name(), func(b *testing.B) { 104 | b.Helper() 105 | f(b, e) 106 | }) 107 | } 108 | } 109 | 110 | // Export is called to write out a test directory from within a test function. 111 | // It takes the exporter and the build system agnostic module descriptions, and 112 | // uses them to build a temporary directory. 113 | // It returns an Exported with the results of the export. 114 | // The Exported.Config is prepared for loading from the exported data. 115 | // You must invoke Exported.Cleanup on the returned value to clean up. 116 | // The file deletion in the cleanup can be skipped by setting the skip-cleanup 117 | // flag when invoking the test, allowing the temporary directory to be left for 118 | // debugging tests. 119 | func Export(t testing.TB, exporter Exporter, modules []Module) *Exported { 120 | t.Helper() 121 | dirname := strings.Replace(t.Name(), "/", "_", -1) 122 | dirname = strings.Replace(dirname, "#", "_", -1) // duplicate subtests get a #NNN suffix. 123 | temp, err := ioutil.TempDir("", dirname) 124 | if err != nil { 125 | t.Fatal(err) 126 | } 127 | exported := &Exported{ 128 | Config: &packages.Config{ 129 | Dir: temp, 130 | Env: append(os.Environ(), "GOPACKAGESDRIVER=off"), 131 | }, 132 | temp: temp, 133 | primary: modules[0].Name, 134 | written: map[string]map[string]string{}, 135 | fset: token.NewFileSet(), 136 | contents: map[string][]byte{}, 137 | } 138 | defer func() { 139 | if t.Failed() || t.Skipped() { 140 | exported.Cleanup() 141 | } 142 | }() 143 | for _, module := range modules { 144 | for fragment, value := range module.Files { 145 | fullpath := exporter.Filename(exported, module.Name, filepath.FromSlash(fragment)) 146 | written, ok := exported.written[module.Name] 147 | if !ok { 148 | written = map[string]string{} 149 | exported.written[module.Name] = written 150 | } 151 | written[fragment] = fullpath 152 | if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil { 153 | t.Fatal(err) 154 | } 155 | switch value := value.(type) { 156 | case Writer: 157 | if err := value(fullpath); err != nil { 158 | t.Fatal(err) 159 | } 160 | case string: 161 | if err := ioutil.WriteFile(fullpath, []byte(value), 0644); err != nil { 162 | t.Fatal(err) 163 | } 164 | default: 165 | t.Fatalf("Invalid type %T in files, must be string or Writer", value) 166 | } 167 | } 168 | } 169 | if err := exporter.Finalize(exported); err != nil { 170 | t.Fatal(err) 171 | } 172 | return exported 173 | } 174 | 175 | // Script returns a Writer that writes out contents to the file and sets the 176 | // executable bit on the created file. 177 | // It is intended for source files that are shell scripts. 178 | func Script(contents string) Writer { 179 | return func(filename string) error { 180 | return ioutil.WriteFile(filename, []byte(contents), 0755) 181 | } 182 | } 183 | 184 | // Link returns a Writer that creates a hard link from the specified source to 185 | // the required file. 186 | // This is used to link testdata files into the generated testing tree. 187 | func Link(source string) Writer { 188 | return func(filename string) error { 189 | return os.Link(source, filename) 190 | } 191 | } 192 | 193 | // Symlink returns a Writer that creates a symlink from the specified source to the 194 | // required file. 195 | // This is used to link testdata files into the generated testing tree. 196 | func Symlink(source string) Writer { 197 | if !strings.HasPrefix(source, ".") { 198 | if abspath, err := filepath.Abs(source); err == nil { 199 | if _, err := os.Stat(source); !os.IsNotExist(err) { 200 | source = abspath 201 | } 202 | } 203 | } 204 | return func(filename string) error { 205 | return os.Symlink(source, filename) 206 | } 207 | } 208 | 209 | // Copy returns a Writer that copies a file from the specified source to the 210 | // required file. 211 | // This is used to copy testdata files into the generated testing tree. 212 | func Copy(source string) Writer { 213 | return func(filename string) error { 214 | stat, err := os.Stat(source) 215 | if err != nil { 216 | return err 217 | } 218 | if !stat.Mode().IsRegular() { 219 | // cannot copy non-regular files (e.g., directories, 220 | // symlinks, devices, etc.) 221 | return fmt.Errorf("Cannot copy non regular file %s", source) 222 | } 223 | contents, err := ioutil.ReadFile(source) 224 | if err != nil { 225 | return err 226 | } 227 | return ioutil.WriteFile(filename, contents, stat.Mode()) 228 | } 229 | } 230 | 231 | // MustCopyFileTree returns a file set for a module based on a real directory tree. 232 | // It scans the directory tree anchored at root and adds a Copy writer to the 233 | // map for every file found. 234 | // This is to enable the common case in tests where you have a full copy of the 235 | // package in your testdata. 236 | // This will panic if there is any kind of error trying to walk the file tree. 237 | func MustCopyFileTree(root string) map[string]interface{} { 238 | result := map[string]interface{}{} 239 | if err := filepath.Walk(filepath.FromSlash(root), func(path string, info os.FileInfo, err error) error { 240 | if err != nil { 241 | return err 242 | } 243 | if info.IsDir() { 244 | return nil 245 | } 246 | fragment, err := filepath.Rel(root, path) 247 | if err != nil { 248 | return err 249 | } 250 | result[fragment] = Copy(path) 251 | return nil 252 | }); err != nil { 253 | log.Panic(fmt.Sprintf("MustCopyFileTree failed: %v", err)) 254 | } 255 | return result 256 | } 257 | 258 | // Cleanup removes the temporary directory (unless the --skip-cleanup flag was set) 259 | // It is safe to call cleanup multiple times. 260 | func (e *Exported) Cleanup() { 261 | if e.temp == "" { 262 | return 263 | } 264 | if *skipCleanup { 265 | log.Printf("Skipping cleanup of temp dir: %s", e.temp) 266 | return 267 | } 268 | os.RemoveAll(e.temp) // ignore errors 269 | e.temp = "" 270 | } 271 | 272 | // Temp returns the temporary directory that was generated. 273 | func (e *Exported) Temp() string { 274 | return e.temp 275 | } 276 | 277 | // File returns the full path for the given module and file fragment. 278 | func (e *Exported) File(module, fragment string) string { 279 | if m := e.written[module]; m != nil { 280 | return m[fragment] 281 | } 282 | return "" 283 | } 284 | 285 | func (e *Exported) fileContents(filename string) ([]byte, error) { 286 | if content, found := e.contents[filename]; found { 287 | return content, nil 288 | } 289 | content, err := ioutil.ReadFile(filename) 290 | if err != nil { 291 | return nil, err 292 | } 293 | return content, nil 294 | } 295 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/packagestest/gopath.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 packagestest 6 | 7 | import ( 8 | "path" 9 | "path/filepath" 10 | ) 11 | 12 | // GOPATH is the exporter that produces GOPATH layouts. 13 | // Each "module" is put in it's own GOPATH entry to help test complex cases. 14 | // Given the two files 15 | // golang.org/repoa#a/a.go 16 | // golang.org/repob#b/b.go 17 | // You would get the directory layout 18 | // /sometemporarydirectory 19 | // ├── repoa 20 | // │ └── src 21 | // │ └── golang.org 22 | // │ └── repoa 23 | // │ └── a 24 | // │ └── a.go 25 | // └── repob 26 | // └── src 27 | // └── golang.org 28 | // └── repob 29 | // └── b 30 | // └── b.go 31 | // GOPATH would be set to 32 | // /sometemporarydirectory/repoa;/sometemporarydirectory/repob 33 | // and the working directory would be 34 | // /sometemporarydirectory/repoa/src 35 | var GOPATH = gopath{} 36 | 37 | func init() { 38 | All = append(All, GOPATH) 39 | } 40 | 41 | type gopath struct{} 42 | 43 | func (gopath) Name() string { 44 | return "GOPATH" 45 | } 46 | 47 | func (gopath) Filename(exported *Exported, module, fragment string) string { 48 | return filepath.Join(gopathDir(exported, module), "src", module, fragment) 49 | } 50 | 51 | func (gopath) Finalize(exported *Exported) error { 52 | exported.Config.Env = append(exported.Config.Env, "GO111MODULE=off") 53 | gopath := "" 54 | for module := range exported.written { 55 | if gopath != "" { 56 | gopath += string(filepath.ListSeparator) 57 | } 58 | dir := gopathDir(exported, module) 59 | gopath += dir 60 | if module == exported.primary { 61 | exported.Config.Dir = filepath.Join(dir, "src") 62 | } 63 | } 64 | exported.Config.Env = append(exported.Config.Env, "GOPATH="+gopath) 65 | return nil 66 | } 67 | 68 | func gopathDir(exported *Exported, module string) string { 69 | dir := path.Base(module) 70 | if versionSuffixRE.MatchString(dir) { 71 | dir = path.Base(path.Dir(module)) + "_" + dir 72 | } 73 | return filepath.Join(exported.temp, dir) 74 | } 75 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/packagestest/modules.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 packagestest 6 | 7 | import ( 8 | "archive/zip" 9 | "bytes" 10 | "fmt" 11 | "io/ioutil" 12 | "os" 13 | "os/exec" 14 | "path" 15 | "path/filepath" 16 | "regexp" 17 | 18 | "golang.org/x/tools/go/packages" 19 | ) 20 | 21 | // Modules is the exporter that produces module layouts. 22 | // Each "repository" is put in it's own module, and the module file generated 23 | // will have replace directives for all other modules. 24 | // Given the two files 25 | // golang.org/repoa#a/a.go 26 | // golang.org/repob#b/b.go 27 | // You would get the directory layout 28 | // /sometemporarydirectory 29 | // ├── repoa 30 | // │ ├── a 31 | // │ │ └── a.go 32 | // │ └── go.mod 33 | // └── repob 34 | // ├── b 35 | // │ └── b.go 36 | // └── go.mod 37 | // and the working directory would be 38 | // /sometemporarydirectory/repoa 39 | var Modules = modules{} 40 | 41 | type modules struct{} 42 | 43 | func (modules) Name() string { 44 | return "Modules" 45 | } 46 | 47 | func (modules) Filename(exported *Exported, module, fragment string) string { 48 | if module == exported.primary { 49 | return filepath.Join(primaryDir(exported), fragment) 50 | } 51 | return filepath.Join(moduleDir(exported, module), fragment) 52 | } 53 | 54 | func (modules) Finalize(exported *Exported) error { 55 | // Write out the primary module. This module can use symlinks and 56 | // other weird stuff, and will be the working dir for the go command. 57 | // It depends on all the other modules. 58 | primaryDir := primaryDir(exported) 59 | exported.Config.Dir = primaryDir 60 | exported.written[exported.primary]["go.mod"] = filepath.Join(primaryDir, "go.mod") 61 | primaryGomod := "module " + exported.primary + "\nrequire (\n" 62 | for other := range exported.written { 63 | if other == exported.primary { 64 | continue 65 | } 66 | primaryGomod += fmt.Sprintf("\t%v %v\n", other, moduleVersion(other)) 67 | } 68 | primaryGomod += ")\n" 69 | if err := ioutil.WriteFile(filepath.Join(primaryDir, "go.mod"), []byte(primaryGomod), 0644); err != nil { 70 | return err 71 | } 72 | 73 | // Create the mod cache so we can rename it later, even if we don't need it. 74 | if err := os.MkdirAll(modCache(exported), 0755); err != nil { 75 | return err 76 | } 77 | 78 | // Write out the go.mod files for the other modules. 79 | for module, files := range exported.written { 80 | if module == exported.primary { 81 | continue 82 | } 83 | dir := moduleDir(exported, module) 84 | 85 | modfile := filepath.Join(dir, "go.mod") 86 | if err := ioutil.WriteFile(modfile, []byte("module "+module+"\n"), 0644); err != nil { 87 | return err 88 | } 89 | files["go.mod"] = modfile 90 | } 91 | 92 | // Zip up all the secondary modules into the proxy dir. 93 | proxyDir := filepath.Join(exported.temp, "modproxy") 94 | for module, files := range exported.written { 95 | if module == exported.primary { 96 | continue 97 | } 98 | dir := filepath.Join(proxyDir, module, "@v") 99 | 100 | if err := writeModuleProxy(dir, module, files); err != nil { 101 | return fmt.Errorf("creating module proxy dir for %v: %v", module, err) 102 | } 103 | } 104 | 105 | // Discard the original mod cache dir, which contained the files written 106 | // for us by Export. 107 | if err := os.Rename(modCache(exported), modCache(exported)+".orig"); err != nil { 108 | return err 109 | } 110 | exported.Config.Env = append(exported.Config.Env, 111 | "GO111MODULE=on", 112 | "GOPATH="+filepath.Join(exported.temp, "modcache"), 113 | "GOPROXY=file://"+filepath.ToSlash(proxyDir)) 114 | 115 | // Run go mod download to recreate the mod cache dir with all the extra 116 | // stuff in cache. All the files created by Export should be recreated. 117 | if err := invokeGo(exported.Config, "mod", "download"); err != nil { 118 | return err 119 | } 120 | 121 | return nil 122 | } 123 | 124 | // writeModuleProxy creates a directory in the proxy dir for a module. 125 | func writeModuleProxy(dir, module string, files map[string]string) error { 126 | ver := moduleVersion(module) 127 | if err := os.MkdirAll(dir, 0755); err != nil { 128 | return err 129 | } 130 | 131 | // list file. Just the single version. 132 | if err := ioutil.WriteFile(filepath.Join(dir, "list"), []byte(ver+"\n"), 0644); err != nil { 133 | return err 134 | } 135 | 136 | // go.mod, copied from the file written in Finalize. 137 | modContents, err := ioutil.ReadFile(files["go.mod"]) 138 | if err != nil { 139 | return err 140 | } 141 | if err := ioutil.WriteFile(filepath.Join(dir, ver+".mod"), modContents, 0644); err != nil { 142 | return err 143 | } 144 | 145 | // info file, just the bare bones. 146 | infoContents := []byte(fmt.Sprintf(`{"Version": "%v", "Time":"2017-12-14T13:08:43Z"}`, ver)) 147 | if err := ioutil.WriteFile(filepath.Join(dir, ver+".info"), infoContents, 0644); err != nil { 148 | return err 149 | } 150 | 151 | // zip of all the source files. 152 | f, err := os.OpenFile(filepath.Join(dir, ver+".zip"), os.O_CREATE|os.O_WRONLY, 0644) 153 | if err != nil { 154 | return err 155 | } 156 | z := zip.NewWriter(f) 157 | for name, path := range files { 158 | zf, err := z.Create(module + "@" + ver + "/" + name) 159 | if err != nil { 160 | return err 161 | } 162 | contents, err := ioutil.ReadFile(path) 163 | if err != nil { 164 | return err 165 | } 166 | if _, err := zf.Write(contents); err != nil { 167 | return err 168 | } 169 | } 170 | if err := z.Close(); err != nil { 171 | return err 172 | } 173 | 174 | return nil 175 | } 176 | 177 | func invokeGo(cfg *packages.Config, args ...string) error { 178 | stdout := new(bytes.Buffer) 179 | stderr := new(bytes.Buffer) 180 | cmd := exec.Command("go", args...) 181 | cmd.Env = append(append([]string{}, cfg.Env...), "PWD="+cfg.Dir) 182 | cmd.Dir = cfg.Dir 183 | cmd.Stdout = stdout 184 | cmd.Stderr = stderr 185 | if err := cmd.Run(); err != nil { 186 | return fmt.Errorf("go %v: %s: %s", args, err, stderr) 187 | } 188 | return nil 189 | } 190 | 191 | func modCache(exported *Exported) string { 192 | return filepath.Join(exported.temp, "modcache/pkg/mod") 193 | } 194 | 195 | func primaryDir(exported *Exported) string { 196 | return filepath.Join(exported.temp, "primarymod", path.Base(exported.primary)) 197 | } 198 | 199 | func moduleDir(exported *Exported, module string) string { 200 | return filepath.Join(modCache(exported), path.Dir(module), path.Base(module)+"@"+moduleVersion(module)) 201 | } 202 | 203 | var versionSuffixRE = regexp.MustCompile(`v\d+`) 204 | 205 | func moduleVersion(module string) string { 206 | if versionSuffixRE.MatchString(path.Base(module)) { 207 | return path.Base(module) + ".0.0" 208 | } 209 | return "v1.0.0" 210 | } 211 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/packagestest/modules_111.go: -------------------------------------------------------------------------------- 1 | // +build go1.11 2 | 3 | package packagestest 4 | 5 | func init() { 6 | All = append(All, Modules) 7 | } 8 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/packages/visit.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sort" 7 | ) 8 | 9 | // Visit visits all the packages in the import graph whose roots are 10 | // pkgs, calling the optional pre function the first time each package 11 | // is encountered (preorder), and the optional post function after a 12 | // package's dependencies have been visited (postorder). 13 | // The boolean result of pre(pkg) determines whether 14 | // the imports of package pkg are visited. 15 | func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) { 16 | seen := make(map[*Package]bool) 17 | var visit func(*Package) 18 | visit = func(pkg *Package) { 19 | if !seen[pkg] { 20 | seen[pkg] = true 21 | 22 | if pre == nil || pre(pkg) { 23 | paths := make([]string, 0, len(pkg.Imports)) 24 | for path := range pkg.Imports { 25 | paths = append(paths, path) 26 | } 27 | sort.Strings(paths) // Imports is a map, this makes visit stable 28 | for _, path := range paths { 29 | visit(pkg.Imports[path]) 30 | } 31 | } 32 | 33 | if post != nil { 34 | post(pkg) 35 | } 36 | } 37 | } 38 | for _, pkg := range pkgs { 39 | visit(pkg) 40 | } 41 | } 42 | 43 | // PrintErrors prints to os.Stderr the accumulated errors of all 44 | // packages in the import graph rooted at pkgs, dependencies first. 45 | // PrintErrors returns the number of errors printed. 46 | func PrintErrors(pkgs []*Package) int { 47 | var n int 48 | Visit(pkgs, nil, func(pkg *Package) { 49 | for _, err := range pkg.Errors { 50 | fmt.Fprintln(os.Stderr, err) 51 | n++ 52 | } 53 | }) 54 | return n 55 | } 56 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 fastwalk provides a faster version of filepath.Walk for file system 6 | // scanning tools. 7 | package fastwalk 8 | 9 | import ( 10 | "errors" 11 | "os" 12 | "path/filepath" 13 | "runtime" 14 | "sync" 15 | ) 16 | 17 | // TraverseLink is used as a return value from WalkFuncs to indicate that the 18 | // symlink named in the call may be traversed. 19 | var TraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") 20 | 21 | // SkipFiles is a used as a return value from WalkFuncs to indicate that the 22 | // callback should not be called for any other files in the current directory. 23 | // Child directories will still be traversed. 24 | var SkipFiles = errors.New("fastwalk: skip remaining files in directory") 25 | 26 | // Walk is a faster implementation of filepath.Walk. 27 | // 28 | // filepath.Walk's design necessarily calls os.Lstat on each file, 29 | // even if the caller needs less info. 30 | // Many tools need only the type of each file. 31 | // On some platforms, this information is provided directly by the readdir 32 | // system call, avoiding the need to stat each file individually. 33 | // fastwalk_unix.go contains a fork of the syscall routines. 34 | // 35 | // See golang.org/issue/16399 36 | // 37 | // Walk walks the file tree rooted at root, calling walkFn for 38 | // each file or directory in the tree, including root. 39 | // 40 | // If fastWalk returns filepath.SkipDir, the directory is skipped. 41 | // 42 | // Unlike filepath.Walk: 43 | // * file stat calls must be done by the user. 44 | // The only provided metadata is the file type, which does not include 45 | // any permission bits. 46 | // * multiple goroutines stat the filesystem concurrently. The provided 47 | // walkFn must be safe for concurrent use. 48 | // * fastWalk can follow symlinks if walkFn returns the TraverseLink 49 | // sentinel error. It is the walkFn's responsibility to prevent 50 | // fastWalk from going into symlink cycles. 51 | func Walk(root string, walkFn func(path string, typ os.FileMode) error) error { 52 | // TODO(bradfitz): make numWorkers configurable? We used a 53 | // minimum of 4 to give the kernel more info about multiple 54 | // things we want, in hopes its I/O scheduling can take 55 | // advantage of that. Hopefully most are in cache. Maybe 4 is 56 | // even too low of a minimum. Profile more. 57 | numWorkers := 4 58 | if n := runtime.NumCPU(); n > numWorkers { 59 | numWorkers = n 60 | } 61 | 62 | // Make sure to wait for all workers to finish, otherwise 63 | // walkFn could still be called after returning. This Wait call 64 | // runs after close(e.donec) below. 65 | var wg sync.WaitGroup 66 | defer wg.Wait() 67 | 68 | w := &walker{ 69 | fn: walkFn, 70 | enqueuec: make(chan walkItem, numWorkers), // buffered for performance 71 | workc: make(chan walkItem, numWorkers), // buffered for performance 72 | donec: make(chan struct{}), 73 | 74 | // buffered for correctness & not leaking goroutines: 75 | resc: make(chan error, numWorkers), 76 | } 77 | defer close(w.donec) 78 | 79 | for i := 0; i < numWorkers; i++ { 80 | wg.Add(1) 81 | go w.doWork(&wg) 82 | } 83 | todo := []walkItem{{dir: root}} 84 | out := 0 85 | for { 86 | workc := w.workc 87 | var workItem walkItem 88 | if len(todo) == 0 { 89 | workc = nil 90 | } else { 91 | workItem = todo[len(todo)-1] 92 | } 93 | select { 94 | case workc <- workItem: 95 | todo = todo[:len(todo)-1] 96 | out++ 97 | case it := <-w.enqueuec: 98 | todo = append(todo, it) 99 | case err := <-w.resc: 100 | out-- 101 | if err != nil { 102 | return err 103 | } 104 | if out == 0 && len(todo) == 0 { 105 | // It's safe to quit here, as long as the buffered 106 | // enqueue channel isn't also readable, which might 107 | // happen if the worker sends both another unit of 108 | // work and its result before the other select was 109 | // scheduled and both w.resc and w.enqueuec were 110 | // readable. 111 | select { 112 | case it := <-w.enqueuec: 113 | todo = append(todo, it) 114 | default: 115 | return nil 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | // doWork reads directories as instructed (via workc) and runs the 123 | // user's callback function. 124 | func (w *walker) doWork(wg *sync.WaitGroup) { 125 | defer wg.Done() 126 | for { 127 | select { 128 | case <-w.donec: 129 | return 130 | case it := <-w.workc: 131 | select { 132 | case <-w.donec: 133 | return 134 | case w.resc <- w.walk(it.dir, !it.callbackDone): 135 | } 136 | } 137 | } 138 | } 139 | 140 | type walker struct { 141 | fn func(path string, typ os.FileMode) error 142 | 143 | donec chan struct{} // closed on fastWalk's return 144 | workc chan walkItem // to workers 145 | enqueuec chan walkItem // from workers 146 | resc chan error // from workers 147 | } 148 | 149 | type walkItem struct { 150 | dir string 151 | callbackDone bool // callback already called; don't do it again 152 | } 153 | 154 | func (w *walker) enqueue(it walkItem) { 155 | select { 156 | case w.enqueuec <- it: 157 | case <-w.donec: 158 | } 159 | } 160 | 161 | func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { 162 | joined := dirName + string(os.PathSeparator) + baseName 163 | if typ == os.ModeDir { 164 | w.enqueue(walkItem{dir: joined}) 165 | return nil 166 | } 167 | 168 | err := w.fn(joined, typ) 169 | if typ == os.ModeSymlink { 170 | if err == TraverseLink { 171 | // Set callbackDone so we don't call it twice for both the 172 | // symlink-as-symlink and the symlink-as-directory later: 173 | w.enqueue(walkItem{dir: joined, callbackDone: true}) 174 | return nil 175 | } 176 | if err == filepath.SkipDir { 177 | // Permit SkipDir on symlinks too. 178 | return nil 179 | } 180 | } 181 | return err 182 | } 183 | 184 | func (w *walker) walk(root string, runUserCallback bool) error { 185 | if runUserCallback { 186 | err := w.fn(root, os.ModeDir) 187 | if err == filepath.SkipDir { 188 | return nil 189 | } 190 | if err != nil { 191 | return err 192 | } 193 | } 194 | 195 | return readDir(root, w.onDirEnt) 196 | } 197 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // +build freebsd openbsd netbsd 6 | 7 | package fastwalk 8 | 9 | import "syscall" 10 | 11 | func direntInode(dirent *syscall.Dirent) uint64 { 12 | return uint64(dirent.Fileno) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // +build linux darwin 6 | // +build !appengine 7 | 8 | package fastwalk 9 | 10 | import "syscall" 11 | 12 | func direntInode(dirent *syscall.Dirent) uint64 { 13 | return uint64(dirent.Ino) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // +build darwin freebsd openbsd netbsd 6 | 7 | package fastwalk 8 | 9 | import "syscall" 10 | 11 | func direntNamlen(dirent *syscall.Dirent) uint64 { 12 | return uint64(dirent.Namlen) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 | // +build linux 6 | // +build !appengine 7 | 8 | package fastwalk 9 | 10 | import ( 11 | "bytes" 12 | "syscall" 13 | "unsafe" 14 | ) 15 | 16 | func direntNamlen(dirent *syscall.Dirent) uint64 { 17 | const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) 18 | nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) 19 | const nameBufLen = uint16(len(nameBuf)) 20 | limit := dirent.Reclen - fixedHdr 21 | if limit > nameBufLen { 22 | limit = nameBufLen 23 | } 24 | nameLen := bytes.IndexByte(nameBuf[:limit], 0) 25 | if nameLen < 0 { 26 | panic("failed to find terminating 0 byte in dirent") 27 | } 28 | return uint64(nameLen) 29 | } 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd 6 | 7 | package fastwalk 8 | 9 | import ( 10 | "io/ioutil" 11 | "os" 12 | ) 13 | 14 | // readDir calls fn for each directory entry in dirName. 15 | // It does not descend into directories or follow symlinks. 16 | // If fn returns a non-nil error, readDir returns with that error 17 | // immediately. 18 | func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { 19 | fis, err := ioutil.ReadDir(dirName) 20 | if err != nil { 21 | return err 22 | } 23 | skipFiles := false 24 | for _, fi := range fis { 25 | if fi.Mode().IsRegular() && skipFiles { 26 | continue 27 | } 28 | if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { 29 | if err == SkipFiles { 30 | skipFiles = true 31 | continue 32 | } 33 | return err 34 | } 35 | } 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // +build linux darwin freebsd openbsd netbsd 6 | // +build !appengine 7 | 8 | package fastwalk 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | "syscall" 14 | "unsafe" 15 | ) 16 | 17 | const blockSize = 8 << 10 18 | 19 | // unknownFileMode is a sentinel (and bogus) os.FileMode 20 | // value used to represent a syscall.DT_UNKNOWN Dirent.Type. 21 | const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice 22 | 23 | func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { 24 | fd, err := syscall.Open(dirName, 0, 0) 25 | if err != nil { 26 | return &os.PathError{Op: "open", Path: dirName, Err: err} 27 | } 28 | defer syscall.Close(fd) 29 | 30 | // The buffer must be at least a block long. 31 | buf := make([]byte, blockSize) // stack-allocated; doesn't escape 32 | bufp := 0 // starting read position in buf 33 | nbuf := 0 // end valid data in buf 34 | skipFiles := false 35 | for { 36 | if bufp >= nbuf { 37 | bufp = 0 38 | nbuf, err = syscall.ReadDirent(fd, buf) 39 | if err != nil { 40 | return os.NewSyscallError("readdirent", err) 41 | } 42 | if nbuf <= 0 { 43 | return nil 44 | } 45 | } 46 | consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) 47 | bufp += consumed 48 | if name == "" || name == "." || name == ".." { 49 | continue 50 | } 51 | // Fallback for filesystems (like old XFS) that don't 52 | // support Dirent.Type and have DT_UNKNOWN (0) there 53 | // instead. 54 | if typ == unknownFileMode { 55 | fi, err := os.Lstat(dirName + "/" + name) 56 | if err != nil { 57 | // It got deleted in the meantime. 58 | if os.IsNotExist(err) { 59 | continue 60 | } 61 | return err 62 | } 63 | typ = fi.Mode() & os.ModeType 64 | } 65 | if skipFiles && typ.IsRegular() { 66 | continue 67 | } 68 | if err := fn(dirName, name, typ); err != nil { 69 | if err == SkipFiles { 70 | skipFiles = true 71 | continue 72 | } 73 | return err 74 | } 75 | } 76 | } 77 | 78 | func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { 79 | // golang.org/issue/15653 80 | dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0])) 81 | if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { 82 | panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) 83 | } 84 | if len(buf) < int(dirent.Reclen) { 85 | panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) 86 | } 87 | consumed = int(dirent.Reclen) 88 | if direntInode(dirent) == 0 { // File absent in directory. 89 | return 90 | } 91 | switch dirent.Type { 92 | case syscall.DT_REG: 93 | typ = 0 94 | case syscall.DT_DIR: 95 | typ = os.ModeDir 96 | case syscall.DT_LNK: 97 | typ = os.ModeSymlink 98 | case syscall.DT_BLK: 99 | typ = os.ModeDevice 100 | case syscall.DT_FIFO: 101 | typ = os.ModeNamedPipe 102 | case syscall.DT_SOCK: 103 | typ = os.ModeSocket 104 | case syscall.DT_UNKNOWN: 105 | typ = unknownFileMode 106 | default: 107 | // Skip weird things. 108 | // It's probably a DT_WHT (http://lwn.net/Articles/325369/) 109 | // or something. Revisit if/when this package is moved outside 110 | // of goimports. goimports only cares about regular files, 111 | // symlinks, and directories. 112 | return 113 | } 114 | 115 | nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) 116 | nameLen := direntNamlen(dirent) 117 | 118 | // Special cases for common things: 119 | if nameLen == 1 && nameBuf[0] == '.' { 120 | name = "." 121 | } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { 122 | name = ".." 123 | } else { 124 | name = string(nameBuf[:nameLen]) 125 | } 126 | return 127 | } 128 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/gopathwalk/walk.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 gopathwalk is like filepath.Walk but specialized for finding Go 6 | // packages, particularly in $GOPATH and $GOROOT. 7 | package gopathwalk 8 | 9 | import ( 10 | "bufio" 11 | "bytes" 12 | "fmt" 13 | "go/build" 14 | "io/ioutil" 15 | "log" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "golang.org/x/tools/internal/fastwalk" 21 | ) 22 | 23 | // Options controls the behavior of a Walk call. 24 | type Options struct { 25 | Debug bool // Enable debug logging 26 | ModulesEnabled bool // Search module caches. Also disables legacy goimports ignore rules. 27 | } 28 | 29 | // RootType indicates the type of a Root. 30 | type RootType int 31 | 32 | const ( 33 | RootUnknown RootType = iota 34 | RootGOROOT 35 | RootGOPATH 36 | RootCurrentModule 37 | RootModuleCache 38 | ) 39 | 40 | // A Root is a starting point for a Walk. 41 | type Root struct { 42 | Path string 43 | Type RootType 44 | } 45 | 46 | // SrcDirsRoots returns the roots from build.Default.SrcDirs(). Not modules-compatible. 47 | func SrcDirsRoots() []Root { 48 | var roots []Root 49 | roots = append(roots, Root{filepath.Join(build.Default.GOROOT, "src"), RootGOROOT}) 50 | for _, p := range filepath.SplitList(build.Default.GOPATH) { 51 | roots = append(roots, Root{filepath.Join(p, "src"), RootGOPATH}) 52 | } 53 | return roots 54 | } 55 | 56 | // Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. 57 | // For each package found, add will be called (concurrently) with the absolute 58 | // paths of the containing source directory and the package directory. 59 | // add will be called concurrently. 60 | func Walk(roots []Root, add func(root Root, dir string), opts Options) { 61 | for _, root := range roots { 62 | walkDir(root, add, opts) 63 | } 64 | } 65 | 66 | func walkDir(root Root, add func(Root, string), opts Options) { 67 | if _, err := os.Stat(root.Path); os.IsNotExist(err) { 68 | if opts.Debug { 69 | log.Printf("skipping nonexistant directory: %v", root.Path) 70 | } 71 | return 72 | } 73 | if opts.Debug { 74 | log.Printf("scanning %s", root.Path) 75 | } 76 | w := &walker{ 77 | root: root, 78 | add: add, 79 | opts: opts, 80 | } 81 | w.init() 82 | if err := fastwalk.Walk(root.Path, w.walk); err != nil { 83 | log.Printf("gopathwalk: scanning directory %v: %v", root.Path, err) 84 | } 85 | 86 | if opts.Debug { 87 | log.Printf("scanned %s", root.Path) 88 | } 89 | } 90 | 91 | // walker is the callback for fastwalk.Walk. 92 | type walker struct { 93 | root Root // The source directory to scan. 94 | add func(Root, string) // The callback that will be invoked for every possible Go package dir. 95 | opts Options // Options passed to Walk by the user. 96 | 97 | ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. 98 | } 99 | 100 | // init initializes the walker based on its Options. 101 | func (w *walker) init() { 102 | var ignoredPaths []string 103 | if w.root.Type == RootModuleCache { 104 | ignoredPaths = []string{"cache"} 105 | } 106 | if !w.opts.ModulesEnabled && w.root.Type == RootGOPATH { 107 | ignoredPaths = w.getIgnoredDirs(w.root.Path) 108 | ignoredPaths = append(ignoredPaths, "v", "mod") 109 | } 110 | 111 | for _, p := range ignoredPaths { 112 | full := filepath.Join(w.root.Path, p) 113 | if fi, err := os.Stat(full); err == nil { 114 | w.ignoredDirs = append(w.ignoredDirs, fi) 115 | if w.opts.Debug { 116 | log.Printf("Directory added to ignore list: %s", full) 117 | } 118 | } else if w.opts.Debug { 119 | log.Printf("Error statting ignored directory: %v", err) 120 | } 121 | } 122 | } 123 | 124 | // getIgnoredDirs reads an optional config file at /.goimportsignore 125 | // of relative directories to ignore when scanning for go files. 126 | // The provided path is one of the $GOPATH entries with "src" appended. 127 | func (w *walker) getIgnoredDirs(path string) []string { 128 | file := filepath.Join(path, ".goimportsignore") 129 | slurp, err := ioutil.ReadFile(file) 130 | if w.opts.Debug { 131 | if err != nil { 132 | log.Print(err) 133 | } else { 134 | log.Printf("Read %s", file) 135 | } 136 | } 137 | if err != nil { 138 | return nil 139 | } 140 | 141 | var ignoredDirs []string 142 | bs := bufio.NewScanner(bytes.NewReader(slurp)) 143 | for bs.Scan() { 144 | line := strings.TrimSpace(bs.Text()) 145 | if line == "" || strings.HasPrefix(line, "#") { 146 | continue 147 | } 148 | ignoredDirs = append(ignoredDirs, line) 149 | } 150 | return ignoredDirs 151 | } 152 | 153 | func (w *walker) shouldSkipDir(fi os.FileInfo) bool { 154 | for _, ignoredDir := range w.ignoredDirs { 155 | if os.SameFile(fi, ignoredDir) { 156 | return true 157 | } 158 | } 159 | return false 160 | } 161 | 162 | func (w *walker) walk(path string, typ os.FileMode) error { 163 | dir := filepath.Dir(path) 164 | if typ.IsRegular() { 165 | if dir == w.root.Path { 166 | // Doesn't make sense to have regular files 167 | // directly in your $GOPATH/src or $GOROOT/src. 168 | return fastwalk.SkipFiles 169 | } 170 | if !strings.HasSuffix(path, ".go") { 171 | return nil 172 | } 173 | 174 | w.add(w.root, dir) 175 | return fastwalk.SkipFiles 176 | } 177 | if typ == os.ModeDir { 178 | base := filepath.Base(path) 179 | if base == "" || base[0] == '.' || base[0] == '_' || 180 | base == "testdata" || 181 | (w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") || 182 | (!w.opts.ModulesEnabled && base == "node_modules") { 183 | return filepath.SkipDir 184 | } 185 | fi, err := os.Lstat(path) 186 | if err == nil && w.shouldSkipDir(fi) { 187 | return filepath.SkipDir 188 | } 189 | return nil 190 | } 191 | if typ == os.ModeSymlink { 192 | base := filepath.Base(path) 193 | if strings.HasPrefix(base, ".#") { 194 | // Emacs noise. 195 | return nil 196 | } 197 | fi, err := os.Lstat(path) 198 | if err != nil { 199 | // Just ignore it. 200 | return nil 201 | } 202 | if w.shouldTraverse(dir, fi) { 203 | return fastwalk.TraverseLink 204 | } 205 | } 206 | return nil 207 | } 208 | 209 | // shouldTraverse reports whether the symlink fi, found in dir, 210 | // should be followed. It makes sure symlinks were never visited 211 | // before to avoid symlink loops. 212 | func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool { 213 | path := filepath.Join(dir, fi.Name()) 214 | target, err := filepath.EvalSymlinks(path) 215 | if err != nil { 216 | return false 217 | } 218 | ts, err := os.Stat(target) 219 | if err != nil { 220 | fmt.Fprintln(os.Stderr, err) 221 | return false 222 | } 223 | if !ts.IsDir() { 224 | return false 225 | } 226 | if w.shouldSkipDir(ts) { 227 | return false 228 | } 229 | // Check for symlink loops by statting each directory component 230 | // and seeing if any are the same file as ts. 231 | for { 232 | parent := filepath.Dir(path) 233 | if parent == path { 234 | // Made it to the root without seeing a cycle. 235 | // Use this symlink. 236 | return true 237 | } 238 | parentInfo, err := os.Stat(parent) 239 | if err != nil { 240 | return false 241 | } 242 | if os.SameFile(ts, parentInfo) { 243 | // Cycle. Don't traverse. 244 | return false 245 | } 246 | path = parent 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/internal/semver/semver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 semver implements comparison of semantic version strings. 6 | // In this package, semantic version strings must begin with a leading "v", 7 | // as in "v1.0.0". 8 | // 9 | // The general form of a semantic version string accepted by this package is 10 | // 11 | // vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]] 12 | // 13 | // where square brackets indicate optional parts of the syntax; 14 | // MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros; 15 | // PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers 16 | // using only alphanumeric characters and hyphens; and 17 | // all-numeric PRERELEASE identifiers must not have leading zeros. 18 | // 19 | // This package follows Semantic Versioning 2.0.0 (see semver.org) 20 | // with two exceptions. First, it requires the "v" prefix. Second, it recognizes 21 | // vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes) 22 | // as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. 23 | package semver 24 | 25 | // parsed returns the parsed form of a semantic version string. 26 | type parsed struct { 27 | major string 28 | minor string 29 | patch string 30 | short string 31 | prerelease string 32 | build string 33 | err string 34 | } 35 | 36 | // IsValid reports whether v is a valid semantic version string. 37 | func IsValid(v string) bool { 38 | _, ok := parse(v) 39 | return ok 40 | } 41 | 42 | // Canonical returns the canonical formatting of the semantic version v. 43 | // It fills in any missing .MINOR or .PATCH and discards build metadata. 44 | // Two semantic versions compare equal only if their canonical formattings 45 | // are identical strings. 46 | // The canonical invalid semantic version is the empty string. 47 | func Canonical(v string) string { 48 | p, ok := parse(v) 49 | if !ok { 50 | return "" 51 | } 52 | if p.build != "" { 53 | return v[:len(v)-len(p.build)] 54 | } 55 | if p.short != "" { 56 | return v + p.short 57 | } 58 | return v 59 | } 60 | 61 | // Major returns the major version prefix of the semantic version v. 62 | // For example, Major("v2.1.0") == "v2". 63 | // If v is an invalid semantic version string, Major returns the empty string. 64 | func Major(v string) string { 65 | pv, ok := parse(v) 66 | if !ok { 67 | return "" 68 | } 69 | return v[:1+len(pv.major)] 70 | } 71 | 72 | // MajorMinor returns the major.minor version prefix of the semantic version v. 73 | // For example, MajorMinor("v2.1.0") == "v2.1". 74 | // If v is an invalid semantic version string, MajorMinor returns the empty string. 75 | func MajorMinor(v string) string { 76 | pv, ok := parse(v) 77 | if !ok { 78 | return "" 79 | } 80 | i := 1 + len(pv.major) 81 | if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor { 82 | return v[:j] 83 | } 84 | return v[:i] + "." + pv.minor 85 | } 86 | 87 | // Prerelease returns the prerelease suffix of the semantic version v. 88 | // For example, Prerelease("v2.1.0-pre+meta") == "-pre". 89 | // If v is an invalid semantic version string, Prerelease returns the empty string. 90 | func Prerelease(v string) string { 91 | pv, ok := parse(v) 92 | if !ok { 93 | return "" 94 | } 95 | return pv.prerelease 96 | } 97 | 98 | // Build returns the build suffix of the semantic version v. 99 | // For example, Build("v2.1.0+meta") == "+meta". 100 | // If v is an invalid semantic version string, Build returns the empty string. 101 | func Build(v string) string { 102 | pv, ok := parse(v) 103 | if !ok { 104 | return "" 105 | } 106 | return pv.build 107 | } 108 | 109 | // Compare returns an integer comparing two versions according to 110 | // according to semantic version precedence. 111 | // The result will be 0 if v == w, -1 if v < w, or +1 if v > w. 112 | // 113 | // An invalid semantic version string is considered less than a valid one. 114 | // All invalid semantic version strings compare equal to each other. 115 | func Compare(v, w string) int { 116 | pv, ok1 := parse(v) 117 | pw, ok2 := parse(w) 118 | if !ok1 && !ok2 { 119 | return 0 120 | } 121 | if !ok1 { 122 | return -1 123 | } 124 | if !ok2 { 125 | return +1 126 | } 127 | if c := compareInt(pv.major, pw.major); c != 0 { 128 | return c 129 | } 130 | if c := compareInt(pv.minor, pw.minor); c != 0 { 131 | return c 132 | } 133 | if c := compareInt(pv.patch, pw.patch); c != 0 { 134 | return c 135 | } 136 | return comparePrerelease(pv.prerelease, pw.prerelease) 137 | } 138 | 139 | // Max canonicalizes its arguments and then returns the version string 140 | // that compares greater. 141 | func Max(v, w string) string { 142 | v = Canonical(v) 143 | w = Canonical(w) 144 | if Compare(v, w) > 0 { 145 | return v 146 | } 147 | return w 148 | } 149 | 150 | func parse(v string) (p parsed, ok bool) { 151 | if v == "" || v[0] != 'v' { 152 | p.err = "missing v prefix" 153 | return 154 | } 155 | p.major, v, ok = parseInt(v[1:]) 156 | if !ok { 157 | p.err = "bad major version" 158 | return 159 | } 160 | if v == "" { 161 | p.minor = "0" 162 | p.patch = "0" 163 | p.short = ".0.0" 164 | return 165 | } 166 | if v[0] != '.' { 167 | p.err = "bad minor prefix" 168 | ok = false 169 | return 170 | } 171 | p.minor, v, ok = parseInt(v[1:]) 172 | if !ok { 173 | p.err = "bad minor version" 174 | return 175 | } 176 | if v == "" { 177 | p.patch = "0" 178 | p.short = ".0" 179 | return 180 | } 181 | if v[0] != '.' { 182 | p.err = "bad patch prefix" 183 | ok = false 184 | return 185 | } 186 | p.patch, v, ok = parseInt(v[1:]) 187 | if !ok { 188 | p.err = "bad patch version" 189 | return 190 | } 191 | if len(v) > 0 && v[0] == '-' { 192 | p.prerelease, v, ok = parsePrerelease(v) 193 | if !ok { 194 | p.err = "bad prerelease" 195 | return 196 | } 197 | } 198 | if len(v) > 0 && v[0] == '+' { 199 | p.build, v, ok = parseBuild(v) 200 | if !ok { 201 | p.err = "bad build" 202 | return 203 | } 204 | } 205 | if v != "" { 206 | p.err = "junk on end" 207 | ok = false 208 | return 209 | } 210 | ok = true 211 | return 212 | } 213 | 214 | func parseInt(v string) (t, rest string, ok bool) { 215 | if v == "" { 216 | return 217 | } 218 | if v[0] < '0' || '9' < v[0] { 219 | return 220 | } 221 | i := 1 222 | for i < len(v) && '0' <= v[i] && v[i] <= '9' { 223 | i++ 224 | } 225 | if v[0] == '0' && i != 1 { 226 | return 227 | } 228 | return v[:i], v[i:], true 229 | } 230 | 231 | func parsePrerelease(v string) (t, rest string, ok bool) { 232 | // "A pre-release version MAY be denoted by appending a hyphen and 233 | // a series of dot separated identifiers immediately following the patch version. 234 | // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. 235 | // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes." 236 | if v == "" || v[0] != '-' { 237 | return 238 | } 239 | i := 1 240 | start := 1 241 | for i < len(v) && v[i] != '+' { 242 | if !isIdentChar(v[i]) && v[i] != '.' { 243 | return 244 | } 245 | if v[i] == '.' { 246 | if start == i || isBadNum(v[start:i]) { 247 | return 248 | } 249 | start = i + 1 250 | } 251 | i++ 252 | } 253 | if start == i || isBadNum(v[start:i]) { 254 | return 255 | } 256 | return v[:i], v[i:], true 257 | } 258 | 259 | func parseBuild(v string) (t, rest string, ok bool) { 260 | if v == "" || v[0] != '+' { 261 | return 262 | } 263 | i := 1 264 | start := 1 265 | for i < len(v) { 266 | if !isIdentChar(v[i]) { 267 | return 268 | } 269 | if v[i] == '.' { 270 | if start == i { 271 | return 272 | } 273 | start = i + 1 274 | } 275 | i++ 276 | } 277 | if start == i { 278 | return 279 | } 280 | return v[:i], v[i:], true 281 | } 282 | 283 | func isIdentChar(c byte) bool { 284 | return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' 285 | } 286 | 287 | func isBadNum(v string) bool { 288 | i := 0 289 | for i < len(v) && '0' <= v[i] && v[i] <= '9' { 290 | i++ 291 | } 292 | return i == len(v) && i > 1 && v[0] == '0' 293 | } 294 | 295 | func isNum(v string) bool { 296 | i := 0 297 | for i < len(v) && '0' <= v[i] && v[i] <= '9' { 298 | i++ 299 | } 300 | return i == len(v) 301 | } 302 | 303 | func compareInt(x, y string) int { 304 | if x == y { 305 | return 0 306 | } 307 | if len(x) < len(y) { 308 | return -1 309 | } 310 | if len(x) > len(y) { 311 | return +1 312 | } 313 | if x < y { 314 | return -1 315 | } else { 316 | return +1 317 | } 318 | } 319 | 320 | func comparePrerelease(x, y string) int { 321 | // "When major, minor, and patch are equal, a pre-release version has 322 | // lower precedence than a normal version. 323 | // Example: 1.0.0-alpha < 1.0.0. 324 | // Precedence for two pre-release versions with the same major, minor, 325 | // and patch version MUST be determined by comparing each dot separated 326 | // identifier from left to right until a difference is found as follows: 327 | // identifiers consisting of only digits are compared numerically and 328 | // identifiers with letters or hyphens are compared lexically in ASCII 329 | // sort order. Numeric identifiers always have lower precedence than 330 | // non-numeric identifiers. A larger set of pre-release fields has a 331 | // higher precedence than a smaller set, if all of the preceding 332 | // identifiers are equal. 333 | // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 334 | // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0." 335 | if x == y { 336 | return 0 337 | } 338 | if x == "" { 339 | return +1 340 | } 341 | if y == "" { 342 | return -1 343 | } 344 | for x != "" && y != "" { 345 | x = x[1:] // skip - or . 346 | y = y[1:] // skip - or . 347 | var dx, dy string 348 | dx, x = nextIdent(x) 349 | dy, y = nextIdent(y) 350 | if dx != dy { 351 | ix := isNum(dx) 352 | iy := isNum(dy) 353 | if ix != iy { 354 | if ix { 355 | return -1 356 | } else { 357 | return +1 358 | } 359 | } 360 | if ix { 361 | if len(dx) < len(dy) { 362 | return -1 363 | } 364 | if len(dx) > len(dy) { 365 | return +1 366 | } 367 | } 368 | if dx < dy { 369 | return -1 370 | } else { 371 | return +1 372 | } 373 | } 374 | } 375 | if x == "" { 376 | return -1 377 | } else { 378 | return +1 379 | } 380 | } 381 | 382 | func nextIdent(x string) (dx, rest string) { 383 | i := 0 384 | for i < len(x) && x[i] != '.' { 385 | i++ 386 | } 387 | return x[:i], x[i:] 388 | } 389 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393 2 | golang.org/x/tools/go/ast/astutil 3 | golang.org/x/tools/go/buildutil 4 | golang.org/x/tools/go/packages 5 | golang.org/x/tools/go/gcexportdata 6 | golang.org/x/tools/go/internal/cgo 7 | golang.org/x/tools/internal/gopathwalk 8 | golang.org/x/tools/internal/semver 9 | golang.org/x/tools/go/packages/packagestest 10 | golang.org/x/tools/go/internal/gcimporter 11 | golang.org/x/tools/internal/fastwalk 12 | golang.org/x/tools/go/expect 13 | --------------------------------------------------------------------------------