mirror of
https://gitea.com/gitea/tea.git
synced 2024-11-03 04:27:21 -05:00
Add gitea-vet (#121)
Close #119 Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: jolheiser <john.olheiser@gmail.com> Reviewed-on: https://gitea.com/gitea/tea/pulls/121 Reviewed-by: John Olheiser <john.olheiser@gmail.com> Reviewed-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
a35fcb682b
commit
4b059770ea
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
tea
|
tea
|
||||||
|
/gitea-vet
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
.history/
|
.history/
|
||||||
dist/
|
dist/
|
||||||
|
4
Makefile
4
Makefile
@ -68,7 +68,11 @@ fmt:
|
|||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
|
# Default vet
|
||||||
$(GO) vet -mod=vendor $(PACKAGES)
|
$(GO) vet -mod=vendor $(PACKAGES)
|
||||||
|
# Custom vet
|
||||||
|
$(GO) build -mod=vendor gitea.com/jolheiser/gitea-vet
|
||||||
|
$(GO) vet -vettool=gitea-vet $(PACKAGES)
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint:
|
lint:
|
||||||
|
14
build.go
Normal file
14
build.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
//+build vendor
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Libraries that are included to vendor utilities used during build.
|
||||||
|
// These libraries will not be included in a normal compilation.
|
||||||
|
|
||||||
|
import (
|
||||||
|
// for vet
|
||||||
|
_ "gitea.com/jolheiser/gitea-vet"
|
||||||
|
)
|
3
go.mod
3
go.mod
@ -4,6 +4,7 @@ go 1.12
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/sdk/gitea v0.11.2
|
code.gitea.io/sdk/gitea v0.11.2
|
||||||
|
gitea.com/jolheiser/gitea-vet v0.1.0
|
||||||
github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
|
github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||||
@ -11,7 +12,7 @@ require (
|
|||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/urfave/cli/v2 v2.1.1
|
github.com/urfave/cli/v2 v2.1.1
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||||
gopkg.in/yaml.v2 v2.2.8
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
)
|
)
|
||||||
|
17
go.sum
17
go.sum
@ -1,5 +1,7 @@
|
|||||||
code.gitea.io/sdk/gitea v0.11.2 h1:D0xIRlHv3IckzdYOWzHK1bPvlkXdA4LD909UYyBdi1o=
|
code.gitea.io/sdk/gitea v0.11.2 h1:D0xIRlHv3IckzdYOWzHK1bPvlkXdA4LD909UYyBdi1o=
|
||||||
code.gitea.io/sdk/gitea v0.11.2/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
code.gitea.io/sdk/gitea v0.11.2/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
||||||
|
gitea.com/jolheiser/gitea-vet v0.1.0 h1:gJEms9YWbIcrPOEmDOJ+5JZXCYFxNpwxlI73uRulAi4=
|
||||||
|
gitea.com/jolheiser/gitea-vet v0.1.0/go.mod h1:2Oa6TAdEp1N/38oBNh3ZeiSEER60D/CeDaBFv2sdH58=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
@ -70,15 +72,23 @@ github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
|||||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -89,6 +99,13 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI=
|
||||||
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
5
vendor/gitea.com/jolheiser/gitea-vet/.gitignore
generated
vendored
Normal file
5
vendor/gitea.com/jolheiser/gitea-vet/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# GoLand
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
/gitea-vet*
|
19
vendor/gitea.com/jolheiser/gitea-vet/LICENSE
generated
vendored
Normal file
19
vendor/gitea.com/jolheiser/gitea-vet/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 The Gitea Authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
7
vendor/gitea.com/jolheiser/gitea-vet/Makefile
generated
vendored
Normal file
7
vendor/gitea.com/jolheiser/gitea-vet/Makefile
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
go build
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
go fmt ./...
|
7
vendor/gitea.com/jolheiser/gitea-vet/README.md
generated
vendored
Normal file
7
vendor/gitea.com/jolheiser/gitea-vet/README.md
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# gitea-vet
|
||||||
|
`go vet` tool for Gitea
|
||||||
|
|
||||||
|
| Analyzer | Description |
|
||||||
|
|----------|---------------------------------------------------------------------|
|
||||||
|
| Imports | Checks for import sorting. stdlib->code.gitea.io->other |
|
||||||
|
| License | Checks file headers for some form of `Copyright...YYYY...Gitea/Gogs`|
|
54
vendor/gitea.com/jolheiser/gitea-vet/checks/imports.go
generated
vendored
Normal file
54
vendor/gitea.com/jolheiser/gitea-vet/checks/imports.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package checks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Imports = &analysis.Analyzer{
|
||||||
|
Name: "imports",
|
||||||
|
Doc: "check for import order.",
|
||||||
|
Run: runImports,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runImports(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
for _, file := range pass.Files {
|
||||||
|
level := 0
|
||||||
|
for _, im := range file.Imports {
|
||||||
|
var lvl int
|
||||||
|
val := im.Path.Value
|
||||||
|
if importHasPrefix(val, "code.gitea.io") {
|
||||||
|
lvl = 2
|
||||||
|
} else if strings.Contains(val, ".") {
|
||||||
|
lvl = 3
|
||||||
|
} else {
|
||||||
|
lvl = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if lvl < level {
|
||||||
|
pass.Reportf(file.Pos(), "Imports are sorted wrong")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
level = lvl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func importHasPrefix(s, p string) bool {
|
||||||
|
return strings.HasPrefix(s, "\""+p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sliceHasPrefix(s string, prefixes ...string) bool {
|
||||||
|
for _, p := range prefixes {
|
||||||
|
if importHasPrefix(s, p) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
73
vendor/gitea.com/jolheiser/gitea-vet/checks/license.go
generated
vendored
Normal file
73
vendor/gitea.com/jolheiser/gitea-vet/checks/license.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package checks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
header = regexp.MustCompile(`.*Copyright.*\d{4}.*(Gitea|Gogs)`)
|
||||||
|
goGenerate = "//go:generate"
|
||||||
|
buildTag = "// +build"
|
||||||
|
)
|
||||||
|
|
||||||
|
var License = &analysis.Analyzer{
|
||||||
|
Name: "license",
|
||||||
|
Doc: "check for a copyright header.",
|
||||||
|
Run: runLicense,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runLicense(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
for _, file := range pass.Files {
|
||||||
|
if len(file.Comments) == 0 {
|
||||||
|
pass.Reportf(file.Pos(), "Copyright not found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(file.Comments[0].List) == 0 {
|
||||||
|
pass.Reportf(file.Pos(), "Copyright not found or wrong")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
commentGroup := 0
|
||||||
|
if strings.HasPrefix(file.Comments[0].List[0].Text, goGenerate) {
|
||||||
|
if len(file.Comments[0].List) > 1 {
|
||||||
|
pass.Reportf(file.Pos(), "Must be an empty line between the go:generate and the Copyright")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
commentGroup++
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(file.Comments[0].List[0].Text, buildTag) {
|
||||||
|
commentGroup++
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(file.Comments) < commentGroup+1 {
|
||||||
|
pass.Reportf(file.Pos(), "Copyright not found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(file.Comments[commentGroup].List) < 1 {
|
||||||
|
pass.Reportf(file.Pos(), "Copyright not found or wrong")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var check bool
|
||||||
|
for _, comment := range file.Comments[commentGroup].List {
|
||||||
|
if header.MatchString(comment.Text) {
|
||||||
|
check = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !check {
|
||||||
|
pass.Reportf(file.Pos(), "Copyright did not match check")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
5
vendor/gitea.com/jolheiser/gitea-vet/go.mod
generated
vendored
Normal file
5
vendor/gitea.com/jolheiser/gitea-vet/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module gitea.com/jolheiser/gitea-vet
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224
|
20
vendor/gitea.com/jolheiser/gitea-vet/go.sum
generated
vendored
Normal file
20
vendor/gitea.com/jolheiser/gitea-vet/go.sum
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI=
|
||||||
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
17
vendor/gitea.com/jolheiser/gitea-vet/main.go
generated
vendored
Normal file
17
vendor/gitea.com/jolheiser/gitea-vet/main.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.com/jolheiser/gitea-vet/checks"
|
||||||
|
"golang.org/x/tools/go/analysis/unitchecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
unitchecker.Main(
|
||||||
|
checks.Imports,
|
||||||
|
checks.License,
|
||||||
|
)
|
||||||
|
}
|
945
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
945
vendor/golang.org/x/crypto/internal/chacha20/asm_ppc64le.s
generated
vendored
File diff suppressed because it is too large
Load Diff
2
vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
generated
vendored
2
vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
generated
vendored
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine
|
||||||
|
|
||||||
package chacha20
|
package chacha20
|
||||||
|
|
||||||
|
23
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
23
vendor/golang.org/x/crypto/internal/chacha20/chacha_ppc64le.go
generated
vendored
@ -6,22 +6,24 @@
|
|||||||
|
|
||||||
package chacha20
|
package chacha20
|
||||||
|
|
||||||
import "encoding/binary"
|
import (
|
||||||
|
"encoding/binary"
|
||||||
const (
|
|
||||||
bufSize = 256
|
|
||||||
haveAsm = true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var haveAsm = true
|
||||||
|
|
||||||
|
const bufSize = 256
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||||
|
// This implementation can handle buffers that aren't multiples of
|
||||||
|
// 256.
|
||||||
if len(src) >= bufSize {
|
if len(src) >= bufSize {
|
||||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
|
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
|
||||||
}
|
} else if len(src)%bufSize != 0 {
|
||||||
if len(src)%bufSize != 0 {
|
chaCha20_ctr32_vsx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
||||||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
|
||||||
start := len(src) - len(src)%bufSize
|
start := len(src) - len(src)%bufSize
|
||||||
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
||||||
// Unroll loop to XOR 32 bytes per iteration.
|
// Unroll loop to XOR 32 bytes per iteration.
|
||||||
@ -46,7 +48,6 @@ func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|||||||
td[i] = tb[i] ^ v
|
td[i] = tb[i] ^ v
|
||||||
}
|
}
|
||||||
c.len = bufSize - (len(src) % bufSize)
|
c.len = bufSize - (len(src) % bufSize)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
6
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
generated
vendored
6
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
generated
vendored
@ -5,6 +5,7 @@
|
|||||||
package packet
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
@ -78,8 +79,9 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
|||||||
// padding oracle attacks.
|
// padding oracle attacks.
|
||||||
switch priv.PubKeyAlgo {
|
switch priv.PubKeyAlgo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||||
k := priv.PrivateKey.(*rsa.PrivateKey)
|
// Supports both *rsa.PrivateKey and crypto.Decrypter
|
||||||
b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes))
|
k := priv.PrivateKey.(crypto.Decrypter)
|
||||||
|
b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil)
|
||||||
case PubKeyAlgoElGamal:
|
case PubKeyAlgoElGamal:
|
||||||
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
|
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
|
||||||
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
|
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
|
||||||
|
2
vendor/golang.org/x/crypto/openpgp/packet/private_key.go
generated
vendored
2
vendor/golang.org/x/crypto/openpgp/packet/private_key.go
generated
vendored
@ -31,7 +31,7 @@ type PrivateKey struct {
|
|||||||
encryptedData []byte
|
encryptedData []byte
|
||||||
cipher CipherFunction
|
cipher CipherFunction
|
||||||
s2k func(out, in []byte)
|
s2k func(out, in []byte)
|
||||||
PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or a crypto.Signer.
|
PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or crypto.Signer/crypto.Decrypter (Decryptor RSA only).
|
||||||
sha1Checksum bool
|
sha1Checksum bool
|
||||||
iv []byte
|
iv []byte
|
||||||
}
|
}
|
||||||
|
10
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
10
vendor/golang.org/x/crypto/ssh/common.go
generated
vendored
@ -58,6 +58,14 @@ var serverForbiddenKexAlgos = map[string]struct{}{
|
|||||||
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// preferredKexAlgos specifies the default preference for key-exchange algorithms
|
||||||
|
// in preference order.
|
||||||
|
var preferredKexAlgos = []string{
|
||||||
|
kexAlgoCurve25519SHA256,
|
||||||
|
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
|
||||||
|
kexAlgoDH14SHA1,
|
||||||
|
}
|
||||||
|
|
||||||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
|
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
|
||||||
// of authenticating servers) in preference order.
|
// of authenticating servers) in preference order.
|
||||||
var supportedHostKeyAlgos = []string{
|
var supportedHostKeyAlgos = []string{
|
||||||
@ -246,7 +254,7 @@ func (c *Config) SetDefaults() {
|
|||||||
c.Ciphers = ciphers
|
c.Ciphers = ciphers
|
||||||
|
|
||||||
if c.KeyExchanges == nil {
|
if c.KeyExchanges == nil {
|
||||||
c.KeyExchanges = supportedKexAlgos
|
c.KeyExchanges = preferredKexAlgos
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.MACs == nil {
|
if c.MACs == nil {
|
||||||
|
2
vendor/golang.org/x/net/internal/socks/socks.go
generated
vendored
2
vendor/golang.org/x/net/internal/socks/socks.go
generated
vendored
@ -127,7 +127,7 @@ type Dialer struct {
|
|||||||
// establishing the transport connection.
|
// establishing the transport connection.
|
||||||
ProxyDial func(context.Context, string, string) (net.Conn, error)
|
ProxyDial func(context.Context, string, string) (net.Conn, error)
|
||||||
|
|
||||||
// AuthMethods specifies the list of request authention
|
// AuthMethods specifies the list of request authentication
|
||||||
// methods.
|
// methods.
|
||||||
// If empty, SOCKS client requests only AuthMethodNotRequired.
|
// If empty, SOCKS client requests only AuthMethodNotRequired.
|
||||||
AuthMethods []AuthMethod
|
AuthMethods []AuthMethod
|
||||||
|
3
vendor/golang.org/x/tools/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/tools/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/tools/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/tools/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/tools/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/tools/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/tools/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/tools/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
221
vendor/golang.org/x/tools/go/analysis/analysis.go
generated
vendored
Normal file
221
vendor/golang.org/x/tools/go/analysis/analysis.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An Analyzer describes an analysis function and its options.
|
||||||
|
type Analyzer struct {
|
||||||
|
// The Name of the analyzer must be a valid Go identifier
|
||||||
|
// as it may appear in command-line flags, URLs, and so on.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Doc is the documentation for the analyzer.
|
||||||
|
// The part before the first "\n\n" is the title
|
||||||
|
// (no capital or period, max ~60 letters).
|
||||||
|
Doc string
|
||||||
|
|
||||||
|
// Flags defines any flags accepted by the analyzer.
|
||||||
|
// The manner in which these flags are exposed to the user
|
||||||
|
// depends on the driver which runs the analyzer.
|
||||||
|
Flags flag.FlagSet
|
||||||
|
|
||||||
|
// Run applies the analyzer to a package.
|
||||||
|
// It returns an error if the analyzer failed.
|
||||||
|
//
|
||||||
|
// On success, the Run function may return a result
|
||||||
|
// computed by the Analyzer; its type must match ResultType.
|
||||||
|
// The driver makes this result available as an input to
|
||||||
|
// another Analyzer that depends directly on this one (see
|
||||||
|
// Requires) when it analyzes the same package.
|
||||||
|
//
|
||||||
|
// To pass analysis results between packages (and thus
|
||||||
|
// potentially between address spaces), use Facts, which are
|
||||||
|
// serializable.
|
||||||
|
Run func(*Pass) (interface{}, error)
|
||||||
|
|
||||||
|
// RunDespiteErrors allows the driver to invoke
|
||||||
|
// the Run method of this analyzer even on a
|
||||||
|
// package that contains parse or type errors.
|
||||||
|
RunDespiteErrors bool
|
||||||
|
|
||||||
|
// Requires is a set of analyzers that must run successfully
|
||||||
|
// before this one on a given package. This analyzer may inspect
|
||||||
|
// the outputs produced by each analyzer in Requires.
|
||||||
|
// The graph over analyzers implied by Requires edges must be acyclic.
|
||||||
|
//
|
||||||
|
// Requires establishes a "horizontal" dependency between
|
||||||
|
// analysis passes (different analyzers, same package).
|
||||||
|
Requires []*Analyzer
|
||||||
|
|
||||||
|
// ResultType is the type of the optional result of the Run function.
|
||||||
|
ResultType reflect.Type
|
||||||
|
|
||||||
|
// FactTypes indicates that this analyzer imports and exports
|
||||||
|
// Facts of the specified concrete types.
|
||||||
|
// An analyzer that uses facts may assume that its import
|
||||||
|
// dependencies have been similarly analyzed before it runs.
|
||||||
|
// Facts must be pointers.
|
||||||
|
//
|
||||||
|
// FactTypes establishes a "vertical" dependency between
|
||||||
|
// analysis passes (same analyzer, different packages).
|
||||||
|
FactTypes []Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analyzer) String() string { return a.Name }
|
||||||
|
|
||||||
|
// A Pass provides information to the Run function that
|
||||||
|
// applies a specific analyzer to a single Go package.
|
||||||
|
//
|
||||||
|
// It forms the interface between the analysis logic and the driver
|
||||||
|
// program, and has both input and an output components.
|
||||||
|
//
|
||||||
|
// As in a compiler, one pass may depend on the result computed by another.
|
||||||
|
//
|
||||||
|
// The Run function should not call any of the Pass functions concurrently.
|
||||||
|
type Pass struct {
|
||||||
|
Analyzer *Analyzer // the identity of the current analyzer
|
||||||
|
|
||||||
|
// syntax and type information
|
||||||
|
Fset *token.FileSet // file position information
|
||||||
|
Files []*ast.File // the abstract syntax tree of each file
|
||||||
|
OtherFiles []string // names of non-Go files of this package
|
||||||
|
Pkg *types.Package // type information about the package
|
||||||
|
TypesInfo *types.Info // type information about the syntax trees
|
||||||
|
TypesSizes types.Sizes // function for computing sizes of types
|
||||||
|
|
||||||
|
// Report reports a Diagnostic, a finding about a specific location
|
||||||
|
// in the analyzed source code such as a potential mistake.
|
||||||
|
// It may be called by the Run function.
|
||||||
|
Report func(Diagnostic)
|
||||||
|
|
||||||
|
// ResultOf provides the inputs to this analysis pass, which are
|
||||||
|
// the corresponding results of its prerequisite analyzers.
|
||||||
|
// The map keys are the elements of Analysis.Required,
|
||||||
|
// and the type of each corresponding value is the required
|
||||||
|
// analysis's ResultType.
|
||||||
|
ResultOf map[*Analyzer]interface{}
|
||||||
|
|
||||||
|
// -- facts --
|
||||||
|
|
||||||
|
// ImportObjectFact retrieves a fact associated with obj.
|
||||||
|
// Given a value ptr of type *T, where *T satisfies Fact,
|
||||||
|
// ImportObjectFact copies the value to *ptr.
|
||||||
|
//
|
||||||
|
// ImportObjectFact panics if called after the pass is complete.
|
||||||
|
// ImportObjectFact is not concurrency-safe.
|
||||||
|
ImportObjectFact func(obj types.Object, fact Fact) bool
|
||||||
|
|
||||||
|
// ImportPackageFact retrieves a fact associated with package pkg,
|
||||||
|
// which must be this package or one of its dependencies.
|
||||||
|
// See comments for ImportObjectFact.
|
||||||
|
ImportPackageFact func(pkg *types.Package, fact Fact) bool
|
||||||
|
|
||||||
|
// ExportObjectFact associates a fact of type *T with the obj,
|
||||||
|
// replacing any previous fact of that type.
|
||||||
|
//
|
||||||
|
// ExportObjectFact panics if it is called after the pass is
|
||||||
|
// complete, or if obj does not belong to the package being analyzed.
|
||||||
|
// ExportObjectFact is not concurrency-safe.
|
||||||
|
ExportObjectFact func(obj types.Object, fact Fact)
|
||||||
|
|
||||||
|
// ExportPackageFact associates a fact with the current package.
|
||||||
|
// See comments for ExportObjectFact.
|
||||||
|
ExportPackageFact func(fact Fact)
|
||||||
|
|
||||||
|
// AllPackageFacts returns a new slice containing all package facts of the analysis's FactTypes
|
||||||
|
// in unspecified order.
|
||||||
|
// WARNING: This is an experimental API and may change in the future.
|
||||||
|
AllPackageFacts func() []PackageFact
|
||||||
|
|
||||||
|
// AllObjectFacts returns a new slice containing all object facts of the analysis's FactTypes
|
||||||
|
// in unspecified order.
|
||||||
|
// WARNING: This is an experimental API and may change in the future.
|
||||||
|
AllObjectFacts func() []ObjectFact
|
||||||
|
|
||||||
|
/* Further fields may be added in future. */
|
||||||
|
// For example, suggested or applied refactorings.
|
||||||
|
}
|
||||||
|
|
||||||
|
// PackageFact is a package together with an associated fact.
|
||||||
|
// WARNING: This is an experimental API and may change in the future.
|
||||||
|
type PackageFact struct {
|
||||||
|
Package *types.Package
|
||||||
|
Fact Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectFact is an object together with an associated fact.
|
||||||
|
// WARNING: This is an experimental API and may change in the future.
|
||||||
|
type ObjectFact struct {
|
||||||
|
Object types.Object
|
||||||
|
Fact Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reportf is a helper function that reports a Diagnostic using the
|
||||||
|
// specified position and formatted error message.
|
||||||
|
func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
|
||||||
|
msg := fmt.Sprintf(format, args...)
|
||||||
|
pass.Report(Diagnostic{Pos: pos, Message: msg})
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Range interface provides a range. It's equivalent to and satisfied by
|
||||||
|
// ast.Node.
|
||||||
|
type Range interface {
|
||||||
|
Pos() token.Pos // position of first character belonging to the node
|
||||||
|
End() token.Pos // position of first character immediately after the node
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportRangef is a helper function that reports a Diagnostic using the
|
||||||
|
// range provided. ast.Node values can be passed in as the range because
|
||||||
|
// they satisfy the Range interface.
|
||||||
|
func (pass *Pass) ReportRangef(rng Range, format string, args ...interface{}) {
|
||||||
|
msg := fmt.Sprintf(format, args...)
|
||||||
|
pass.Report(Diagnostic{Pos: rng.Pos(), End: rng.End(), Message: msg})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pass *Pass) String() string {
|
||||||
|
return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Fact is an intermediate fact produced during analysis.
|
||||||
|
//
|
||||||
|
// Each fact is associated with a named declaration (a types.Object) or
|
||||||
|
// with a package as a whole. A single object or package may have
|
||||||
|
// multiple associated facts, but only one of any particular fact type.
|
||||||
|
//
|
||||||
|
// A Fact represents a predicate such as "never returns", but does not
|
||||||
|
// represent the subject of the predicate such as "function F" or "package P".
|
||||||
|
//
|
||||||
|
// Facts may be produced in one analysis pass and consumed by another
|
||||||
|
// analysis pass even if these are in different address spaces.
|
||||||
|
// If package P imports Q, all facts about Q produced during
|
||||||
|
// analysis of that package will be available during later analysis of P.
|
||||||
|
// Facts are analogous to type export data in a build system:
|
||||||
|
// just as export data enables separate compilation of several passes,
|
||||||
|
// facts enable "separate analysis".
|
||||||
|
//
|
||||||
|
// Each pass (a, p) starts with the set of facts produced by the
|
||||||
|
// same analyzer a applied to the packages directly imported by p.
|
||||||
|
// The analysis may add facts to the set, and they may be exported in turn.
|
||||||
|
// An analysis's Run function may retrieve facts by calling
|
||||||
|
// Pass.Import{Object,Package}Fact and update them using
|
||||||
|
// Pass.Export{Object,Package}Fact.
|
||||||
|
//
|
||||||
|
// A fact is logically private to its Analysis. To pass values
|
||||||
|
// between different analyzers, use the results mechanism;
|
||||||
|
// see Analyzer.Requires, Analyzer.ResultType, and Pass.ResultOf.
|
||||||
|
//
|
||||||
|
// A Fact type must be a pointer.
|
||||||
|
// Facts are encoded and decoded using encoding/gob.
|
||||||
|
// A Fact may implement the GobEncoder/GobDecoder interfaces
|
||||||
|
// to customize its encoding. Fact encoding should not fail.
|
||||||
|
//
|
||||||
|
// A Fact should not be modified once exported.
|
||||||
|
type Fact interface {
|
||||||
|
AFact() // dummy method to avoid type errors
|
||||||
|
}
|
61
vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
Normal file
61
vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package analysis
|
||||||
|
|
||||||
|
import "go/token"
|
||||||
|
|
||||||
|
// A Diagnostic is a message associated with a source location or range.
|
||||||
|
//
|
||||||
|
// An Analyzer may return a variety of diagnostics; the optional Category,
|
||||||
|
// which should be a constant, may be used to classify them.
|
||||||
|
// It is primarily intended to make it easy to look up documentation.
|
||||||
|
//
|
||||||
|
// If End is provided, the diagnostic is specified to apply to the range between
|
||||||
|
// Pos and End.
|
||||||
|
type Diagnostic struct {
|
||||||
|
Pos token.Pos
|
||||||
|
End token.Pos // optional
|
||||||
|
Category string // optional
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// SuggestedFixes contains suggested fixes for a diagnostic which can be used to perform
|
||||||
|
// edits to a file that address the diagnostic.
|
||||||
|
// TODO(matloob): Should multiple SuggestedFixes be allowed for a diagnostic?
|
||||||
|
// Diagnostics should not contain SuggestedFixes that overlap.
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
SuggestedFixes []SuggestedFix // optional
|
||||||
|
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
Related []RelatedInformation // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelatedInformation contains information related to a diagnostic.
|
||||||
|
// For example, a diagnostic that flags duplicated declarations of a
|
||||||
|
// variable may include one RelatedInformation per existing
|
||||||
|
// declaration.
|
||||||
|
type RelatedInformation struct {
|
||||||
|
Pos token.Pos
|
||||||
|
End token.Pos
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A SuggestedFix is a code change associated with a Diagnostic that a user can choose
|
||||||
|
// to apply to their code. Usually the SuggestedFix is meant to fix the issue flagged
|
||||||
|
// by the diagnostic.
|
||||||
|
// TextEdits for a SuggestedFix should not overlap. TextEdits for a SuggestedFix
|
||||||
|
// should not contain edits for other packages.
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
type SuggestedFix struct {
|
||||||
|
// A description for this suggested fix to be shown to a user deciding
|
||||||
|
// whether to accept it.
|
||||||
|
Message string
|
||||||
|
TextEdits []TextEdit
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TextEdit represents the replacement of the code between Pos and End with the new text.
|
||||||
|
// Each TextEdit should apply to a single file. End should not be earlier in the file than Pos.
|
||||||
|
// Experimental: This API is experimental and may change in the future.
|
||||||
|
type TextEdit struct {
|
||||||
|
// For a pure insertion, End can either be set to Pos or token.NoPos.
|
||||||
|
Pos token.Pos
|
||||||
|
End token.Pos
|
||||||
|
NewText []byte
|
||||||
|
}
|
301
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
Normal file
301
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Package analysis defines the interface between a modular static
|
||||||
|
analysis and an analysis driver program.
|
||||||
|
|
||||||
|
|
||||||
|
Background
|
||||||
|
|
||||||
|
A static analysis is a function that inspects a package of Go code and
|
||||||
|
reports a set of diagnostics (typically mistakes in the code), and
|
||||||
|
perhaps produces other results as well, such as suggested refactorings
|
||||||
|
or other facts. An analysis that reports mistakes is informally called a
|
||||||
|
"checker". For example, the printf checker reports mistakes in
|
||||||
|
fmt.Printf format strings.
|
||||||
|
|
||||||
|
A "modular" analysis is one that inspects one package at a time but can
|
||||||
|
save information from a lower-level package and use it when inspecting a
|
||||||
|
higher-level package, analogous to separate compilation in a toolchain.
|
||||||
|
The printf checker is modular: when it discovers that a function such as
|
||||||
|
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
|
||||||
|
calls to that function too, including calls made from another package.
|
||||||
|
|
||||||
|
By implementing a common interface, checkers from a variety of sources
|
||||||
|
can be easily selected, incorporated, and reused in a wide range of
|
||||||
|
driver programs including command-line tools (such as vet), text editors and
|
||||||
|
IDEs, build and test systems (such as go build, Bazel, or Buck), test
|
||||||
|
frameworks, code review tools, code-base indexers (such as SourceGraph),
|
||||||
|
documentation viewers (such as godoc), batch pipelines for large code
|
||||||
|
bases, and so on.
|
||||||
|
|
||||||
|
|
||||||
|
Analyzer
|
||||||
|
|
||||||
|
The primary type in the API is Analyzer. An Analyzer statically
|
||||||
|
describes an analysis function: its name, documentation, flags,
|
||||||
|
relationship to other analyzers, and of course, its logic.
|
||||||
|
|
||||||
|
To define an analysis, a user declares a (logically constant) variable
|
||||||
|
of type Analyzer. Here is a typical example from one of the analyzers in
|
||||||
|
the go/analysis/passes/ subdirectory:
|
||||||
|
|
||||||
|
package unusedresult
|
||||||
|
|
||||||
|
var Analyzer = &analysis.Analyzer{
|
||||||
|
Name: "unusedresult",
|
||||||
|
Doc: "check for unused results of calls to some functions",
|
||||||
|
Run: run,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
An analysis driver is a program such as vet that runs a set of
|
||||||
|
analyses and prints the diagnostics that they report.
|
||||||
|
The driver program must import the list of Analyzers it needs.
|
||||||
|
Typically each Analyzer resides in a separate package.
|
||||||
|
To add a new Analyzer to an existing driver, add another item to the list:
|
||||||
|
|
||||||
|
import ( "unusedresult"; "nilness"; "printf" )
|
||||||
|
|
||||||
|
var analyses = []*analysis.Analyzer{
|
||||||
|
unusedresult.Analyzer,
|
||||||
|
nilness.Analyzer,
|
||||||
|
printf.Analyzer,
|
||||||
|
}
|
||||||
|
|
||||||
|
A driver may use the name, flags, and documentation to provide on-line
|
||||||
|
help that describes the analyses it performs.
|
||||||
|
The doc comment contains a brief one-line summary,
|
||||||
|
optionally followed by paragraphs of explanation.
|
||||||
|
|
||||||
|
The Analyzer type has more fields besides those shown above:
|
||||||
|
|
||||||
|
type Analyzer struct {
|
||||||
|
Name string
|
||||||
|
Doc string
|
||||||
|
Flags flag.FlagSet
|
||||||
|
Run func(*Pass) (interface{}, error)
|
||||||
|
RunDespiteErrors bool
|
||||||
|
ResultType reflect.Type
|
||||||
|
Requires []*Analyzer
|
||||||
|
FactTypes []Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
The Flags field declares a set of named (global) flag variables that
|
||||||
|
control analysis behavior. Unlike vet, analysis flags are not declared
|
||||||
|
directly in the command line FlagSet; it is up to the driver to set the
|
||||||
|
flag variables. A driver for a single analysis, a, might expose its flag
|
||||||
|
f directly on the command line as -f, whereas a driver for multiple
|
||||||
|
analyses might prefix the flag name by the analysis name (-a.f) to avoid
|
||||||
|
ambiguity. An IDE might expose the flags through a graphical interface,
|
||||||
|
and a batch pipeline might configure them from a config file.
|
||||||
|
See the "findcall" analyzer for an example of flags in action.
|
||||||
|
|
||||||
|
The RunDespiteErrors flag indicates whether the analysis is equipped to
|
||||||
|
handle ill-typed code. If not, the driver will skip the analysis if
|
||||||
|
there were parse or type errors.
|
||||||
|
The optional ResultType field specifies the type of the result value
|
||||||
|
computed by this analysis and made available to other analyses.
|
||||||
|
The Requires field specifies a list of analyses upon which
|
||||||
|
this one depends and whose results it may access, and it constrains the
|
||||||
|
order in which a driver may run analyses.
|
||||||
|
The FactTypes field is discussed in the section on Modularity.
|
||||||
|
The analysis package provides a Validate function to perform basic
|
||||||
|
sanity checks on an Analyzer, such as that its Requires graph is
|
||||||
|
acyclic, its fact and result types are unique, and so on.
|
||||||
|
|
||||||
|
Finally, the Run field contains a function to be called by the driver to
|
||||||
|
execute the analysis on a single package. The driver passes it an
|
||||||
|
instance of the Pass type.
|
||||||
|
|
||||||
|
|
||||||
|
Pass
|
||||||
|
|
||||||
|
A Pass describes a single unit of work: the application of a particular
|
||||||
|
Analyzer to a particular package of Go code.
|
||||||
|
The Pass provides information to the Analyzer's Run function about the
|
||||||
|
package being analyzed, and provides operations to the Run function for
|
||||||
|
reporting diagnostics and other information back to the driver.
|
||||||
|
|
||||||
|
type Pass struct {
|
||||||
|
Fset *token.FileSet
|
||||||
|
Files []*ast.File
|
||||||
|
OtherFiles []string
|
||||||
|
Pkg *types.Package
|
||||||
|
TypesInfo *types.Info
|
||||||
|
ResultOf map[*Analyzer]interface{}
|
||||||
|
Report func(Diagnostic)
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
|
||||||
|
type information, and source positions for a single package of Go code.
|
||||||
|
|
||||||
|
The OtherFiles field provides the names, but not the contents, of non-Go
|
||||||
|
files such as assembly that are part of this package. See the "asmdecl"
|
||||||
|
or "buildtags" analyzers for examples of loading non-Go files and reporting
|
||||||
|
diagnostics against them.
|
||||||
|
|
||||||
|
The ResultOf field provides the results computed by the analyzers
|
||||||
|
required by this one, as expressed in its Analyzer.Requires field. The
|
||||||
|
driver runs the required analyzers first and makes their results
|
||||||
|
available in this map. Each Analyzer must return a value of the type
|
||||||
|
described in its Analyzer.ResultType field.
|
||||||
|
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
|
||||||
|
provides a control-flow graph for each function in the package (see
|
||||||
|
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
|
||||||
|
enables other Analyzers to traverse the syntax trees of the package more
|
||||||
|
efficiently; and the "buildssa" analyzer constructs an SSA-form
|
||||||
|
intermediate representation.
|
||||||
|
Each of these Analyzers extends the capabilities of later Analyzers
|
||||||
|
without adding a dependency to the core API, so an analysis tool pays
|
||||||
|
only for the extensions it needs.
|
||||||
|
|
||||||
|
The Report function emits a diagnostic, a message associated with a
|
||||||
|
source position. For most analyses, diagnostics are their primary
|
||||||
|
result.
|
||||||
|
For convenience, Pass provides a helper method, Reportf, to report a new
|
||||||
|
diagnostic by formatting a string.
|
||||||
|
Diagnostic is defined as:
|
||||||
|
|
||||||
|
type Diagnostic struct {
|
||||||
|
Pos token.Pos
|
||||||
|
Category string // optional
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
The optional Category field is a short identifier that classifies the
|
||||||
|
kind of message when an analysis produces several kinds of diagnostic.
|
||||||
|
|
||||||
|
Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
|
||||||
|
and buildtag, inspect the raw text of Go source files or even non-Go
|
||||||
|
files such as assembly. To report a diagnostic against a line of a
|
||||||
|
raw text file, use the following sequence:
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil { ... }
|
||||||
|
tf := fset.AddFile(filename, -1, len(content))
|
||||||
|
tf.SetLinesForContent(content)
|
||||||
|
...
|
||||||
|
pass.Reportf(tf.LineStart(line), "oops")
|
||||||
|
|
||||||
|
|
||||||
|
Modular analysis with Facts
|
||||||
|
|
||||||
|
To improve efficiency and scalability, large programs are routinely
|
||||||
|
built using separate compilation: units of the program are compiled
|
||||||
|
separately, and recompiled only when one of their dependencies changes;
|
||||||
|
independent modules may be compiled in parallel. The same technique may
|
||||||
|
be applied to static analyses, for the same benefits. Such analyses are
|
||||||
|
described as "modular".
|
||||||
|
|
||||||
|
A compiler’s type checker is an example of a modular static analysis.
|
||||||
|
Many other checkers we would like to apply to Go programs can be
|
||||||
|
understood as alternative or non-standard type systems. For example,
|
||||||
|
vet's printf checker infers whether a function has the "printf wrapper"
|
||||||
|
type, and it applies stricter checks to calls of such functions. In
|
||||||
|
addition, it records which functions are printf wrappers for use by
|
||||||
|
later analysis passes to identify other printf wrappers by induction.
|
||||||
|
A result such as “f is a printf wrapper” that is not interesting by
|
||||||
|
itself but serves as a stepping stone to an interesting result (such as
|
||||||
|
a diagnostic) is called a "fact".
|
||||||
|
|
||||||
|
The analysis API allows an analysis to define new types of facts, to
|
||||||
|
associate facts of these types with objects (named entities) declared
|
||||||
|
within the current package, or with the package as a whole, and to query
|
||||||
|
for an existing fact of a given type associated with an object or
|
||||||
|
package.
|
||||||
|
|
||||||
|
An Analyzer that uses facts must declare their types:
|
||||||
|
|
||||||
|
var Analyzer = &analysis.Analyzer{
|
||||||
|
Name: "printf",
|
||||||
|
FactTypes: []analysis.Fact{new(isWrapper)},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
type isWrapper struct{} // => *types.Func f “is a printf wrapper”
|
||||||
|
|
||||||
|
The driver program ensures that facts for a pass’s dependencies are
|
||||||
|
generated before analyzing the package and is responsible for propagating
|
||||||
|
facts from one package to another, possibly across address spaces.
|
||||||
|
Consequently, Facts must be serializable. The API requires that drivers
|
||||||
|
use the gob encoding, an efficient, robust, self-describing binary
|
||||||
|
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
|
||||||
|
if the default encoding is unsuitable. Facts should be stateless.
|
||||||
|
|
||||||
|
The Pass type has functions to import and export facts,
|
||||||
|
associated either with an object or with a package:
|
||||||
|
|
||||||
|
type Pass struct {
|
||||||
|
...
|
||||||
|
ExportObjectFact func(types.Object, Fact)
|
||||||
|
ImportObjectFact func(types.Object, Fact) bool
|
||||||
|
|
||||||
|
ExportPackageFact func(fact Fact)
|
||||||
|
ImportPackageFact func(*types.Package, Fact) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
An Analyzer may only export facts associated with the current package or
|
||||||
|
its objects, though it may import facts from any package or object that
|
||||||
|
is an import dependency of the current package.
|
||||||
|
|
||||||
|
Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
|
||||||
|
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
|
||||||
|
retrieves the entry from this map and copies its value into the variable
|
||||||
|
pointed to by fact. This scheme assumes that the concrete type of fact
|
||||||
|
is a pointer; this assumption is checked by the Validate function.
|
||||||
|
See the "printf" analyzer for an example of object facts in action.
|
||||||
|
|
||||||
|
Some driver implementations (such as those based on Bazel and Blaze) do
|
||||||
|
not currently apply analyzers to packages of the standard library.
|
||||||
|
Therefore, for best results, analyzer authors should not rely on
|
||||||
|
analysis facts being available for standard packages.
|
||||||
|
For example, although the printf checker is capable of deducing during
|
||||||
|
analysis of the log package that log.Printf is a printf wrapper,
|
||||||
|
this fact is built in to the analyzer so that it correctly checks
|
||||||
|
calls to log.Printf even when run in a driver that does not apply
|
||||||
|
it to standard packages. We would like to remove this limitation in future.
|
||||||
|
|
||||||
|
|
||||||
|
Testing an Analyzer
|
||||||
|
|
||||||
|
The analysistest subpackage provides utilities for testing an Analyzer.
|
||||||
|
In a few lines of code, it is possible to run an analyzer on a package
|
||||||
|
of testdata files and check that it reported all the expected
|
||||||
|
diagnostics and facts (and no more). Expectations are expressed using
|
||||||
|
"// want ..." comments in the input code.
|
||||||
|
|
||||||
|
|
||||||
|
Standalone commands
|
||||||
|
|
||||||
|
Analyzers are provided in the form of packages that a driver program is
|
||||||
|
expected to import. The vet command imports a set of several analyzers,
|
||||||
|
but users may wish to define their own analysis commands that perform
|
||||||
|
additional checks. To simplify the task of creating an analysis command,
|
||||||
|
either for a single analyzer or for a whole suite, we provide the
|
||||||
|
singlechecker and multichecker subpackages.
|
||||||
|
|
||||||
|
The singlechecker package provides the main function for a command that
|
||||||
|
runs one analyzer. By convention, each analyzer such as
|
||||||
|
go/passes/findcall should be accompanied by a singlechecker-based
|
||||||
|
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
|
||||||
|
entirety as:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/go/analysis/passes/findcall"
|
||||||
|
"golang.org/x/tools/go/analysis/singlechecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() { singlechecker.Main(findcall.Analyzer) }
|
||||||
|
|
||||||
|
A tool that provides multiple analyzers can use multichecker in a
|
||||||
|
similar way, giving it the list of Analyzers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package analysis
|
388
vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
generated
vendored
Normal file
388
vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
generated
vendored
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package analysisflags defines helpers for processing flags of
|
||||||
|
// analysis driver tools.
|
||||||
|
package analysisflags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
// flags common to all {single,multi,unit}checkers.
|
||||||
|
var (
|
||||||
|
JSON = false // -json
|
||||||
|
Context = -1 // -c=N: if N>0, display offending line plus N lines of context
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse creates a flag for each of the analyzer's flags,
|
||||||
|
// including (in multi mode) a flag named after the analyzer,
|
||||||
|
// parses the flags, then filters and returns the list of
|
||||||
|
// analyzers enabled by flags.
|
||||||
|
//
|
||||||
|
// The result is intended to be passed to unitchecker.Run or checker.Run.
|
||||||
|
// Use in unitchecker.Run will gob.Register all fact types for the returned
|
||||||
|
// graph of analyzers but of course not the ones only reachable from
|
||||||
|
// dropped analyzers. To avoid inconsistency about which gob types are
|
||||||
|
// registered from run to run, Parse itself gob.Registers all the facts
|
||||||
|
// only reachable from dropped analyzers.
|
||||||
|
// This is not a particularly elegant API, but this is an internal package.
|
||||||
|
func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
|
||||||
|
// Connect each analysis flag to the command line as -analysis.flag.
|
||||||
|
enabled := make(map[*analysis.Analyzer]*triState)
|
||||||
|
for _, a := range analyzers {
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
// Add -NAME flag to enable it.
|
||||||
|
if multi {
|
||||||
|
prefix = a.Name + "."
|
||||||
|
|
||||||
|
enable := new(triState)
|
||||||
|
enableUsage := "enable " + a.Name + " analysis"
|
||||||
|
flag.Var(enable, a.Name, enableUsage)
|
||||||
|
enabled[a] = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Flags.VisitAll(func(f *flag.Flag) {
|
||||||
|
if !multi && flag.Lookup(f.Name) != nil {
|
||||||
|
log.Printf("%s flag -%s would conflict with driver; skipping", a.Name, f.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := prefix + f.Name
|
||||||
|
flag.Var(f.Value, name, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard flags: -flags, -V.
|
||||||
|
printflags := flag.Bool("flags", false, "print analyzer flags in JSON")
|
||||||
|
addVersionFlag()
|
||||||
|
|
||||||
|
// flags common to all checkers
|
||||||
|
flag.BoolVar(&JSON, "json", JSON, "emit JSON output")
|
||||||
|
flag.IntVar(&Context, "c", Context, `display offending line with this many lines of context`)
|
||||||
|
|
||||||
|
// Add shims for legacy vet flags to enable existing
|
||||||
|
// scripts that run vet to continue to work.
|
||||||
|
_ = flag.Bool("source", false, "no effect (deprecated)")
|
||||||
|
_ = flag.Bool("v", false, "no effect (deprecated)")
|
||||||
|
_ = flag.Bool("all", false, "no effect (deprecated)")
|
||||||
|
_ = flag.String("tags", "", "no effect (deprecated)")
|
||||||
|
for old, new := range vetLegacyFlags {
|
||||||
|
newFlag := flag.Lookup(new)
|
||||||
|
if newFlag != nil && flag.Lookup(old) == nil {
|
||||||
|
flag.Var(newFlag.Value, old, "deprecated alias for -"+new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Parse() // (ExitOnError)
|
||||||
|
|
||||||
|
// -flags: print flags so that go vet knows which ones are legitimate.
|
||||||
|
if *printflags {
|
||||||
|
printFlags()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
everything := expand(analyzers)
|
||||||
|
|
||||||
|
// If any -NAME flag is true, run only those analyzers. Otherwise,
|
||||||
|
// if any -NAME flag is false, run all but those analyzers.
|
||||||
|
if multi {
|
||||||
|
var hasTrue, hasFalse bool
|
||||||
|
for _, ts := range enabled {
|
||||||
|
switch *ts {
|
||||||
|
case setTrue:
|
||||||
|
hasTrue = true
|
||||||
|
case setFalse:
|
||||||
|
hasFalse = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var keep []*analysis.Analyzer
|
||||||
|
if hasTrue {
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if *enabled[a] == setTrue {
|
||||||
|
keep = append(keep, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analyzers = keep
|
||||||
|
} else if hasFalse {
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if *enabled[a] != setFalse {
|
||||||
|
keep = append(keep, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analyzers = keep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register fact types of skipped analyzers
|
||||||
|
// in case we encounter them in imported files.
|
||||||
|
kept := expand(analyzers)
|
||||||
|
for a := range everything {
|
||||||
|
if !kept[a] {
|
||||||
|
for _, f := range a.FactTypes {
|
||||||
|
gob.Register(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return analyzers
|
||||||
|
}
|
||||||
|
|
||||||
|
func expand(analyzers []*analysis.Analyzer) map[*analysis.Analyzer]bool {
|
||||||
|
seen := make(map[*analysis.Analyzer]bool)
|
||||||
|
var visitAll func([]*analysis.Analyzer)
|
||||||
|
visitAll = func(analyzers []*analysis.Analyzer) {
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if !seen[a] {
|
||||||
|
seen[a] = true
|
||||||
|
visitAll(a.Requires)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visitAll(analyzers)
|
||||||
|
return seen
|
||||||
|
}
|
||||||
|
|
||||||
|
func printFlags() {
|
||||||
|
type jsonFlag struct {
|
||||||
|
Name string
|
||||||
|
Bool bool
|
||||||
|
Usage string
|
||||||
|
}
|
||||||
|
var flags []jsonFlag = nil
|
||||||
|
flag.VisitAll(func(f *flag.Flag) {
|
||||||
|
// Don't report {single,multi}checker debugging
|
||||||
|
// flags or fix as these have no effect on unitchecker
|
||||||
|
// (as invoked by 'go vet').
|
||||||
|
switch f.Name {
|
||||||
|
case "debug", "cpuprofile", "memprofile", "trace", "fix":
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := f.Value.(interface{ IsBoolFlag() bool })
|
||||||
|
isBool := ok && b.IsBoolFlag()
|
||||||
|
flags = append(flags, jsonFlag{f.Name, isBool, f.Usage})
|
||||||
|
})
|
||||||
|
data, err := json.MarshalIndent(flags, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
os.Stdout.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addVersionFlag registers a -V flag that, if set,
|
||||||
|
// prints the executable version and exits 0.
|
||||||
|
//
|
||||||
|
// If the -V flag already exists — for example, because it was already
|
||||||
|
// registered by a call to cmd/internal/objabi.AddVersionFlag — then
|
||||||
|
// addVersionFlag does nothing.
|
||||||
|
func addVersionFlag() {
|
||||||
|
if flag.Lookup("V") == nil {
|
||||||
|
flag.Var(versionFlag{}, "V", "print version and exit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// versionFlag minimally complies with the -V protocol required by "go vet".
|
||||||
|
type versionFlag struct{}
|
||||||
|
|
||||||
|
func (versionFlag) IsBoolFlag() bool { return true }
|
||||||
|
func (versionFlag) Get() interface{} { return nil }
|
||||||
|
func (versionFlag) String() string { return "" }
|
||||||
|
func (versionFlag) Set(s string) error {
|
||||||
|
if s != "full" {
|
||||||
|
log.Fatalf("unsupported flag value: -V=%s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This replicates the minimal subset of
|
||||||
|
// cmd/internal/objabi.AddVersionFlag, which is private to the
|
||||||
|
// go tool yet forms part of our command-line interface.
|
||||||
|
// TODO(adonovan): clarify the contract.
|
||||||
|
|
||||||
|
// Print the tool version so the build system can track changes.
|
||||||
|
// Formats:
|
||||||
|
// $progname version devel ... buildID=...
|
||||||
|
// $progname version go1.9.1
|
||||||
|
progname := os.Args[0]
|
||||||
|
f, err := os.Open(progname)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
h := sha256.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
fmt.Printf("%s version devel comments-go-here buildID=%02x\n",
|
||||||
|
progname, string(h.Sum(nil)))
|
||||||
|
os.Exit(0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A triState is a boolean that knows whether
|
||||||
|
// it has been set to either true or false.
|
||||||
|
// It is used to identify whether a flag appears;
|
||||||
|
// the standard boolean flag cannot
|
||||||
|
// distinguish missing from unset.
|
||||||
|
// It also satisfies flag.Value.
|
||||||
|
type triState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
unset triState = iota
|
||||||
|
setTrue
|
||||||
|
setFalse
|
||||||
|
)
|
||||||
|
|
||||||
|
func triStateFlag(name string, value triState, usage string) *triState {
|
||||||
|
flag.Var(&value, name, usage)
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
|
||||||
|
// triState implements flag.Value, flag.Getter, and flag.boolFlag.
|
||||||
|
// They work like boolean flags: we can say vet -printf as well as vet -printf=true
|
||||||
|
func (ts *triState) Get() interface{} {
|
||||||
|
return *ts == setTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts triState) isTrue() bool {
|
||||||
|
return ts == setTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *triState) Set(value string) error {
|
||||||
|
b, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
// This error message looks poor but package "flag" adds
|
||||||
|
// "invalid boolean value %q for -NAME: %s"
|
||||||
|
return fmt.Errorf("want true or false")
|
||||||
|
}
|
||||||
|
if b {
|
||||||
|
*ts = setTrue
|
||||||
|
} else {
|
||||||
|
*ts = setFalse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *triState) String() string {
|
||||||
|
switch *ts {
|
||||||
|
case unset:
|
||||||
|
return "true"
|
||||||
|
case setTrue:
|
||||||
|
return "true"
|
||||||
|
case setFalse:
|
||||||
|
return "false"
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts triState) IsBoolFlag() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy flag support
|
||||||
|
|
||||||
|
// vetLegacyFlags maps flags used by legacy vet to their corresponding
|
||||||
|
// new names. The old names will continue to work.
|
||||||
|
var vetLegacyFlags = map[string]string{
|
||||||
|
// Analyzer name changes
|
||||||
|
"bool": "bools",
|
||||||
|
"buildtags": "buildtag",
|
||||||
|
"methods": "stdmethods",
|
||||||
|
"rangeloops": "loopclosure",
|
||||||
|
|
||||||
|
// Analyzer flags
|
||||||
|
"compositewhitelist": "composites.whitelist",
|
||||||
|
"printfuncs": "printf.funcs",
|
||||||
|
"shadowstrict": "shadow.strict",
|
||||||
|
"unusedfuncs": "unusedresult.funcs",
|
||||||
|
"unusedstringmethods": "unusedresult.stringmethods",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- output helpers common to all drivers ----
|
||||||
|
|
||||||
|
// PrintPlain prints a diagnostic in plain text form,
|
||||||
|
// with context specified by the -c flag.
|
||||||
|
func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) {
|
||||||
|
posn := fset.Position(diag.Pos)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s\n", posn, diag.Message)
|
||||||
|
|
||||||
|
// -c=N: show offending line plus N lines of context.
|
||||||
|
if Context >= 0 {
|
||||||
|
posn := fset.Position(diag.Pos)
|
||||||
|
end := fset.Position(diag.End)
|
||||||
|
if !end.IsValid() {
|
||||||
|
end = posn
|
||||||
|
}
|
||||||
|
data, _ := ioutil.ReadFile(posn.Filename)
|
||||||
|
lines := strings.Split(string(data), "\n")
|
||||||
|
for i := posn.Line - Context; i <= end.Line+Context; i++ {
|
||||||
|
if 1 <= i && i <= len(lines) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A JSONTree is a mapping from package ID to analysis name to result.
|
||||||
|
// Each result is either a jsonError or a list of jsonDiagnostic.
|
||||||
|
type JSONTree map[string]map[string]interface{}
|
||||||
|
|
||||||
|
// Add adds the result of analysis 'name' on package 'id'.
|
||||||
|
// The result is either a list of diagnostics or an error.
|
||||||
|
func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
|
||||||
|
var v interface{}
|
||||||
|
if err != nil {
|
||||||
|
type jsonError struct {
|
||||||
|
Err string `json:"error"`
|
||||||
|
}
|
||||||
|
v = jsonError{err.Error()}
|
||||||
|
} else if len(diags) > 0 {
|
||||||
|
type jsonDiagnostic struct {
|
||||||
|
Category string `json:"category,omitempty"`
|
||||||
|
Posn string `json:"posn"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
var diagnostics []jsonDiagnostic
|
||||||
|
// TODO(matloob): Should the JSON diagnostics contain ranges?
|
||||||
|
// If so, how should they be formatted?
|
||||||
|
for _, f := range diags {
|
||||||
|
diagnostics = append(diagnostics, jsonDiagnostic{
|
||||||
|
Category: f.Category,
|
||||||
|
Posn: fset.Position(f.Pos).String(),
|
||||||
|
Message: f.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
v = diagnostics
|
||||||
|
}
|
||||||
|
if v != nil {
|
||||||
|
m, ok := tree[id]
|
||||||
|
if !ok {
|
||||||
|
m = make(map[string]interface{})
|
||||||
|
tree[id] = m
|
||||||
|
}
|
||||||
|
m[name] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tree JSONTree) Print() {
|
||||||
|
data, err := json.MarshalIndent(tree, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("internal error: JSON marshalling failed: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", data)
|
||||||
|
}
|
92
vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
generated
vendored
Normal file
92
vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package analysisflags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
const help = `PROGNAME is a tool for static analysis of Go programs.
|
||||||
|
|
||||||
|
PROGNAME examines Go source code and reports suspicious constructs,
|
||||||
|
such as Printf calls whose arguments do not align with the format
|
||||||
|
string. It uses heuristics that do not guarantee all reports are
|
||||||
|
genuine problems, but it can find errors not caught by the compilers.
|
||||||
|
`
|
||||||
|
|
||||||
|
// Help implements the help subcommand for a multichecker or unitchecker
|
||||||
|
// style command. The optional args specify the analyzers to describe.
|
||||||
|
// Help calls log.Fatal if no such analyzer exists.
|
||||||
|
func Help(progname string, analyzers []*analysis.Analyzer, args []string) {
|
||||||
|
// No args: show summary of all analyzers.
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Println(strings.Replace(help, "PROGNAME", progname, -1))
|
||||||
|
fmt.Println("Registered analyzers:")
|
||||||
|
fmt.Println()
|
||||||
|
sort.Slice(analyzers, func(i, j int) bool {
|
||||||
|
return analyzers[i].Name < analyzers[j].Name
|
||||||
|
})
|
||||||
|
for _, a := range analyzers {
|
||||||
|
title := strings.Split(a.Doc, "\n\n")[0]
|
||||||
|
fmt.Printf(" %-12s %s\n", a.Name, title)
|
||||||
|
}
|
||||||
|
fmt.Println("\nBy default all analyzers are run.")
|
||||||
|
fmt.Println("To select specific analyzers, use the -NAME flag for each one,")
|
||||||
|
fmt.Println(" or -NAME=false to run all analyzers not explicitly disabled.")
|
||||||
|
|
||||||
|
// Show only the core command-line flags.
|
||||||
|
fmt.Println("\nCore flags:")
|
||||||
|
fmt.Println()
|
||||||
|
fs := flag.NewFlagSet("", flag.ExitOnError)
|
||||||
|
flag.VisitAll(func(f *flag.Flag) {
|
||||||
|
if !strings.Contains(f.Name, ".") {
|
||||||
|
fs.Var(f.Value, f.Name, f.Usage)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fs.SetOutput(os.Stdout)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
|
||||||
|
fmt.Printf("\nTo see details and flags of a specific analyzer, run '%s help name'.\n", progname)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show help on specific analyzer(s).
|
||||||
|
outer:
|
||||||
|
for _, arg := range args {
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if a.Name == arg {
|
||||||
|
paras := strings.Split(a.Doc, "\n\n")
|
||||||
|
title := paras[0]
|
||||||
|
fmt.Printf("%s: %s\n", a.Name, title)
|
||||||
|
|
||||||
|
// Show only the flags relating to this analysis,
|
||||||
|
// properly prefixed.
|
||||||
|
first := true
|
||||||
|
fs := flag.NewFlagSet(a.Name, flag.ExitOnError)
|
||||||
|
a.Flags.VisitAll(func(f *flag.Flag) {
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
fmt.Println("\nAnalyzer flags:")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
fs.Var(f.Value, a.Name+"."+f.Name, f.Usage)
|
||||||
|
})
|
||||||
|
fs.SetOutput(os.Stdout)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
|
||||||
|
if len(paras) > 1 {
|
||||||
|
fmt.Printf("\n%s\n", strings.Join(paras[1:], "\n\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Fatalf("Analyzer %q not registered", arg)
|
||||||
|
}
|
||||||
|
}
|
323
vendor/golang.org/x/tools/go/analysis/internal/facts/facts.go
generated
vendored
Normal file
323
vendor/golang.org/x/tools/go/analysis/internal/facts/facts.go
generated
vendored
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package facts defines a serializable set of analysis.Fact.
|
||||||
|
//
|
||||||
|
// It provides a partial implementation of the Fact-related parts of the
|
||||||
|
// analysis.Pass interface for use in analysis drivers such as "go vet"
|
||||||
|
// and other build systems.
|
||||||
|
//
|
||||||
|
// The serial format is unspecified and may change, so the same version
|
||||||
|
// of this package must be used for reading and writing serialized facts.
|
||||||
|
//
|
||||||
|
// The handling of facts in the analysis system parallels the handling
|
||||||
|
// of type information in the compiler: during compilation of package P,
|
||||||
|
// the compiler emits an export data file that describes the type of
|
||||||
|
// every object (named thing) defined in package P, plus every object
|
||||||
|
// indirectly reachable from one of those objects. Thus the downstream
|
||||||
|
// compiler of package Q need only load one export data file per direct
|
||||||
|
// import of Q, and it will learn everything about the API of package P
|
||||||
|
// and everything it needs to know about the API of P's dependencies.
|
||||||
|
//
|
||||||
|
// Similarly, analysis of package P emits a fact set containing facts
|
||||||
|
// about all objects exported from P, plus additional facts about only
|
||||||
|
// those objects of P's dependencies that are reachable from the API of
|
||||||
|
// package P; the downstream analysis of Q need only load one fact set
|
||||||
|
// per direct import of Q.
|
||||||
|
//
|
||||||
|
// The notion of "exportedness" that matters here is that of the
|
||||||
|
// compiler. According to the language spec, a method pkg.T.f is
|
||||||
|
// unexported simply because its name starts with lowercase. But the
|
||||||
|
// compiler must nonetheless export f so that downstream compilations can
|
||||||
|
// accurately ascertain whether pkg.T implements an interface pkg.I
|
||||||
|
// defined as interface{f()}. Exported thus means "described in export
|
||||||
|
// data".
|
||||||
|
//
|
||||||
|
package facts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
"golang.org/x/tools/go/types/objectpath"
|
||||||
|
)
|
||||||
|
|
||||||
|
const debug = false
|
||||||
|
|
||||||
|
// A Set is a set of analysis.Facts.
|
||||||
|
//
|
||||||
|
// Decode creates a Set of facts by reading from the imports of a given
|
||||||
|
// package, and Encode writes out the set. Between these operation,
|
||||||
|
// the Import and Export methods will query and update the set.
|
||||||
|
//
|
||||||
|
// All of Set's methods except String are safe to call concurrently.
|
||||||
|
type Set struct {
|
||||||
|
pkg *types.Package
|
||||||
|
mu sync.Mutex
|
||||||
|
m map[key]analysis.Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
type key struct {
|
||||||
|
pkg *types.Package
|
||||||
|
obj types.Object // (object facts only)
|
||||||
|
t reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportObjectFact implements analysis.Pass.ImportObjectFact.
|
||||||
|
func (s *Set) ImportObjectFact(obj types.Object, ptr analysis.Fact) bool {
|
||||||
|
if obj == nil {
|
||||||
|
panic("nil object")
|
||||||
|
}
|
||||||
|
key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(ptr)}
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if v, ok := s.m[key]; ok {
|
||||||
|
reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportObjectFact implements analysis.Pass.ExportObjectFact.
|
||||||
|
func (s *Set) ExportObjectFact(obj types.Object, fact analysis.Fact) {
|
||||||
|
if obj.Pkg() != s.pkg {
|
||||||
|
log.Panicf("in package %s: ExportObjectFact(%s, %T): can't set fact on object belonging another package",
|
||||||
|
s.pkg, obj, fact)
|
||||||
|
}
|
||||||
|
key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(fact)}
|
||||||
|
s.mu.Lock()
|
||||||
|
s.m[key] = fact // clobber any existing entry
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Set) AllObjectFacts(filter map[reflect.Type]bool) []analysis.ObjectFact {
|
||||||
|
var facts []analysis.ObjectFact
|
||||||
|
s.mu.Lock()
|
||||||
|
for k, v := range s.m {
|
||||||
|
if k.obj != nil && filter[k.t] {
|
||||||
|
facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
return facts
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportPackageFact implements analysis.Pass.ImportPackageFact.
|
||||||
|
func (s *Set) ImportPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
|
||||||
|
if pkg == nil {
|
||||||
|
panic("nil package")
|
||||||
|
}
|
||||||
|
key := key{pkg: pkg, t: reflect.TypeOf(ptr)}
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if v, ok := s.m[key]; ok {
|
||||||
|
reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportPackageFact implements analysis.Pass.ExportPackageFact.
|
||||||
|
func (s *Set) ExportPackageFact(fact analysis.Fact) {
|
||||||
|
key := key{pkg: s.pkg, t: reflect.TypeOf(fact)}
|
||||||
|
s.mu.Lock()
|
||||||
|
s.m[key] = fact // clobber any existing entry
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Set) AllPackageFacts(filter map[reflect.Type]bool) []analysis.PackageFact {
|
||||||
|
var facts []analysis.PackageFact
|
||||||
|
s.mu.Lock()
|
||||||
|
for k, v := range s.m {
|
||||||
|
if k.obj == nil && filter[k.t] {
|
||||||
|
facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
return facts
|
||||||
|
}
|
||||||
|
|
||||||
|
// gobFact is the Gob declaration of a serialized fact.
|
||||||
|
type gobFact struct {
|
||||||
|
PkgPath string // path of package
|
||||||
|
Object objectpath.Path // optional path of object relative to package itself
|
||||||
|
Fact analysis.Fact // type and value of user-defined Fact
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode decodes all the facts relevant to the analysis of package pkg.
|
||||||
|
// The read function reads serialized fact data from an external source
|
||||||
|
// for one of of pkg's direct imports. The empty file is a valid
|
||||||
|
// encoding of an empty fact set.
|
||||||
|
//
|
||||||
|
// It is the caller's responsibility to call gob.Register on all
|
||||||
|
// necessary fact types.
|
||||||
|
func Decode(pkg *types.Package, read func(packagePath string) ([]byte, error)) (*Set, error) {
|
||||||
|
// Compute the import map for this package.
|
||||||
|
// See the package doc comment.
|
||||||
|
packages := importMap(pkg.Imports())
|
||||||
|
|
||||||
|
// Read facts from imported packages.
|
||||||
|
// Facts may describe indirectly imported packages, or their objects.
|
||||||
|
m := make(map[key]analysis.Fact) // one big bucket
|
||||||
|
for _, imp := range pkg.Imports() {
|
||||||
|
logf := func(format string, args ...interface{}) {
|
||||||
|
if debug {
|
||||||
|
prefix := fmt.Sprintf("in %s, importing %s: ",
|
||||||
|
pkg.Path(), imp.Path())
|
||||||
|
log.Print(prefix, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the gob-encoded facts.
|
||||||
|
data, err := read(imp.Path())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("in %s, can't import facts for package %q: %v",
|
||||||
|
pkg.Path(), imp.Path(), err)
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
continue // no facts
|
||||||
|
}
|
||||||
|
var gobFacts []gobFact
|
||||||
|
if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil {
|
||||||
|
return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err)
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
logf("decoded %d facts: %v", len(gobFacts), gobFacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse each one into a key and a Fact.
|
||||||
|
for _, f := range gobFacts {
|
||||||
|
factPkg := packages[f.PkgPath]
|
||||||
|
if factPkg == nil {
|
||||||
|
// Fact relates to a dependency that was
|
||||||
|
// unused in this translation unit. Skip.
|
||||||
|
logf("no package %q; discarding %v", f.PkgPath, f.Fact)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := key{pkg: factPkg, t: reflect.TypeOf(f.Fact)}
|
||||||
|
if f.Object != "" {
|
||||||
|
// object fact
|
||||||
|
obj, err := objectpath.Object(factPkg, f.Object)
|
||||||
|
if err != nil {
|
||||||
|
// (most likely due to unexported object)
|
||||||
|
// TODO(adonovan): audit for other possibilities.
|
||||||
|
logf("no object for path: %v; discarding %s", err, f.Fact)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key.obj = obj
|
||||||
|
logf("read %T fact %s for %v", f.Fact, f.Fact, key.obj)
|
||||||
|
} else {
|
||||||
|
// package fact
|
||||||
|
logf("read %T fact %s for %v", f.Fact, f.Fact, factPkg)
|
||||||
|
}
|
||||||
|
m[key] = f.Fact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Set{pkg: pkg, m: m}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes a set of facts to a memory buffer.
|
||||||
|
//
|
||||||
|
// It may fail if one of the Facts could not be gob-encoded, but this is
|
||||||
|
// a sign of a bug in an Analyzer.
|
||||||
|
func (s *Set) Encode() []byte {
|
||||||
|
|
||||||
|
// TODO(adonovan): opt: use a more efficient encoding
|
||||||
|
// that avoids repeating PkgPath for each fact.
|
||||||
|
|
||||||
|
// Gather all facts, including those from imported packages.
|
||||||
|
var gobFacts []gobFact
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
for k, fact := range s.m {
|
||||||
|
if debug {
|
||||||
|
log.Printf("%v => %s\n", k, fact)
|
||||||
|
}
|
||||||
|
var object objectpath.Path
|
||||||
|
if k.obj != nil {
|
||||||
|
path, err := objectpath.For(k.obj)
|
||||||
|
if err != nil {
|
||||||
|
if debug {
|
||||||
|
log.Printf("discarding fact %s about %s\n", fact, k.obj)
|
||||||
|
}
|
||||||
|
continue // object not accessible from package API; discard fact
|
||||||
|
}
|
||||||
|
object = path
|
||||||
|
}
|
||||||
|
gobFacts = append(gobFacts, gobFact{
|
||||||
|
PkgPath: k.pkg.Path(),
|
||||||
|
Object: object,
|
||||||
|
Fact: fact,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
|
// Sort facts by (package, object, type) for determinism.
|
||||||
|
sort.Slice(gobFacts, func(i, j int) bool {
|
||||||
|
x, y := gobFacts[i], gobFacts[j]
|
||||||
|
if x.PkgPath != y.PkgPath {
|
||||||
|
return x.PkgPath < y.PkgPath
|
||||||
|
}
|
||||||
|
if x.Object != y.Object {
|
||||||
|
return x.Object < y.Object
|
||||||
|
}
|
||||||
|
tx := reflect.TypeOf(x.Fact)
|
||||||
|
ty := reflect.TypeOf(y.Fact)
|
||||||
|
if tx != ty {
|
||||||
|
return tx.String() < ty.String()
|
||||||
|
}
|
||||||
|
return false // equal
|
||||||
|
})
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if len(gobFacts) > 0 {
|
||||||
|
if err := gob.NewEncoder(&buf).Encode(gobFacts); err != nil {
|
||||||
|
// Fact encoding should never fail. Identify the culprit.
|
||||||
|
for _, gf := range gobFacts {
|
||||||
|
if err := gob.NewEncoder(ioutil.Discard).Encode(gf); err != nil {
|
||||||
|
fact := gf.Fact
|
||||||
|
pkgpath := reflect.TypeOf(fact).Elem().PkgPath()
|
||||||
|
log.Panicf("internal error: gob encoding of analysis fact %s failed: %v; please report a bug against fact %T in package %q",
|
||||||
|
fact, err, fact, pkgpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
log.Printf("package %q: encode %d facts, %d bytes\n",
|
||||||
|
s.pkg.Path(), len(gobFacts), buf.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is provided only for debugging, and must not be called
|
||||||
|
// concurrent with any Import/Export method.
|
||||||
|
func (s *Set) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString("{")
|
||||||
|
for k, f := range s.m {
|
||||||
|
if buf.Len() > 1 {
|
||||||
|
buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
if k.obj != nil {
|
||||||
|
buf.WriteString(k.obj.String())
|
||||||
|
} else {
|
||||||
|
buf.WriteString(k.pkg.Path())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, ": %v", f)
|
||||||
|
}
|
||||||
|
buf.WriteString("}")
|
||||||
|
return buf.String()
|
||||||
|
}
|
88
vendor/golang.org/x/tools/go/analysis/internal/facts/imports.go
generated
vendored
Normal file
88
vendor/golang.org/x/tools/go/analysis/internal/facts/imports.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package facts
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
// importMap computes the import map for a package by traversing the
|
||||||
|
// entire exported API each of its imports.
|
||||||
|
//
|
||||||
|
// This is a workaround for the fact that we cannot access the map used
|
||||||
|
// internally by the types.Importer returned by go/importer. The entries
|
||||||
|
// in this map are the packages and objects that may be relevant to the
|
||||||
|
// current analysis unit.
|
||||||
|
//
|
||||||
|
// Packages in the map that are only indirectly imported may be
|
||||||
|
// incomplete (!pkg.Complete()).
|
||||||
|
//
|
||||||
|
func importMap(imports []*types.Package) map[string]*types.Package {
|
||||||
|
objects := make(map[types.Object]bool)
|
||||||
|
packages := make(map[string]*types.Package)
|
||||||
|
|
||||||
|
var addObj func(obj types.Object) bool
|
||||||
|
var addType func(T types.Type)
|
||||||
|
|
||||||
|
addObj = func(obj types.Object) bool {
|
||||||
|
if !objects[obj] {
|
||||||
|
objects[obj] = true
|
||||||
|
addType(obj.Type())
|
||||||
|
if pkg := obj.Pkg(); pkg != nil {
|
||||||
|
packages[pkg.Path()] = pkg
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
addType = func(T types.Type) {
|
||||||
|
switch T := T.(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
// nop
|
||||||
|
case *types.Named:
|
||||||
|
if addObj(T.Obj()) {
|
||||||
|
for i := 0; i < T.NumMethods(); i++ {
|
||||||
|
addObj(T.Method(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *types.Pointer:
|
||||||
|
addType(T.Elem())
|
||||||
|
case *types.Slice:
|
||||||
|
addType(T.Elem())
|
||||||
|
case *types.Array:
|
||||||
|
addType(T.Elem())
|
||||||
|
case *types.Chan:
|
||||||
|
addType(T.Elem())
|
||||||
|
case *types.Map:
|
||||||
|
addType(T.Key())
|
||||||
|
addType(T.Elem())
|
||||||
|
case *types.Signature:
|
||||||
|
addType(T.Params())
|
||||||
|
addType(T.Results())
|
||||||
|
case *types.Struct:
|
||||||
|
for i := 0; i < T.NumFields(); i++ {
|
||||||
|
addObj(T.Field(i))
|
||||||
|
}
|
||||||
|
case *types.Tuple:
|
||||||
|
for i := 0; i < T.Len(); i++ {
|
||||||
|
addObj(T.At(i))
|
||||||
|
}
|
||||||
|
case *types.Interface:
|
||||||
|
for i := 0; i < T.NumMethods(); i++ {
|
||||||
|
addObj(T.Method(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, imp := range imports {
|
||||||
|
packages[imp.Path()] = imp
|
||||||
|
|
||||||
|
scope := imp.Scope()
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
addObj(scope.Lookup(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages
|
||||||
|
}
|
396
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
Normal file
396
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// The unitchecker package defines the main function for an analysis
|
||||||
|
// driver that analyzes a single compilation unit during a build.
|
||||||
|
// It is invoked by a build system such as "go vet":
|
||||||
|
//
|
||||||
|
// $ go vet -vettool=$(which vet)
|
||||||
|
//
|
||||||
|
// It supports the following command-line protocol:
|
||||||
|
//
|
||||||
|
// -V=full describe executable (to the build tool)
|
||||||
|
// -flags describe flags (to the build tool)
|
||||||
|
// foo.cfg description of compilation unit (from the build tool)
|
||||||
|
//
|
||||||
|
// This package does not depend on go/packages.
|
||||||
|
// If you need a standalone tool, use multichecker,
|
||||||
|
// which supports this mode but can also load packages
|
||||||
|
// from source using go/packages.
|
||||||
|
package unitchecker
|
||||||
|
|
||||||
|
// TODO(adonovan):
|
||||||
|
// - with gccgo, go build does not build standard library,
|
||||||
|
// so we will not get to analyze it. Yet we must in order
|
||||||
|
// to create base facts for, say, the fmt package for the
|
||||||
|
// printf checker.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/build"
|
||||||
|
"go/importer"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
"golang.org/x/tools/go/analysis/internal/analysisflags"
|
||||||
|
"golang.org/x/tools/go/analysis/internal/facts"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Config describes a compilation unit to be analyzed.
|
||||||
|
// It is provided to the tool in a JSON-encoded file
|
||||||
|
// whose name ends with ".cfg".
|
||||||
|
type Config struct {
|
||||||
|
ID string // e.g. "fmt [fmt.test]"
|
||||||
|
Compiler string
|
||||||
|
Dir string
|
||||||
|
ImportPath string
|
||||||
|
GoFiles []string
|
||||||
|
NonGoFiles []string
|
||||||
|
ImportMap map[string]string
|
||||||
|
PackageFile map[string]string
|
||||||
|
Standard map[string]bool
|
||||||
|
PackageVetx map[string]string
|
||||||
|
VetxOnly bool
|
||||||
|
VetxOutput string
|
||||||
|
SucceedOnTypecheckFailure bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main is the main function of a vet-like analysis tool that must be
|
||||||
|
// invoked by a build system to analyze a single package.
|
||||||
|
//
|
||||||
|
// The protocol required by 'go vet -vettool=...' is that the tool must support:
|
||||||
|
//
|
||||||
|
// -flags describe flags in JSON
|
||||||
|
// -V=full describe executable for build caching
|
||||||
|
// foo.cfg perform separate modular analyze on the single
|
||||||
|
// unit described by a JSON config file foo.cfg.
|
||||||
|
//
|
||||||
|
func Main(analyzers ...*analysis.Analyzer) {
|
||||||
|
progname := filepath.Base(os.Args[0])
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix(progname + ": ")
|
||||||
|
|
||||||
|
if err := analysis.Validate(analyzers); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, `%[1]s is a tool for static analysis of Go programs.
|
||||||
|
|
||||||
|
Usage of %[1]s:
|
||||||
|
%.16[1]s unit.cfg # execute analysis specified by config file
|
||||||
|
%.16[1]s help # general help
|
||||||
|
%.16[1]s help name # help on specific analyzer and its flags
|
||||||
|
`, progname)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzers = analysisflags.Parse(analyzers, true)
|
||||||
|
|
||||||
|
args := flag.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
}
|
||||||
|
if args[0] == "help" {
|
||||||
|
analysisflags.Help(progname, analyzers, args[1:])
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if len(args) != 1 || !strings.HasSuffix(args[0], ".cfg") {
|
||||||
|
log.Fatalf(`invoking "go tool vet" directly is unsupported; use "go vet"`)
|
||||||
|
}
|
||||||
|
Run(args[0], analyzers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run reads the *.cfg file, runs the analysis,
|
||||||
|
// and calls os.Exit with an appropriate error code.
|
||||||
|
// It assumes flags have already been set.
|
||||||
|
func Run(configFile string, analyzers []*analysis.Analyzer) {
|
||||||
|
cfg, err := readConfig(configFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
results, err := run(fset, cfg, analyzers)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In VetxOnly mode, the analysis is run only for facts.
|
||||||
|
if !cfg.VetxOnly {
|
||||||
|
if analysisflags.JSON {
|
||||||
|
// JSON output
|
||||||
|
tree := make(analysisflags.JSONTree)
|
||||||
|
for _, res := range results {
|
||||||
|
tree.Add(fset, cfg.ID, res.a.Name, res.diagnostics, res.err)
|
||||||
|
}
|
||||||
|
tree.Print()
|
||||||
|
} else {
|
||||||
|
// plain text
|
||||||
|
exit := 0
|
||||||
|
for _, res := range results {
|
||||||
|
if res.err != nil {
|
||||||
|
log.Println(res.err)
|
||||||
|
exit = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, res := range results {
|
||||||
|
for _, diag := range res.diagnostics {
|
||||||
|
analysisflags.PrintPlain(fset, diag)
|
||||||
|
exit = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Exit(exit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readConfig(filename string) (*Config, error) {
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg := new(Config)
|
||||||
|
if err := json.Unmarshal(data, cfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot decode JSON config file %s: %v", filename, err)
|
||||||
|
}
|
||||||
|
if len(cfg.GoFiles) == 0 {
|
||||||
|
// The go command disallows packages with no files.
|
||||||
|
// The only exception is unsafe, but the go command
|
||||||
|
// doesn't call vet on it.
|
||||||
|
return nil, fmt.Errorf("package has no files: %s", cfg.ImportPath)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var importerForCompiler = func(_ *token.FileSet, compiler string, lookup importer.Lookup) types.Importer {
|
||||||
|
// broken legacy implementation (https://golang.org/issue/28995)
|
||||||
|
return importer.For(compiler, lookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]result, error) {
|
||||||
|
// Load, parse, typecheck.
|
||||||
|
var files []*ast.File
|
||||||
|
for _, name := range cfg.GoFiles {
|
||||||
|
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
|
||||||
|
if err != nil {
|
||||||
|
if cfg.SucceedOnTypecheckFailure {
|
||||||
|
// Silently succeed; let the compiler
|
||||||
|
// report parse errors.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
files = append(files, f)
|
||||||
|
}
|
||||||
|
compilerImporter := importerForCompiler(fset, cfg.Compiler, func(path string) (io.ReadCloser, error) {
|
||||||
|
// path is a resolved package path, not an import path.
|
||||||
|
file, ok := cfg.PackageFile[path]
|
||||||
|
if !ok {
|
||||||
|
if cfg.Compiler == "gccgo" && cfg.Standard[path] {
|
||||||
|
return nil, nil // fall back to default gccgo lookup
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no package file for %q", path)
|
||||||
|
}
|
||||||
|
return os.Open(file)
|
||||||
|
})
|
||||||
|
importer := importerFunc(func(importPath string) (*types.Package, error) {
|
||||||
|
path, ok := cfg.ImportMap[importPath] // resolve vendoring, etc
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("can't resolve import %q", path)
|
||||||
|
}
|
||||||
|
return compilerImporter.Import(path)
|
||||||
|
})
|
||||||
|
tc := &types.Config{
|
||||||
|
Importer: importer,
|
||||||
|
Sizes: types.SizesFor("gc", build.Default.GOARCH), // assume gccgo ≡ gc?
|
||||||
|
}
|
||||||
|
info := &types.Info{
|
||||||
|
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||||
|
Defs: make(map[*ast.Ident]types.Object),
|
||||||
|
Uses: make(map[*ast.Ident]types.Object),
|
||||||
|
Implicits: make(map[ast.Node]types.Object),
|
||||||
|
Scopes: make(map[ast.Node]*types.Scope),
|
||||||
|
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||||
|
}
|
||||||
|
pkg, err := tc.Check(cfg.ImportPath, fset, files, info)
|
||||||
|
if err != nil {
|
||||||
|
if cfg.SucceedOnTypecheckFailure {
|
||||||
|
// Silently succeed; let the compiler
|
||||||
|
// report type errors.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register fact types with gob.
|
||||||
|
// In VetxOnly mode, analyzers are only for their facts,
|
||||||
|
// so we can skip any analysis that neither produces facts
|
||||||
|
// nor depends on any analysis that produces facts.
|
||||||
|
// Also build a map to hold working state and result.
|
||||||
|
type action struct {
|
||||||
|
once sync.Once
|
||||||
|
result interface{}
|
||||||
|
err error
|
||||||
|
usesFacts bool // (transitively uses)
|
||||||
|
diagnostics []analysis.Diagnostic
|
||||||
|
}
|
||||||
|
actions := make(map[*analysis.Analyzer]*action)
|
||||||
|
var registerFacts func(a *analysis.Analyzer) bool
|
||||||
|
registerFacts = func(a *analysis.Analyzer) bool {
|
||||||
|
act, ok := actions[a]
|
||||||
|
if !ok {
|
||||||
|
act = new(action)
|
||||||
|
var usesFacts bool
|
||||||
|
for _, f := range a.FactTypes {
|
||||||
|
usesFacts = true
|
||||||
|
gob.Register(f)
|
||||||
|
}
|
||||||
|
for _, req := range a.Requires {
|
||||||
|
if registerFacts(req) {
|
||||||
|
usesFacts = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
act.usesFacts = usesFacts
|
||||||
|
actions[a] = act
|
||||||
|
}
|
||||||
|
return act.usesFacts
|
||||||
|
}
|
||||||
|
var filtered []*analysis.Analyzer
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if registerFacts(a) || !cfg.VetxOnly {
|
||||||
|
filtered = append(filtered, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analyzers = filtered
|
||||||
|
|
||||||
|
// Read facts from imported packages.
|
||||||
|
read := func(path string) ([]byte, error) {
|
||||||
|
if vetx, ok := cfg.PackageVetx[path]; ok {
|
||||||
|
return ioutil.ReadFile(vetx)
|
||||||
|
}
|
||||||
|
return nil, nil // no .vetx file, no facts
|
||||||
|
}
|
||||||
|
facts, err := facts.Decode(pkg, read)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// In parallel, execute the DAG of analyzers.
|
||||||
|
var exec func(a *analysis.Analyzer) *action
|
||||||
|
var execAll func(analyzers []*analysis.Analyzer)
|
||||||
|
exec = func(a *analysis.Analyzer) *action {
|
||||||
|
act := actions[a]
|
||||||
|
act.once.Do(func() {
|
||||||
|
execAll(a.Requires) // prefetch dependencies in parallel
|
||||||
|
|
||||||
|
// The inputs to this analysis are the
|
||||||
|
// results of its prerequisites.
|
||||||
|
inputs := make(map[*analysis.Analyzer]interface{})
|
||||||
|
var failed []string
|
||||||
|
for _, req := range a.Requires {
|
||||||
|
reqact := exec(req)
|
||||||
|
if reqact.err != nil {
|
||||||
|
failed = append(failed, req.String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inputs[req] = reqact.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report an error if any dependency failed.
|
||||||
|
if failed != nil {
|
||||||
|
sort.Strings(failed)
|
||||||
|
act.err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", "))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
factFilter := make(map[reflect.Type]bool)
|
||||||
|
for _, f := range a.FactTypes {
|
||||||
|
factFilter[reflect.TypeOf(f)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Analyzer: a,
|
||||||
|
Fset: fset,
|
||||||
|
Files: files,
|
||||||
|
OtherFiles: cfg.NonGoFiles,
|
||||||
|
Pkg: pkg,
|
||||||
|
TypesInfo: info,
|
||||||
|
TypesSizes: tc.Sizes,
|
||||||
|
ResultOf: inputs,
|
||||||
|
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
||||||
|
ImportObjectFact: facts.ImportObjectFact,
|
||||||
|
ExportObjectFact: facts.ExportObjectFact,
|
||||||
|
AllObjectFacts: func() []analysis.ObjectFact { return facts.AllObjectFacts(factFilter) },
|
||||||
|
ImportPackageFact: facts.ImportPackageFact,
|
||||||
|
ExportPackageFact: facts.ExportPackageFact,
|
||||||
|
AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) },
|
||||||
|
}
|
||||||
|
|
||||||
|
t0 := time.Now()
|
||||||
|
act.result, act.err = a.Run(pass)
|
||||||
|
if false {
|
||||||
|
log.Printf("analysis %s = %s", pass, time.Since(t0))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return act
|
||||||
|
}
|
||||||
|
execAll = func(analyzers []*analysis.Analyzer) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, a := range analyzers {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(a *analysis.Analyzer) {
|
||||||
|
_ = exec(a)
|
||||||
|
wg.Done()
|
||||||
|
}(a)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
execAll(analyzers)
|
||||||
|
|
||||||
|
// Return diagnostics and errors from root analyzers.
|
||||||
|
results := make([]result, len(analyzers))
|
||||||
|
for i, a := range analyzers {
|
||||||
|
act := actions[a]
|
||||||
|
results[i].a = a
|
||||||
|
results[i].err = act.err
|
||||||
|
results[i].diagnostics = act.diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
data := facts.Encode()
|
||||||
|
if err := ioutil.WriteFile(cfg.VetxOutput, data, 0666); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write analysis facts: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
a *analysis.Analyzer
|
||||||
|
diagnostics []analysis.Diagnostic
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type importerFunc func(path string) (*types.Package, error)
|
||||||
|
|
||||||
|
func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
|
9
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go
generated
vendored
Normal file
9
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// +build go1.12
|
||||||
|
|
||||||
|
package unitchecker
|
||||||
|
|
||||||
|
import "go/importer"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
importerForCompiler = importer.ForCompiler
|
||||||
|
}
|
97
vendor/golang.org/x/tools/go/analysis/validate.go
generated
vendored
Normal file
97
vendor/golang.org/x/tools/go/analysis/validate.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validate reports an error if any of the analyzers are misconfigured.
|
||||||
|
// Checks include:
|
||||||
|
// that the name is a valid identifier;
|
||||||
|
// that the Requires graph is acyclic;
|
||||||
|
// that analyzer fact types are unique;
|
||||||
|
// that each fact type is a pointer.
|
||||||
|
func Validate(analyzers []*Analyzer) error {
|
||||||
|
// Map each fact type to its sole generating analyzer.
|
||||||
|
factTypes := make(map[reflect.Type]*Analyzer)
|
||||||
|
|
||||||
|
// Traverse the Requires graph, depth first.
|
||||||
|
const (
|
||||||
|
white = iota
|
||||||
|
grey
|
||||||
|
black
|
||||||
|
finished
|
||||||
|
)
|
||||||
|
color := make(map[*Analyzer]uint8)
|
||||||
|
var visit func(a *Analyzer) error
|
||||||
|
visit = func(a *Analyzer) error {
|
||||||
|
if a == nil {
|
||||||
|
return fmt.Errorf("nil *Analyzer")
|
||||||
|
}
|
||||||
|
if color[a] == white {
|
||||||
|
color[a] = grey
|
||||||
|
|
||||||
|
// names
|
||||||
|
if !validIdent(a.Name) {
|
||||||
|
return fmt.Errorf("invalid analyzer name %q", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Doc == "" {
|
||||||
|
return fmt.Errorf("analyzer %q is undocumented", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fact types
|
||||||
|
for _, f := range a.FactTypes {
|
||||||
|
if f == nil {
|
||||||
|
return fmt.Errorf("analyzer %s has nil FactType", a)
|
||||||
|
}
|
||||||
|
t := reflect.TypeOf(f)
|
||||||
|
if prev := factTypes[t]; prev != nil {
|
||||||
|
return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
|
||||||
|
t, a, prev)
|
||||||
|
}
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
|
||||||
|
}
|
||||||
|
factTypes[t] = a
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursion
|
||||||
|
for i, req := range a.Requires {
|
||||||
|
if err := visit(req); err != nil {
|
||||||
|
return fmt.Errorf("%s.Requires[%d]: %v", a.Name, i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color[a] = black
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if err := visit(a); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject duplicates among analyzers.
|
||||||
|
// Precondition: color[a] == black.
|
||||||
|
// Postcondition: color[a] == finished.
|
||||||
|
for _, a := range analyzers {
|
||||||
|
if color[a] == finished {
|
||||||
|
return fmt.Errorf("duplicate analyzer: %s", a.Name)
|
||||||
|
}
|
||||||
|
color[a] = finished
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validIdent(name string) bool {
|
||||||
|
for i, r := range name {
|
||||||
|
if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name != ""
|
||||||
|
}
|
523
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
523
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package objectpath defines a naming scheme for types.Objects
|
||||||
|
// (that is, named entities in Go programs) relative to their enclosing
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// Type-checker objects are canonical, so they are usually identified by
|
||||||
|
// their address in memory (a pointer), but a pointer has meaning only
|
||||||
|
// within one address space. By contrast, objectpath names allow the
|
||||||
|
// identity of an object to be sent from one program to another,
|
||||||
|
// establishing a correspondence between types.Object variables that are
|
||||||
|
// distinct but logically equivalent.
|
||||||
|
//
|
||||||
|
// A single object may have multiple paths. In this example,
|
||||||
|
// type A struct{ X int }
|
||||||
|
// type B A
|
||||||
|
// the field X has two paths due to its membership of both A and B.
|
||||||
|
// The For(obj) function always returns one of these paths, arbitrarily
|
||||||
|
// but consistently.
|
||||||
|
package objectpath
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Path is an opaque name that identifies a types.Object
|
||||||
|
// relative to its package. Conceptually, the name consists of a
|
||||||
|
// sequence of destructuring operations applied to the package scope
|
||||||
|
// to obtain the original object.
|
||||||
|
// The name does not include the package itself.
|
||||||
|
type Path string
|
||||||
|
|
||||||
|
// Encoding
|
||||||
|
//
|
||||||
|
// An object path is a textual and (with training) human-readable encoding
|
||||||
|
// of a sequence of destructuring operators, starting from a types.Package.
|
||||||
|
// The sequences represent a path through the package/object/type graph.
|
||||||
|
// We classify these operators by their type:
|
||||||
|
//
|
||||||
|
// PO package->object Package.Scope.Lookup
|
||||||
|
// OT object->type Object.Type
|
||||||
|
// TT type->type Type.{Elem,Key,Params,Results,Underlying} [EKPRU]
|
||||||
|
// TO type->object Type.{At,Field,Method,Obj} [AFMO]
|
||||||
|
//
|
||||||
|
// All valid paths start with a package and end at an object
|
||||||
|
// and thus may be defined by the regular language:
|
||||||
|
//
|
||||||
|
// objectpath = PO (OT TT* TO)*
|
||||||
|
//
|
||||||
|
// The concrete encoding follows directly:
|
||||||
|
// - The only PO operator is Package.Scope.Lookup, which requires an identifier.
|
||||||
|
// - The only OT operator is Object.Type,
|
||||||
|
// which we encode as '.' because dot cannot appear in an identifier.
|
||||||
|
// - The TT operators are encoded as [EKPRU].
|
||||||
|
// - The OT operators are encoded as [AFMO];
|
||||||
|
// three of these (At,Field,Method) require an integer operand,
|
||||||
|
// which is encoded as a string of decimal digits.
|
||||||
|
// These indices are stable across different representations
|
||||||
|
// of the same package, even source and export data.
|
||||||
|
//
|
||||||
|
// In the example below,
|
||||||
|
//
|
||||||
|
// package p
|
||||||
|
//
|
||||||
|
// type T interface {
|
||||||
|
// f() (a string, b struct{ X int })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// field X has the path "T.UM0.RA1.F0",
|
||||||
|
// representing the following sequence of operations:
|
||||||
|
//
|
||||||
|
// p.Lookup("T") T
|
||||||
|
// .Type().Underlying().Method(0). f
|
||||||
|
// .Type().Results().At(1) b
|
||||||
|
// .Type().Field(0) X
|
||||||
|
//
|
||||||
|
// The encoding is not maximally compact---every R or P is
|
||||||
|
// followed by an A, for example---but this simplifies the
|
||||||
|
// encoder and decoder.
|
||||||
|
//
|
||||||
|
const (
|
||||||
|
// object->type operators
|
||||||
|
opType = '.' // .Type() (Object)
|
||||||
|
|
||||||
|
// type->type operators
|
||||||
|
opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
|
||||||
|
opKey = 'K' // .Key() (Map)
|
||||||
|
opParams = 'P' // .Params() (Signature)
|
||||||
|
opResults = 'R' // .Results() (Signature)
|
||||||
|
opUnderlying = 'U' // .Underlying() (Named)
|
||||||
|
|
||||||
|
// type->object operators
|
||||||
|
opAt = 'A' // .At(i) (Tuple)
|
||||||
|
opField = 'F' // .Field(i) (Struct)
|
||||||
|
opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
|
||||||
|
opObj = 'O' // .Obj() (Named)
|
||||||
|
)
|
||||||
|
|
||||||
|
// The For function returns the path to an object relative to its package,
|
||||||
|
// or an error if the object is not accessible from the package's Scope.
|
||||||
|
//
|
||||||
|
// The For function guarantees to return a path only for the following objects:
|
||||||
|
// - package-level types
|
||||||
|
// - exported package-level non-types
|
||||||
|
// - methods
|
||||||
|
// - parameter and result variables
|
||||||
|
// - struct fields
|
||||||
|
// These objects are sufficient to define the API of their package.
|
||||||
|
// The objects described by a package's export data are drawn from this set.
|
||||||
|
//
|
||||||
|
// For does not return a path for predeclared names, imported package
|
||||||
|
// names, local names, and unexported package-level names (except
|
||||||
|
// types).
|
||||||
|
//
|
||||||
|
// Example: given this definition,
|
||||||
|
//
|
||||||
|
// package p
|
||||||
|
//
|
||||||
|
// type T interface {
|
||||||
|
// f() (a string, b struct{ X int })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// For(X) would return a path that denotes the following sequence of operations:
|
||||||
|
//
|
||||||
|
// p.Scope().Lookup("T") (TypeName T)
|
||||||
|
// .Type().Underlying().Method(0). (method Func f)
|
||||||
|
// .Type().Results().At(1) (field Var b)
|
||||||
|
// .Type().Field(0) (field Var X)
|
||||||
|
//
|
||||||
|
// where p is the package (*types.Package) to which X belongs.
|
||||||
|
func For(obj types.Object) (Path, error) {
|
||||||
|
pkg := obj.Pkg()
|
||||||
|
|
||||||
|
// This table lists the cases of interest.
|
||||||
|
//
|
||||||
|
// Object Action
|
||||||
|
// ------ ------
|
||||||
|
// nil reject
|
||||||
|
// builtin reject
|
||||||
|
// pkgname reject
|
||||||
|
// label reject
|
||||||
|
// var
|
||||||
|
// package-level accept
|
||||||
|
// func param/result accept
|
||||||
|
// local reject
|
||||||
|
// struct field accept
|
||||||
|
// const
|
||||||
|
// package-level accept
|
||||||
|
// local reject
|
||||||
|
// func
|
||||||
|
// package-level accept
|
||||||
|
// init functions reject
|
||||||
|
// concrete method accept
|
||||||
|
// interface method accept
|
||||||
|
// type
|
||||||
|
// package-level accept
|
||||||
|
// local reject
|
||||||
|
//
|
||||||
|
// The only accessible package-level objects are members of pkg itself.
|
||||||
|
//
|
||||||
|
// The cases are handled in four steps:
|
||||||
|
//
|
||||||
|
// 1. reject nil and builtin
|
||||||
|
// 2. accept package-level objects
|
||||||
|
// 3. reject obviously invalid objects
|
||||||
|
// 4. search the API for the path to the param/result/field/method.
|
||||||
|
|
||||||
|
// 1. reference to nil or builtin?
|
||||||
|
if pkg == nil {
|
||||||
|
return "", fmt.Errorf("predeclared %s has no path", obj)
|
||||||
|
}
|
||||||
|
scope := pkg.Scope()
|
||||||
|
|
||||||
|
// 2. package-level object?
|
||||||
|
if scope.Lookup(obj.Name()) == obj {
|
||||||
|
// Only exported objects (and non-exported types) have a path.
|
||||||
|
// Non-exported types may be referenced by other objects.
|
||||||
|
if _, ok := obj.(*types.TypeName); !ok && !obj.Exported() {
|
||||||
|
return "", fmt.Errorf("no path for non-exported %v", obj)
|
||||||
|
}
|
||||||
|
return Path(obj.Name()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Not a package-level object.
|
||||||
|
// Reject obviously non-viable cases.
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *types.Const, // Only package-level constants have a path.
|
||||||
|
*types.TypeName, // Only package-level types have a path.
|
||||||
|
*types.Label, // Labels are function-local.
|
||||||
|
*types.PkgName: // PkgNames are file-local.
|
||||||
|
return "", fmt.Errorf("no path for %v", obj)
|
||||||
|
|
||||||
|
case *types.Var:
|
||||||
|
// Could be:
|
||||||
|
// - a field (obj.IsField())
|
||||||
|
// - a func parameter or result
|
||||||
|
// - a local var.
|
||||||
|
// Sadly there is no way to distinguish
|
||||||
|
// a param/result from a local
|
||||||
|
// so we must proceed to the find.
|
||||||
|
|
||||||
|
case *types.Func:
|
||||||
|
// A func, if not package-level, must be a method.
|
||||||
|
if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
|
||||||
|
return "", fmt.Errorf("func is not a method: %v", obj)
|
||||||
|
}
|
||||||
|
// TODO(adonovan): opt: if the method is concrete,
|
||||||
|
// do a specialized version of the rest of this function so
|
||||||
|
// that it's O(1) not O(|scope|). Basically 'find' is needed
|
||||||
|
// only for struct fields and interface methods.
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Search the API for the path to the var (field/param/result) or method.
|
||||||
|
|
||||||
|
// First inspect package-level named types.
|
||||||
|
// In the presence of path aliases, these give
|
||||||
|
// the best paths because non-types may
|
||||||
|
// refer to types, but not the reverse.
|
||||||
|
empty := make([]byte, 0, 48) // initial space
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
tname, ok := o.(*types.TypeName)
|
||||||
|
if !ok {
|
||||||
|
continue // handle non-types in second pass
|
||||||
|
}
|
||||||
|
|
||||||
|
path := append(empty, name...)
|
||||||
|
path = append(path, opType)
|
||||||
|
|
||||||
|
T := o.Type()
|
||||||
|
|
||||||
|
if tname.IsAlias() {
|
||||||
|
// type alias
|
||||||
|
if r := find(obj, T, path); r != nil {
|
||||||
|
return Path(r), nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// defined (named) type
|
||||||
|
if r := find(obj, T.Underlying(), append(path, opUnderlying)); r != nil {
|
||||||
|
return Path(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then inspect everything else:
|
||||||
|
// non-types, and declared methods of defined types.
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
o := scope.Lookup(name)
|
||||||
|
path := append(empty, name...)
|
||||||
|
if _, ok := o.(*types.TypeName); !ok {
|
||||||
|
if o.Exported() {
|
||||||
|
// exported non-type (const, var, func)
|
||||||
|
if r := find(obj, o.Type(), append(path, opType)); r != nil {
|
||||||
|
return Path(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect declared methods of defined types.
|
||||||
|
if T, ok := o.Type().(*types.Named); ok {
|
||||||
|
path = append(path, opType)
|
||||||
|
for i := 0; i < T.NumMethods(); i++ {
|
||||||
|
m := T.Method(i)
|
||||||
|
path2 := appendOpArg(path, opMethod, i)
|
||||||
|
if m == obj {
|
||||||
|
return Path(path2), nil // found declared method
|
||||||
|
}
|
||||||
|
if r := find(obj, m.Type(), append(path2, opType)); r != nil {
|
||||||
|
return Path(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("can't find path for %v in %s", obj, pkg.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendOpArg(path []byte, op byte, arg int) []byte {
|
||||||
|
path = append(path, op)
|
||||||
|
path = strconv.AppendInt(path, int64(arg), 10)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// find finds obj within type T, returning the path to it, or nil if not found.
|
||||||
|
func find(obj types.Object, T types.Type, path []byte) []byte {
|
||||||
|
switch T := T.(type) {
|
||||||
|
case *types.Basic, *types.Named:
|
||||||
|
// Named types belonging to pkg were handled already,
|
||||||
|
// so T must belong to another package. No path.
|
||||||
|
return nil
|
||||||
|
case *types.Pointer:
|
||||||
|
return find(obj, T.Elem(), append(path, opElem))
|
||||||
|
case *types.Slice:
|
||||||
|
return find(obj, T.Elem(), append(path, opElem))
|
||||||
|
case *types.Array:
|
||||||
|
return find(obj, T.Elem(), append(path, opElem))
|
||||||
|
case *types.Chan:
|
||||||
|
return find(obj, T.Elem(), append(path, opElem))
|
||||||
|
case *types.Map:
|
||||||
|
if r := find(obj, T.Key(), append(path, opKey)); r != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return find(obj, T.Elem(), append(path, opElem))
|
||||||
|
case *types.Signature:
|
||||||
|
if r := find(obj, T.Params(), append(path, opParams)); r != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return find(obj, T.Results(), append(path, opResults))
|
||||||
|
case *types.Struct:
|
||||||
|
for i := 0; i < T.NumFields(); i++ {
|
||||||
|
f := T.Field(i)
|
||||||
|
path2 := appendOpArg(path, opField, i)
|
||||||
|
if f == obj {
|
||||||
|
return path2 // found field var
|
||||||
|
}
|
||||||
|
if r := find(obj, f.Type(), append(path2, opType)); r != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case *types.Tuple:
|
||||||
|
for i := 0; i < T.Len(); i++ {
|
||||||
|
v := T.At(i)
|
||||||
|
path2 := appendOpArg(path, opAt, i)
|
||||||
|
if v == obj {
|
||||||
|
return path2 // found param/result var
|
||||||
|
}
|
||||||
|
if r := find(obj, v.Type(), append(path2, opType)); r != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case *types.Interface:
|
||||||
|
for i := 0; i < T.NumMethods(); i++ {
|
||||||
|
m := T.Method(i)
|
||||||
|
path2 := appendOpArg(path, opMethod, i)
|
||||||
|
if m == obj {
|
||||||
|
return path2 // found interface method
|
||||||
|
}
|
||||||
|
if r := find(obj, m.Type(), append(path2, opType)); r != nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
panic(T)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object returns the object denoted by path p within the package pkg.
|
||||||
|
func Object(pkg *types.Package, p Path) (types.Object, error) {
|
||||||
|
if p == "" {
|
||||||
|
return nil, fmt.Errorf("empty path")
|
||||||
|
}
|
||||||
|
|
||||||
|
pathstr := string(p)
|
||||||
|
var pkgobj, suffix string
|
||||||
|
if dot := strings.IndexByte(pathstr, opType); dot < 0 {
|
||||||
|
pkgobj = pathstr
|
||||||
|
} else {
|
||||||
|
pkgobj = pathstr[:dot]
|
||||||
|
suffix = pathstr[dot:] // suffix starts with "."
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := pkg.Scope().Lookup(pkgobj)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, fmt.Errorf("package %s does not contain %q", pkg.Path(), pkgobj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstraction of *types.{Pointer,Slice,Array,Chan,Map}
|
||||||
|
type hasElem interface {
|
||||||
|
Elem() types.Type
|
||||||
|
}
|
||||||
|
// abstraction of *types.{Interface,Named}
|
||||||
|
type hasMethods interface {
|
||||||
|
Method(int) *types.Func
|
||||||
|
NumMethods() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// The loop state is the pair (t, obj),
|
||||||
|
// exactly one of which is non-nil, initially obj.
|
||||||
|
// All suffixes start with '.' (the only object->type operation),
|
||||||
|
// followed by optional type->type operations,
|
||||||
|
// then a type->object operation.
|
||||||
|
// The cycle then repeats.
|
||||||
|
var t types.Type
|
||||||
|
for suffix != "" {
|
||||||
|
code := suffix[0]
|
||||||
|
suffix = suffix[1:]
|
||||||
|
|
||||||
|
// Codes [AFM] have an integer operand.
|
||||||
|
var index int
|
||||||
|
switch code {
|
||||||
|
case opAt, opField, opMethod:
|
||||||
|
rest := strings.TrimLeft(suffix, "0123456789")
|
||||||
|
numerals := suffix[:len(suffix)-len(rest)]
|
||||||
|
suffix = rest
|
||||||
|
i, err := strconv.Atoi(numerals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid path: bad numeric operand %q for code %q", numerals, code)
|
||||||
|
}
|
||||||
|
index = int(i)
|
||||||
|
case opObj:
|
||||||
|
// no operand
|
||||||
|
default:
|
||||||
|
// The suffix must end with a type->object operation.
|
||||||
|
if suffix == "" {
|
||||||
|
return nil, fmt.Errorf("invalid path: ends with %q, want [AFMO]", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if code == opType {
|
||||||
|
if t != nil {
|
||||||
|
return nil, fmt.Errorf("invalid path: unexpected %q in type context", opType)
|
||||||
|
}
|
||||||
|
t = obj.Type()
|
||||||
|
obj = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
return nil, fmt.Errorf("invalid path: code %q in object context", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inv: t != nil, obj == nil
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case opElem:
|
||||||
|
hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want pointer, slice, array, chan or map)", code, t, t)
|
||||||
|
}
|
||||||
|
t = hasElem.Elem()
|
||||||
|
|
||||||
|
case opKey:
|
||||||
|
mapType, ok := t.(*types.Map)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want map)", code, t, t)
|
||||||
|
}
|
||||||
|
t = mapType.Key()
|
||||||
|
|
||||||
|
case opParams:
|
||||||
|
sig, ok := t.(*types.Signature)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
|
||||||
|
}
|
||||||
|
t = sig.Params()
|
||||||
|
|
||||||
|
case opResults:
|
||||||
|
sig, ok := t.(*types.Signature)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
|
||||||
|
}
|
||||||
|
t = sig.Results()
|
||||||
|
|
||||||
|
case opUnderlying:
|
||||||
|
named, ok := t.(*types.Named)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t)
|
||||||
|
}
|
||||||
|
t = named.Underlying()
|
||||||
|
|
||||||
|
case opAt:
|
||||||
|
tuple, ok := t.(*types.Tuple)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %s, want tuple)", code, t, t)
|
||||||
|
}
|
||||||
|
if n := tuple.Len(); index >= n {
|
||||||
|
return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
|
||||||
|
}
|
||||||
|
obj = tuple.At(index)
|
||||||
|
t = nil
|
||||||
|
|
||||||
|
case opField:
|
||||||
|
structType, ok := t.(*types.Struct)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want struct)", code, t, t)
|
||||||
|
}
|
||||||
|
if n := structType.NumFields(); index >= n {
|
||||||
|
return nil, fmt.Errorf("field index %d out of range [0-%d)", index, n)
|
||||||
|
}
|
||||||
|
obj = structType.Field(index)
|
||||||
|
t = nil
|
||||||
|
|
||||||
|
case opMethod:
|
||||||
|
hasMethods, ok := t.(hasMethods) // Interface or Named
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %s, want interface or named)", code, t, t)
|
||||||
|
}
|
||||||
|
if n := hasMethods.NumMethods(); index >= n {
|
||||||
|
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, n)
|
||||||
|
}
|
||||||
|
obj = hasMethods.Method(index)
|
||||||
|
t = nil
|
||||||
|
|
||||||
|
case opObj:
|
||||||
|
named, ok := t.(*types.Named)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t)
|
||||||
|
}
|
||||||
|
obj = named.Obj()
|
||||||
|
t = nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid path: unknown code %q", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Pkg() != pkg {
|
||||||
|
return nil, fmt.Errorf("path denotes %s, which belongs to a different package", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj, nil // success
|
||||||
|
}
|
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@ -1,5 +1,8 @@
|
|||||||
# code.gitea.io/sdk/gitea v0.11.2
|
# code.gitea.io/sdk/gitea v0.11.2
|
||||||
code.gitea.io/sdk/gitea
|
code.gitea.io/sdk/gitea
|
||||||
|
# gitea.com/jolheiser/gitea-vet v0.1.0
|
||||||
|
gitea.com/jolheiser/gitea-vet
|
||||||
|
gitea.com/jolheiser/gitea-vet/checks
|
||||||
# github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
|
# github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
|
||||||
github.com/araddon/dateparse
|
github.com/araddon/dateparse
|
||||||
# github.com/cpuguy83/go-md2man/v2 v2.0.0
|
# github.com/cpuguy83/go-md2man/v2 v2.0.0
|
||||||
@ -46,7 +49,7 @@ github.com/stretchr/testify/assert
|
|||||||
github.com/urfave/cli/v2
|
github.com/urfave/cli/v2
|
||||||
# github.com/xanzy/ssh-agent v0.2.1
|
# github.com/xanzy/ssh-agent v0.2.1
|
||||||
github.com/xanzy/ssh-agent
|
github.com/xanzy/ssh-agent
|
||||||
# golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
# golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||||
golang.org/x/crypto/cast5
|
golang.org/x/crypto/cast5
|
||||||
golang.org/x/crypto/curve25519
|
golang.org/x/crypto/curve25519
|
||||||
golang.org/x/crypto/ed25519
|
golang.org/x/crypto/ed25519
|
||||||
@ -64,7 +67,7 @@ golang.org/x/crypto/ssh
|
|||||||
golang.org/x/crypto/ssh/agent
|
golang.org/x/crypto/ssh/agent
|
||||||
golang.org/x/crypto/ssh/knownhosts
|
golang.org/x/crypto/ssh/knownhosts
|
||||||
golang.org/x/crypto/ssh/terminal
|
golang.org/x/crypto/ssh/terminal
|
||||||
# golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
|
# golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
|
||||||
golang.org/x/net/context
|
golang.org/x/net/context
|
||||||
golang.org/x/net/internal/socks
|
golang.org/x/net/internal/socks
|
||||||
golang.org/x/net/proxy
|
golang.org/x/net/proxy
|
||||||
@ -72,6 +75,12 @@ golang.org/x/net/proxy
|
|||||||
golang.org/x/sys/cpu
|
golang.org/x/sys/cpu
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
|
# golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224
|
||||||
|
golang.org/x/tools/go/analysis
|
||||||
|
golang.org/x/tools/go/analysis/internal/analysisflags
|
||||||
|
golang.org/x/tools/go/analysis/internal/facts
|
||||||
|
golang.org/x/tools/go/analysis/unitchecker
|
||||||
|
golang.org/x/tools/go/types/objectpath
|
||||||
# gopkg.in/src-d/go-billy.v4 v4.3.2
|
# gopkg.in/src-d/go-billy.v4 v4.3.2
|
||||||
gopkg.in/src-d/go-billy.v4
|
gopkg.in/src-d/go-billy.v4
|
||||||
gopkg.in/src-d/go-billy.v4/helper/chroot
|
gopkg.in/src-d/go-billy.v4/helper/chroot
|
||||||
|
Loading…
Reference in New Issue
Block a user