diff --git a/.golangci.yml b/.golangci.yml index f8247f04999..e156c0154a0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -14,6 +14,7 @@ linters: - depguard - dupl - errcheck + - funlen - gochecknoglobals - gochecknoinits - goconst diff --git a/tests/tools/go.mod b/tests/tools/go.mod index 4efbca22244..1ba39f8d346 100644 --- a/tests/tools/go.mod +++ b/tests/tools/go.mod @@ -1,10 +1,10 @@ module github.com/containers/buildah/tests/tools -go 1.12 +go 1.14 require ( github.com/cpuguy83/go-md2man v1.0.10 - github.com/golangci/golangci-lint v1.17.1 + github.com/golangci/golangci-lint v1.18.0 github.com/onsi/ginkgo v1.8.0 github.com/vbatts/git-validation v1.0.0 ) diff --git a/tests/tools/go.sum b/tests/tools/go.sum index d92b61a8750..c2ae9738858 100644 --- a/tests/tools/go.sum +++ b/tests/tools/go.sum @@ -1,7 +1,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2 h1:HTOmFEEYrWi4MW5ZKUx6xfeyM10Sx3kQF65xiQJMPYA= -github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= +github.com/OpenPeeDeeP/depguard v1.0.0 h1:k9QF73nrHT3nPLz3lu6G5s+3Hi8Je36ODr1F5gjAXXM= +github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -11,8 +11,8 @@ github.com/fatih/color v1.6.0 h1:66qjqZk8kalYAvDRtM1AdAJQI0tj4Wrue3Eq3B3pmFU= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-critic/go-critic v0.0.0-20181204210945-1df300866540 h1:7CU1IXBpPvxpQ/NqJrpuMXMHAw+FB2vfqtRF8tgW9fw= -github.com/go-critic/go-critic v0.0.0-20181204210945-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540 h1:djv/qAomOVj8voCHt0M0OYwR/4vfDq1zNKSPKjJCexs= +github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -49,26 +49,26 @@ github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5 github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6 h1:i2jIkQFb8RG45DuQs+ElyROY848cSJIoIkBM+7XXypA= -github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196 h1:9rtVlONXLF1rJZzvLt4tfOXtnAFUEhxCJ64Ibzj6ECo= -github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= +github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c h1:/7detzz5stiXWPzkTlPTzkBEIIE4WGpppBJYjKqBiPI= +github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8= github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8= github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= -github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98 h1:ir6/L2ZOJfFrJlOTsuf/hlzdPuUwXV/VzkSlgS6f1vs= -github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.17.1 h1:lc8Hf9GPCjIr0hg3S/xhvFT1+Hydass8F1xchr8jkME= -github.com/golangci/golangci-lint v1.17.1/go.mod h1:+5sJSl2h3aly+fpmL2meSP8CaSKua2E4Twi9LPy7b1g= -github.com/golangci/gosec v0.0.0-20180901114220-66fb7fc33547 h1:qMomh8bv+kDazm1dSLZ9S3zZ2PJZMHL4ilfBjxFOlmI= -github.com/golangci/gosec v0.0.0-20180901114220-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= -github.com/golangci/ineffassign v0.0.0-20180808204949-42439a7714cc h1:XRFao922N8F3EcIXBSNX8Iywk+GI0dxD/8FicMX2D/c= -github.com/golangci/ineffassign v0.0.0-20180808204949-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= -github.com/golangci/lint-1 v0.0.0-20180610141402-ee948d087217 h1:r7vyX+SN24x6+5AnpnrRn/bdwBb7U+McZqCHOVtXDuk= -github.com/golangci/lint-1 v0.0.0-20180610141402-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98 h1:0OkFarm1Zy2CjCiDKfK9XHgmc2wbDlRMD2hD8anAJHU= +github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.18.0 h1:XmQgfcLofSG/6AsQuQqmLizB+3GggD+o6ObBG9L+VMM= +github.com/golangci/golangci-lint v1.18.0/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg= +github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547 h1:fUdgm/BdKvwOHxg5AhNbkNRp2mSy8sxTXyBVs/laQHo= +github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217 h1:En/tZdwhAn0JNwLuXzP3k2RVtMqMmOEK7Yu/g3tmtJE= +github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk= @@ -131,8 +131,8 @@ github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.1.0 h1:cmiOvKzEunMsAxyhXSzpL5Q1CRKpVv0KQsnAIcSEVYM= github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= @@ -166,8 +166,10 @@ github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7Sr github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb h1:lI9ufgFfvuqRctP9Ny8lDDLbSWCMxBPletcSqrnyFYM= -github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec h1:AmoEvWAO3nDx1MEcMzPh+GzOOIA5Znpv6++c7bePPY0= +github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/ultraware/funlen v0.0.1 h1:UeC9tpM4wNWzUJfan8z9sFE4QCzjjzlCZmuJN+aOkH0= +github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= @@ -180,13 +182,12 @@ golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -203,8 +204,10 @@ golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd h1:7E3PabyysDSEjnaANKBgums/hyvMI/HoHQ50qZEzTrg= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190909030654-5b82db07426d h1:PhtdWYteEBebOX7KXm4qkIAVSUTHQ883/2hRB92r9lk= +golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= @@ -222,7 +225,7 @@ mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wp mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20190124213536-fbb59629db34 h1:B1LAOfRqg2QUyCdzfjf46quTSYUTAK5OCwbh6pljHbM= -mvdan.cc/unparam v0.0.0-20190124213536-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= +mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 h1:duVSyluuJA+u0BnkcLR01smoLrGgDTfWt5c8ODYG8fU= +mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md index 6f742511241..3f7f2a4bbbb 100644 --- a/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md +++ b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md @@ -28,6 +28,9 @@ The following is an example configuration file. "packages": [ "github.com/OpenPeeDeeP/depguard" ], + "inTests": [ + "github.com/stretchr/testify" + ], "includeGoRoot": true } ``` @@ -35,6 +38,7 @@ The following is an example configuration file. - `type` can be either `whitelist` or `blacklist`. This check is case insensitive. If not specified the default is `blacklist`. - `packages` is a list of packages for the list type specified. +- `inTests` is a list of packages allowed/disallowed only in test files. - Set `includeGoRoot` to true if you want to check the list against standard lib. If not specified the default is false. diff --git a/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go index 433cf8ff2fb..b547c0b618a 100644 --- a/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go +++ b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go @@ -1,7 +1,6 @@ package depguard import ( - "go/build" "go/token" "os" "sort" @@ -11,44 +10,50 @@ import ( "golang.org/x/tools/go/loader" ) -//ListType states what kind of list is passed in. +// ListType states what kind of list is passed in. type ListType int const ( - //LTBlacklist states the list given is a blacklist. (default) + // LTBlacklist states the list given is a blacklist. (default) LTBlacklist ListType = iota - //LTWhitelist states the list given is a whitelist. + // LTWhitelist states the list given is a whitelist. LTWhitelist ) -//StringToListType makes it easier to turn a string into a ListType. -//It assumes that the string representation is lower case. +// StringToListType makes it easier to turn a string into a ListType. +// It assumes that the string representation is lower case. var StringToListType = map[string]ListType{ "whitelist": LTWhitelist, "blacklist": LTBlacklist, } -//Issue with the package with PackageName at the Position. +// Issue with the package with PackageName at the Position. type Issue struct { PackageName string Position token.Position } -//Depguard checks imports to make sure they follow the given list and constraints. +// Depguard checks imports to make sure they follow the given list and constraints. type Depguard struct { - ListType ListType + ListType ListType + IncludeGoRoot bool + Packages []string - IncludeGoRoot bool prefixPackages []string globPackages []glob.Glob - buildCtx *build.Context - cwd string + + TestPackages []string + prefixTestPackages []string + globTestPackages []glob.Glob + + rootChecker *RootChecker + cwd string } -//Run checks for dependencies given the program and validates them against -//Packages. +// Run checks for dependencies given the program and validates them against +// Packages. func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, error) { - //Shortcut execution on an empty blacklist as that means every package is allowed + // Shortcut execution on an empty blacklist as that means every package is allowed if dg.ListType == LTBlacklist && len(dg.Packages) == 0 { return nil, nil } @@ -56,15 +61,20 @@ func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, if err := dg.initialize(config, prog); err != nil { return nil, err } - directImports, err := dg.createImportMap(prog) if err != nil { return nil, err } var issues []*Issue for pkg, positions := range directImports { - if dg.flagIt(pkg) { - for _, pos := range positions { + for _, pos := range positions { + + prefixList, globList := dg.prefixPackages, dg.globPackages + if len(dg.TestPackages) > 0 && strings.Index(pos.Filename, "_test.go") != -1 { + prefixList, globList = dg.prefixTestPackages, dg.globTestPackages + } + + if dg.flagIt(pkg, prefixList, globList) { issues = append(issues, &Issue{ PackageName: pkg, Position: pos, @@ -76,7 +86,7 @@ func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, } func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) error { - //Try and get the current working directory + // Try and get the current working directory dg.cwd = config.Cwd if dg.cwd == "" { var err error @@ -86,12 +96,9 @@ func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) erro } } - //Use the &build.Default if one is not specified - dg.buildCtx = config.Build - if dg.buildCtx == nil { - dg.buildCtx = &build.Default - } + dg.rootChecker = NewRootChecker(config.Build) + // parse ordinary guarded packages for _, pkg := range dg.Packages { if strings.ContainsAny(pkg, "!?*[]{}") { g, err := glob.Compile(pkg, '/') @@ -104,27 +111,44 @@ func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) erro } } - //Sort the packages so we can have a faster search in the array + // Sort the packages so we can have a faster search in the array sort.Strings(dg.prefixPackages) + + // parse guarded tests packages + for _, pkg := range dg.TestPackages { + if strings.ContainsAny(pkg, "!?*[]{}") { + g, err := glob.Compile(pkg, '/') + if err != nil { + return err + } + dg.globTestPackages = append(dg.globTestPackages, g) + } else { + dg.prefixTestPackages = append(dg.prefixTestPackages, pkg) + } + } + + // Sort the test packages so we can have a faster search in the array + sort.Strings(dg.prefixTestPackages) + return nil } func (dg *Depguard) createImportMap(prog *loader.Program) (map[string][]token.Position, error) { importMap := make(map[string][]token.Position) - //For the directly imported packages + // For the directly imported packages for _, imported := range prog.InitialPackages() { - //Go through their files + // Go through their files for _, file := range imported.Files { - //And populate a map of all direct imports and their positions - //This will filter out GoRoot depending on the Depguard.IncludeGoRoot + // And populate a map of all direct imports and their positions + // This will filter out GoRoot depending on the Depguard.IncludeGoRoot for _, fileImport := range file.Imports { fileImportPath := cleanBasicLitString(fileImport.Path.Value) if !dg.IncludeGoRoot { - pkg, err := dg.buildCtx.Import(fileImportPath, dg.cwd, 0) + isRoot, err := dg.rootChecker.IsRoot(fileImportPath, dg.cwd) if err != nil { return nil, err } - if pkg.Goroot { + if isRoot { continue } } @@ -143,29 +167,29 @@ func (dg *Depguard) createImportMap(prog *loader.Program) (map[string][]token.Po return importMap, nil } -func (dg *Depguard) pkgInList(pkg string) bool { - if dg.pkgInPrefixList(pkg) { +func (dg *Depguard) pkgInList(pkg string, prefixList []string, globList []glob.Glob) bool { + if dg.pkgInPrefixList(pkg, prefixList) { return true } - return dg.pkgInGlobList(pkg) + return dg.pkgInGlobList(pkg, globList) } -func (dg *Depguard) pkgInPrefixList(pkg string) bool { - //Idx represents where in the package slice the passed in package would go - //when sorted. -1 Just means that it would be at the very front of the slice. - idx := sort.Search(len(dg.prefixPackages), func(i int) bool { - return dg.prefixPackages[i] > pkg +func (dg *Depguard) pkgInPrefixList(pkg string, prefixList []string) bool { + // Idx represents where in the package slice the passed in package would go + // when sorted. -1 Just means that it would be at the very front of the slice. + idx := sort.Search(len(prefixList), func(i int) bool { + return prefixList[i] > pkg }) - 1 - //This means that the package passed in has no way to be prefixed by anything - //in the package list as it is already smaller then everything + // This means that the package passed in has no way to be prefixed by anything + // in the package list as it is already smaller then everything if idx == -1 { return false } - return strings.HasPrefix(pkg, dg.prefixPackages[idx]) + return strings.HasPrefix(pkg, prefixList[idx]) } -func (dg *Depguard) pkgInGlobList(pkg string) bool { - for _, g := range dg.globPackages { +func (dg *Depguard) pkgInGlobList(pkg string, globList []glob.Glob) bool { + for _, g := range globList { if g.Match(pkg) { return true } @@ -173,11 +197,11 @@ func (dg *Depguard) pkgInGlobList(pkg string) bool { return false } -//InList | WhiteList | BlackList +// InList | WhiteList | BlackList // y | | x // n | x | -func (dg *Depguard) flagIt(pkg string) bool { - return dg.pkgInList(pkg) == (dg.ListType == LTBlacklist) +func (dg *Depguard) flagIt(pkg string, prefixList []string, globList []glob.Glob) bool { + return dg.pkgInList(pkg, prefixList, globList) == (dg.ListType == LTBlacklist) } func cleanBasicLitString(value string) string { diff --git a/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go new file mode 100644 index 00000000000..7dae0efd1d9 --- /dev/null +++ b/tests/tools/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go @@ -0,0 +1,52 @@ +package depguard + +import ( + "go/build" +) + +// RootChecker checks if import paths point to root packages. +type RootChecker struct { + buildCtx *build.Context + cache map[string]bool +} + +// NewRootChecker creates a new RootChecker instance using the build.Context +// given, or build.Default. +func NewRootChecker(buildCtx *build.Context) *RootChecker { + // Use the &build.Default if build.Context is not specified + ctx := buildCtx + if ctx == nil { + ctx = &build.Default + } + return &RootChecker{ + buildCtx: ctx, + cache: make(map[string]bool, 0), + } +} + +// IsRoot checks if the given import path (imported from sourceDir) +// points to a a root package. Subsequent calls with the same arguments +// are cached. This is not thread-safe. +func (rc *RootChecker) IsRoot(path, sourceDir string) (bool, error) { + key := path + ":::" + sourceDir + isRoot, ok := rc.cache[key] + if ok { + return isRoot, nil + } + isRoot, err := rc.calcIsRoot(path, sourceDir) + if err != nil { + return false, err + } + rc.cache[key] = isRoot + return isRoot, nil +} + +// calcIsRoot performs the call to the build context to check if +// the import path points to a root package. +func (rc *RootChecker) calcIsRoot(path, sourceDir string) (bool, error) { + pkg, err := rc.buildCtx.Import(path, sourceDir, build.FindOnly) + if err != nil { + return false, err + } + return pkg.Goroot, nil +} diff --git a/tests/tools/vendor/github.com/golangci/go-tools/lint/lint.go b/tests/tools/vendor/github.com/golangci/go-tools/lint/lint.go index a5a9feef024..e9aa7933fdb 100644 --- a/tests/tools/vendor/github.com/golangci/go-tools/lint/lint.go +++ b/tests/tools/vendor/github.com/golangci/go-tools/lint/lint.go @@ -9,17 +9,16 @@ import ( "io" "os" "path/filepath" - "runtime/debug" "sort" "strings" "sync" "time" "unicode" + "golang.org/x/tools/go/packages" "github.com/golangci/go-tools/config" "github.com/golangci/go-tools/ssa" "github.com/golangci/go-tools/ssa/ssautil" - "golang.org/x/tools/go/packages" ) type Job struct { @@ -30,7 +29,6 @@ type Job struct { problems []Problem duration time.Duration - panicErr error } type Ignore interface { @@ -453,11 +451,6 @@ func (l *Linter) Lint(initial []*packages.Package, stats *PerfStats) []Problem { for _, j := range jobs { wg.Add(1) go func(j *Job) { - defer func() { - if panicErr := recover(); panicErr != nil { - j.panicErr = fmt.Errorf("panic: %s: %s", panicErr, string(debug.Stack())) - } - }() defer wg.Done() sem <- struct{}{} defer func() { <-sem }() @@ -473,10 +466,6 @@ func (l *Linter) Lint(initial []*packages.Package, stats *PerfStats) []Problem { wg.Wait() for _, j := range jobs { - if j.panicErr != nil { - panic(j.panicErr) - } - if stats != nil { stats.Jobs = append(stats.Jobs, JobStat{j.check.ID, j.duration}) } diff --git a/tests/tools/vendor/github.com/golangci/go-tools/stylecheck/lint.go b/tests/tools/vendor/github.com/golangci/go-tools/stylecheck/lint.go index c0601861a71..620cacf3e5d 100644 --- a/tests/tools/vendor/github.com/golangci/go-tools/stylecheck/lint.go +++ b/tests/tools/vendor/github.com/golangci/go-tools/stylecheck/lint.go @@ -252,9 +252,6 @@ func (c *Checker) CheckUnexportedReturn(j *lint.Job) { func (c *Checker) CheckReceiverNames(j *lint.Job) { for _, pkg := range j.Program.InitialPackages { - if pkg.SSA == nil { - continue - } for _, m := range pkg.SSA.Members { if T, ok := m.Object().(*types.TypeName); ok && !T.IsAlias() { ms := typeutil.IntuitiveMethodSet(T.Type(), nil) @@ -279,10 +276,6 @@ func (c *Checker) CheckReceiverNames(j *lint.Job) { func (c *Checker) CheckReceiverNamesIdentical(j *lint.Job) { for _, pkg := range j.Program.InitialPackages { - if pkg.SSA == nil { - continue - } - for _, m := range pkg.SSA.Members { names := map[string]int{} diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/completion.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/completion.go new file mode 100644 index 00000000000..1ff4b44f746 --- /dev/null +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/completion.go @@ -0,0 +1,32 @@ +package commands + +import ( + "os" + + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +func (e *Executor) initCompletion() { + completionCmd := &cobra.Command{ + Use: "completion", + Short: "Output completion script", + } + e.rootCmd.AddCommand(completionCmd) + + bashCmd := &cobra.Command{ + Use: "bash", + Short: "Output bash completion script", + RunE: e.executeCompletion, + } + completionCmd.AddCommand(bashCmd) +} + +func (e *Executor) executeCompletion(cmd *cobra.Command, args []string) error { + err := cmd.Root().GenBashCompletion(os.Stdout) + if err != nil { + return errors.Wrap(err, "unable to generate bash completions: %v") + } + + return nil +} diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go index 1f6231e956e..718456919af 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go @@ -72,6 +72,7 @@ func NewExecutor(version, commit, date string) *Executor { e.initHelp() e.initLinters() e.initConfig() + e.initCompletion() // init e.cfg by values from config: flags parse will see these values // like the default ones. It will overwrite them only if the same option diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go index 597d26d6523..565169eb32e 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/golangci/golangci-lint/pkg/packages" "github.com/golangci/golangci-lint/pkg/result/processors" "github.com/fatih/color" @@ -26,7 +27,7 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) -func getDefaultExcludeHelp() string { +func getDefaultIssueExcludeHelp() string { parts := []string{"Use or not use default excludes:"} for _, ep := range config.DefaultExcludePatterns { parts = append(parts, @@ -38,6 +39,15 @@ func getDefaultExcludeHelp() string { return strings.Join(parts, "\n") } +func getDefaultDirectoryExcludeHelp() string { + parts := []string{"Use or not use default excluded directories:"} + for _, dir := range packages.StdExcludeDirRegexps { + parts = append(parts, fmt.Sprintf(" - %s", color.YellowString(dir))) + } + parts = append(parts, "") + return strings.Join(parts, "\n") +} + const welcomeMessage = "Run this tool in cloud on every github pull " + "request in https://golangci.com for free (public repos)" @@ -45,6 +55,7 @@ func wh(text string) string { return color.GreenString(text) } +//nolint:funlen func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, isFinalInit bool) { hideFlag := func(name string) { if err := fs.MarkHidden(name); err != nil { @@ -82,6 +93,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is fs.StringVarP(&rc.Config, "config", "c", "", wh("Read config from file path `PATH`")) fs.BoolVar(&rc.NoConfig, "no-config", false, wh("Don't read config")) fs.StringSliceVar(&rc.SkipDirs, "skip-dirs", nil, wh("Regexps of directories to skip")) + fs.BoolVar(&rc.UseDefaultSkipDirs, "skip-dirs-use-default", true, getDefaultDirectoryExcludeHelp()) fs.StringSliceVar(&rc.SkipFiles, "skip-files", nil, wh("Regexps of files to skip")) // Linters settings config @@ -161,7 +173,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is // Issues config ic := &cfg.Issues fs.StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", nil, wh("Exclude issue by regexp")) - fs.BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultExcludeHelp()) + fs.BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultIssueExcludeHelp()) fs.IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50, wh("Maximum issues count per one linter. Set to 0 to disable")) diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/config/config.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/config/config.go index 9a113fe6d89..775e14b21b2 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/config/config.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/config/config.go @@ -118,8 +118,9 @@ type Run struct { Deadline time.Duration PrintVersion bool - SkipFiles []string `mapstructure:"skip-files"` - SkipDirs []string `mapstructure:"skip-dirs"` + SkipFiles []string `mapstructure:"skip-files"` + SkipDirs []string `mapstructure:"skip-dirs"` + UseDefaultSkipDirs bool `mapstructure:"skip-dirs-use-default"` } type LintersSettings struct { @@ -153,9 +154,10 @@ type LintersSettings struct { MinOccurrencesCount int `mapstructure:"min-occurrences"` } Depguard struct { - ListType string `mapstructure:"list-type"` - Packages []string - IncludeGoRoot bool `mapstructure:"include-go-root"` + ListType string `mapstructure:"list-type"` + Packages []string + IncludeGoRoot bool `mapstructure:"include-go-root"` + PackagesWithErrorMessage map[string]string `mapstructure:"packages-with-error-message"` } Misspell struct { Locale string @@ -164,6 +166,10 @@ type LintersSettings struct { Unused struct { CheckExported bool `mapstructure:"check-exported"` } + Funlen struct { + Lines int + Statements int + } Lll LllSettings Unparam UnparamSettings diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go index 6c97bddacfe..8e4d8c32618 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go @@ -3,6 +3,7 @@ package fsutils import ( "fmt" "io/ioutil" + "sync" "github.com/golangci/golangci-lint/pkg/logutils" @@ -10,19 +11,17 @@ import ( ) type FileCache struct { - files map[string][]byte + files sync.Map } func NewFileCache() *FileCache { - return &FileCache{ - files: map[string][]byte{}, - } + return &FileCache{} } func (fc *FileCache) GetFileBytes(filePath string) ([]byte, error) { - cachedBytes := fc.files[filePath] - if cachedBytes != nil { - return cachedBytes, nil + cachedBytes, ok := fc.files.Load(filePath) + if ok { + return cachedBytes.([]byte), nil } fileBytes, err := ioutil.ReadFile(filePath) @@ -30,7 +29,7 @@ func (fc *FileCache) GetFileBytes(filePath string) ([]byte, error) { return nil, errors.Wrapf(err, "can't read file %s", filePath) } - fc.files[filePath] = fileBytes + fc.files.Store(filePath, fileBytes) return fileBytes, nil } @@ -56,9 +55,13 @@ func prettifyBytesCount(n int) string { func (fc *FileCache) PrintStats(log logutils.Log) { var size int - for _, fileBytes := range fc.files { - size += len(fileBytes) - } + var mapLen int + fc.files.Range(func(_, fileBytes interface{}) bool { + mapLen++ + size += len(fileBytes.([]byte)) + + return true + }) - log.Infof("File cache stats: %d entries of total size %s", len(fc.files), prettifyBytesCount(size)) + log.Infof("File cache stats: %d entries of total size %s", mapLen, prettifyBytesCount(size)) } diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go index a651a504964..10f31422a91 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go @@ -3,6 +3,7 @@ package fsutils import ( "bytes" "fmt" + "sync" "github.com/pkg/errors" ) @@ -10,13 +11,12 @@ import ( type fileLinesCache [][]byte type LineCache struct { - files map[string]fileLinesCache + files sync.Map fileCache *FileCache } func NewLineCache(fc *FileCache) *LineCache { return &LineCache{ - files: map[string]fileLinesCache{}, fileCache: fc, } } @@ -53,9 +53,9 @@ func (lc *LineCache) getRawLine(filePath string, index0 int) ([]byte, error) { } func (lc *LineCache) getFileCache(filePath string) (fileLinesCache, error) { - fc := lc.files[filePath] - if fc != nil { - return fc, nil + loadedFc, ok := lc.files.Load(filePath) + if ok { + return loadedFc.(fileLinesCache), nil } fileBytes, err := lc.fileCache.GetFileBytes(filePath) @@ -63,7 +63,7 @@ func (lc *LineCache) getFileCache(filePath string) (fileLinesCache, error) { return nil, errors.Wrapf(err, "can't get file %s bytes from cache", filePath) } - fc = bytes.Split(fileBytes, []byte("\n")) - lc.files[filePath] = fc + fc := bytes.Split(fileBytes, []byte("\n")) + lc.files.Store(filePath, fileLinesCache(fc)) return fc, nil } diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go index a00af5c9f1a..9fb59dfa31d 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go @@ -17,6 +17,38 @@ func (Depguard) Name() string { return "depguard" } +func setDepguardListType(dg *depguardAPI.Depguard, lintCtx *linter.Context) error { + listType := lintCtx.Settings().Depguard.ListType + var found bool + dg.ListType, found = depguardAPI.StringToListType[strings.ToLower(listType)] + if !found { + if listType != "" { + return fmt.Errorf("unsure what list type %s is", listType) + } + dg.ListType = depguardAPI.LTBlacklist + } + + return nil +} + +func setupDepguardPackages(dg *depguardAPI.Depguard, lintCtx *linter.Context) { + if dg.ListType == depguardAPI.LTBlacklist { + // if the list type was a blacklist the packages with error messages should + // be included in the blacklist package list + + noMessagePackages := make(map[string]bool) + for _, pkg := range dg.Packages { + noMessagePackages[pkg] = true + } + + for pkg := range lintCtx.Settings().Depguard.PackagesWithErrorMessage { + if _, ok := noMessagePackages[pkg]; !ok { + dg.Packages = append(dg.Packages, pkg) + } + } + } +} + func (Depguard) Desc() string { return "Go linter that checks if package imports are in a list of acceptable packages" } @@ -26,15 +58,10 @@ func (d Depguard) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Is Packages: lintCtx.Settings().Depguard.Packages, IncludeGoRoot: lintCtx.Settings().Depguard.IncludeGoRoot, } - listType := lintCtx.Settings().Depguard.ListType - var found bool - dg.ListType, found = depguardAPI.StringToListType[strings.ToLower(listType)] - if !found { - if listType != "" { - return nil, fmt.Errorf("unsure what list type %s is", listType) - } - dg.ListType = depguardAPI.LTBlacklist + if err := setDepguardListType(dg, lintCtx); err != nil { + return nil, err } + setupDepguardPackages(dg, lintCtx) issues, err := dg.Run(lintCtx.LoaderConfig, lintCtx.Program) if err != nil { @@ -49,9 +76,13 @@ func (d Depguard) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Is } res := make([]result.Issue, 0, len(issues)) for _, i := range issues { + userSuppliedMsgSuffix := lintCtx.Settings().Depguard.PackagesWithErrorMessage[i.PackageName] + if userSuppliedMsgSuffix != "" { + userSuppliedMsgSuffix = ": " + userSuppliedMsgSuffix + } res = append(res, result.Issue{ Pos: i.Position, - Text: fmt.Sprintf("%s %s", formatCode(i.PackageName, lintCtx.Cfg), msgSuffix), + Text: fmt.Sprintf("%s %s%s", formatCode(i.PackageName, lintCtx.Cfg), msgSuffix, userSuppliedMsgSuffix), FromLinter: d.Name(), }) } diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen.go new file mode 100644 index 00000000000..c5768ec36b7 --- /dev/null +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen.go @@ -0,0 +1,47 @@ +package golinters + +import ( + "context" + "go/token" + "strings" + + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/result" + + "github.com/ultraware/funlen" +) + +type Funlen struct{} + +func (Funlen) Name() string { + return "funlen" +} + +func (Funlen) Desc() string { + return "Tool for detection of long functions" +} + +func (f Funlen) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { + var issues []funlen.Message + for _, file := range lintCtx.ASTCache.GetAllValidFiles() { + issues = append(issues, funlen.Run(file.F, file.Fset, lintCtx.Settings().Funlen.Lines, lintCtx.Settings().Funlen.Statements)...) + } + + if len(issues) == 0 { + return nil, nil + } + + res := make([]result.Issue, len(issues)) + for k, i := range issues { + res[k] = result.Issue{ + Pos: token.Position{ + Filename: i.Pos.Filename, + Line: i.Pos.Line, + }, + Text: strings.TrimRight(i.Message, "\n"), + FromLinter: f.Name(), + } + } + + return res, nil +} diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go index afff750e75b..fc36c2961c3 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go @@ -124,13 +124,13 @@ func (lnt Linter) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Is } var issues []result.Issue - for _, diag := range diags { - i := result.Issue{ + for i := range diags { + diag := &diags[i] + issues = append(issues, result.Issue{ FromLinter: lnt.Name(), Text: fmt.Sprintf("%s: %s", diag.AnalyzerName, diag.Message), Pos: diag.Position, - } - issues = append(issues, i) + }) } return issues, nil diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go index d2b66501b71..c1a67ad7c64 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go @@ -61,7 +61,7 @@ func (lint Gochecknoglobals) checkFile(f *ast.File, fset *token.FileSet) []resul } func isWhitelisted(i *ast.Ident) bool { - return i.Name == "_" || looksLikeError(i) + return i.Name == "_" || i.Name == "version" || looksLikeError(i) } // looksLikeError returns true if the AST identifier starts diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/megacheck.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/megacheck.go index 14c66720e78..d4bf8604181 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/megacheck.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/megacheck.go @@ -177,7 +177,9 @@ func (m MegacheckMetalinter) isValidChild(name string) bool { } func (m megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { - issues, err := m.runMegacheck(lintCtx.Packages, lintCtx.Settings().Unused.CheckExported) + // Use OriginalPackages not Packages because `unused` doesn't work properly + // when we deduplicate normal and test packages. + issues, err := m.runMegacheck(lintCtx.OriginalPackages, lintCtx.Settings().Unused.CheckExported) if err != nil { return nil, errors.Wrap(err, "failed to run megacheck") } @@ -231,16 +233,17 @@ func (m megacheck) runMegacheck(workingPkgs []*packages.Package, checkExportedUn opts := &lintutil.Options{ // TODO: get current go version, but now it doesn't matter, // may be needed after next updates of megacheck - GoVersion: 11, + GoVersion: 12, Config: cfg, // TODO: support Ignores option } - return runMegacheckCheckers(checkers, opts, workingPkgs) + return runMegacheckCheckers(checkers, workingPkgs, opts) } -// parseIgnore is a copy from megacheck code just to not fork megacheck +// parseIgnore is a copy from megacheck honnef.co/go/tools/lint/lintutil.parseIgnore +// just to not fork megacheck. func parseIgnore(s string) ([]lint.Ignore, error) { var out []lint.Ignore if s == "" { @@ -258,17 +261,28 @@ func parseIgnore(s string) ([]lint.Ignore, error) { return out, nil } -func runMegacheckCheckers(cs []lint.Checker, opt *lintutil.Options, workingPkgs []*packages.Package) ([]lint.Problem, error) { +// runMegacheckCheckers is like megacheck honnef.co/go/tools/lint/lintutil.Lint, +// but takes a list of already-parsed packages instead of a list of +// package-paths to parse. +func runMegacheckCheckers(cs []lint.Checker, workingPkgs []*packages.Package, opt *lintutil.Options) ([]lint.Problem, error) { stats := lint.PerfStats{ CheckerInits: map[string]time.Duration{}, } + if opt == nil { + opt = &lintutil.Options{} + } ignores, err := parseIgnore(opt.Ignores) if err != nil { return nil, err } + // package-parsing elided here + stats.PackageLoading = 0 + var problems []lint.Problem + // populating 'problems' with parser-problems elided here + if len(workingPkgs) == 0 { return problems, nil } diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go index d7afceac953..413c20f8485 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go @@ -82,15 +82,12 @@ func (lint Misspell) runOnFile(fileName string, r *misspell.Replacer, lintCtx *l Line: diff.Line, Column: diff.Column + 1, } - var replacement *result.Replacement - if lintCtx.Cfg.Issues.NeedFix { - replacement = &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: diff.Column, - Length: len(diff.Original), - NewString: diff.Corrected, - }, - } + replacement := &result.Replacement{ + Inline: &result.InlineFix{ + StartCol: diff.Column, + Length: len(diff.Original), + NewString: diff.Corrected, + }, } res = append(res, result.Issue{ diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go index 9c3d50401b4..aaf805821d7 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go @@ -13,7 +13,13 @@ import ( ) type Context struct { - Packages []*packages.Package + // Packages are deduplicated (test and normal packages) packages + Packages []*packages.Package + + // OriginalPackages aren't deduplicated: they contain both normal and test + // version for each of packages + OriginalPackages []*packages.Package + NotCompilingPackages []*packages.Package LoaderConfig *loader.Config // deprecated, don't use for new linters diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go index dd5c57ca6d9..0b5effdc749 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go @@ -77,6 +77,7 @@ func (Manager) GetMetaLinters() map[string]linter.MetaLinter { return ret } +//nolint:funlen func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { var govetCfg *config.GovetSettings if m.cfg != nil { @@ -237,6 +238,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithSpeed(10). WithURL("https://github.com/leighmcculloch/gochecknoglobals"), + linter.NewConfig(golinters.Funlen{}). + WithPresets(linter.PresetStyle). + WithSpeed(10). + WithURL("https://github.com/ultraware/funlen"), } isLocalRun := os.Getenv("GOLANGCI_COM_RUN") == "" diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go index 63e2076ff41..9a8d0ccb391 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go @@ -88,11 +88,6 @@ func (cl ContextLoader) makeFakeLoaderPackageInfo(pkg *packages.Package) *loader } } -func shouldSkipPkg(pkg *packages.Package) bool { - // it's an implicit testmain package - return pkg.Name == "main" && strings.HasSuffix(pkg.PkgPath, ".test") -} - func (cl ContextLoader) makeFakeLoaderProgram(pkgs []*packages.Package) *loader.Program { var createdPkgs []*loader.PackageInfo for _, pkg := range pkgs { @@ -148,39 +143,19 @@ func (cl ContextLoader) buildSSAProgram(pkgs []*packages.Package) *ssa.Program { } func (cl ContextLoader) findLoadMode(linters []*linter.Config) packages.LoadMode { - maxLoadMode := packages.LoadFiles + //TODO: specify them in linters: need more fine-grained control. + // e.g. NeedTypesSizes is needed only for go vet + loadMode := packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles for _, lc := range linters { - curLoadMode := packages.LoadFiles if lc.NeedsTypeInfo { - curLoadMode = packages.LoadSyntax + loadMode |= packages.NeedImports | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedTypesInfo | packages.NeedSyntax } if lc.NeedsSSARepr { - curLoadMode = packages.LoadAllSyntax - } - if curLoadMode > maxLoadMode { - maxLoadMode = curLoadMode + loadMode |= packages.NeedDeps } } - return maxLoadMode -} - -func stringifyLoadMode(mode packages.LoadMode) string { - switch mode { - case packages.LoadFiles: - return "load files" - case packages.LoadImports: - return "load imports" - case packages.LoadTypes: - return "load types" - case packages.LoadSyntax: - return "load types and syntax" - } - // it may be an alias, and may be not - if mode == packages.LoadAllSyntax { - return "load deps types and syntax" - } - return "unknown" + return loadMode } func (cl ContextLoader) buildArgs() []string { @@ -231,6 +206,58 @@ func (cl ContextLoader) makeBuildFlags() ([]string, error) { return buildFlags, nil } +func stringifyLoadMode(mode packages.LoadMode) string { + m := map[packages.LoadMode]string{ + packages.NeedCompiledGoFiles: "compiled_files", + packages.NeedDeps: "deps", + packages.NeedExportsFile: "exports_file", + packages.NeedFiles: "files", + packages.NeedImports: "imports", + packages.NeedName: "name", + packages.NeedSyntax: "syntax", + packages.NeedTypes: "types", + packages.NeedTypesInfo: "types_info", + packages.NeedTypesSizes: "types_sizes", + } + + var flags []string + for flag, flagStr := range m { + if mode&flag != 0 { + flags = append(flags, flagStr) + } + } + + return fmt.Sprintf("%d (%s)", mode, strings.Join(flags, "|")) +} + +func (cl ContextLoader) debugPrintLoadedPackages(pkgs []*packages.Package) { + cl.debugf("loaded %d pkgs", len(pkgs)) + for i, pkg := range pkgs { + var syntaxFiles []string + for _, sf := range pkg.Syntax { + syntaxFiles = append(syntaxFiles, pkg.Fset.Position(sf.Pos()).Filename) + } + cl.debugf("Loaded pkg #%d: ID=%s GoFiles=%s CompiledGoFiles=%s Syntax=%s", + i, pkg.ID, pkg.GoFiles, pkg.CompiledGoFiles, syntaxFiles) + } +} + +func (cl ContextLoader) parseLoadedPackagesErrors(pkgs []*packages.Package) error { + for _, pkg := range pkgs { + for _, err := range pkg.Errors { + if strings.Contains(err.Msg, "no Go files") { + return errors.Wrapf(exitcodes.ErrNoGoFiles, "package %s", pkg.PkgPath) + } + if strings.Contains(err.Msg, "cannot find package") { + // when analyzing not existing directory + return errors.Wrap(exitcodes.ErrFailure, err.Msg) + } + } + } + + return nil +} + func (cl ContextLoader) loadPackages(ctx context.Context, loadMode packages.LoadMode) ([]*packages.Package, error) { defer func(startedAt time.Time) { cl.log.Infof("Go packages loading at mode %s took %s", stringifyLoadMode(loadMode), time.Since(startedAt)) @@ -248,6 +275,7 @@ func (cl ContextLoader) loadPackages(ctx context.Context, loadMode packages.Load Tests: cl.cfg.Run.AnalyzeTests, Context: ctx, BuildFlags: buildFlags, + Logf: cl.debugf, //TODO: use fset, parsefile, overlay } @@ -257,29 +285,13 @@ func (cl ContextLoader) loadPackages(ctx context.Context, loadMode packages.Load if err != nil { return nil, errors.Wrap(err, "failed to load program with go/packages") } - cl.debugf("loaded %d pkgs", len(pkgs)) - for i, pkg := range pkgs { - var syntaxFiles []string - for _, sf := range pkg.Syntax { - syntaxFiles = append(syntaxFiles, pkg.Fset.Position(sf.Pos()).Filename) - } - cl.debugf("Loaded pkg #%d: ID=%s GoFiles=%s CompiledGoFiles=%s Syntax=%s", - i, pkg.ID, pkg.GoFiles, pkg.CompiledGoFiles, syntaxFiles) - } + cl.debugPrintLoadedPackages(pkgs) - for _, pkg := range pkgs { - for _, err := range pkg.Errors { - if strings.Contains(err.Msg, "no Go files") { - return nil, errors.Wrapf(exitcodes.ErrNoGoFiles, "package %s", pkg.PkgPath) - } - if strings.Contains(err.Msg, "cannot find package") { - // when analyzing not existing directory - return nil, errors.Wrap(exitcodes.ErrFailure, err.Msg) - } - } + if err := cl.parseLoadedPackagesErrors(pkgs); err != nil { + return nil, err } - return cl.filterPackages(pkgs), nil + return cl.filterTestMainPackages(pkgs), nil } func (cl ContextLoader) tryParseTestPackage(pkg *packages.Package) (name, testName string, isTest bool) { @@ -291,7 +303,22 @@ func (cl ContextLoader) tryParseTestPackage(pkg *packages.Package) (name, testNa return matches[1], matches[2], true } -func (cl ContextLoader) filterPackages(pkgs []*packages.Package) []*packages.Package { +func (cl ContextLoader) filterTestMainPackages(pkgs []*packages.Package) []*packages.Package { + var retPkgs []*packages.Package + for _, pkg := range pkgs { + if pkg.Name == "main" && strings.HasSuffix(pkg.PkgPath, ".test") { + // it's an implicit testmain package + cl.debugf("skip pkg ID=%s", pkg.ID) + continue + } + + retPkgs = append(retPkgs, pkg) + } + + return retPkgs +} + +func (cl ContextLoader) filterDuplicatePackages(pkgs []*packages.Package) []*packages.Package { packagesWithTests := map[string]bool{} for _, pkg := range pkgs { name, _, isTest := cl.tryParseTestPackage(pkg) @@ -305,11 +332,6 @@ func (cl ContextLoader) filterPackages(pkgs []*packages.Package) []*packages.Pac var retPkgs []*packages.Package for _, pkg := range pkgs { - if shouldSkipPkg(pkg) { - cl.debugf("skip pkg ID=%s", pkg.ID) - continue - } - _, _, isTest := cl.tryParseTestPackage(pkg) if !isTest && packagesWithTests[pkg.PkgPath] { // If tests loading is enabled, @@ -336,28 +358,35 @@ func (cl ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*li return nil, err } - if len(pkgs) == 0 { + deduplicatedPkgs := cl.filterDuplicatePackages(pkgs) + + if len(deduplicatedPkgs) == 0 { return nil, exitcodes.ErrNoGoFiles } var prog *loader.Program - if loadMode >= packages.LoadSyntax { - prog = cl.makeFakeLoaderProgram(pkgs) + if loadMode&packages.NeedTypes != 0 { + prog = cl.makeFakeLoaderProgram(deduplicatedPkgs) } var ssaProg *ssa.Program - if loadMode == packages.LoadAllSyntax { - ssaProg = cl.buildSSAProgram(pkgs) + if loadMode&packages.NeedDeps != 0 { + ssaProg = cl.buildSSAProgram(deduplicatedPkgs) } astLog := cl.log.Child("astcache") - astCache, err := astcache.LoadFromPackages(pkgs, astLog) + astCache, err := astcache.LoadFromPackages(deduplicatedPkgs, astLog) if err != nil { return nil, err } ret := &linter.Context{ - Packages: pkgs, + Packages: deduplicatedPkgs, + + // At least `unused` linters works properly only on original (not deduplicated) packages, + // see https://github.com/golangci/golangci-lint/pull/585. + OriginalPackages: pkgs, + Program: prog, SSAProgram: ssaProg, LoaderConfig: &loader.Config{ @@ -378,6 +407,7 @@ func (cl ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*li // separateNotCompilingPackages moves not compiling packages into separate slice: // a lot of linters crash on such packages func separateNotCompilingPackages(lintCtx *linter.Context) { + // Separate deduplicated packages goodPkgs := make([]*packages.Package, 0, len(lintCtx.Packages)) for _, pkg := range lintCtx.Packages { if pkg.IllTyped { @@ -391,4 +421,13 @@ func separateNotCompilingPackages(lintCtx *linter.Context) { if len(lintCtx.NotCompilingPackages) != 0 { lintCtx.Log.Infof("Packages that do not compile: %+v", lintCtx.NotCompilingPackages) } + + // Separate original (not deduplicated) packages + goodOriginalPkgs := make([]*packages.Package, 0, len(lintCtx.OriginalPackages)) + for _, pkg := range lintCtx.OriginalPackages { + if !pkg.IllTyped { + goodOriginalPkgs = append(goodOriginalPkgs, pkg) + } + } + lintCtx.OriginalPackages = goodOriginalPkgs } diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go index fd700a496bb..1de78e717b2 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go @@ -48,8 +48,10 @@ func NewRunner(astCache *astcache.Cache, cfg *config.Config, log logutils.Log, g return nil, err } - skipDirs := append([]string{}, packages.StdExcludeDirRegexps...) - skipDirs = append(skipDirs, cfg.Run.SkipDirs...) + skipDirs := cfg.Run.SkipDirs + if cfg.Run.UseDefaultSkipDirs { + skipDirs = append(skipDirs, packages.StdExcludeDirRegexps...) + } skipDirsProcessor, err := processors.NewSkipDirs(skipDirs, log.Child("skip dirs"), cfg.Run.Args) if err != nil { return nil, err diff --git a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go index 99d354a009e..825c3fdbded 100644 --- a/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go +++ b/tests/tools/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go @@ -21,9 +21,14 @@ type testSuiteXML struct { } type testCaseXML struct { - Name string `xml:"name,attr"` - ClassName string `xml:"classname,attr"` - Status string `xml:"status,attr"` + Name string `xml:"name,attr"` + ClassName string `xml:"classname,attr"` + Failure failureXML `xml:"failure"` +} + +type failureXML struct { + Message string `xml:"message,attr"` + Content string `xml:",cdata"` } type JunitXML struct { @@ -34,24 +39,24 @@ func NewJunitXML() *JunitXML { } func (JunitXML) Print(ctx context.Context, issues <-chan result.Issue) error { - suites := make(map[string]testSuiteXML) // use a map to group-by "FromLinter" + suites := make(map[string]testSuiteXML) // use a map to group by file for i := range issues { - fromLinter := i.FromLinter - testSuite := suites[fromLinter] - testSuite.Suite = fromLinter + suiteName := i.FilePath() + testSuite := suites[suiteName] + testSuite.Suite = i.FilePath() - var source string - for _, line := range i.SourceLines { - source += strings.TrimSpace(line) + "; " - } - tc := testCaseXML{Name: i.Text, + tc := testCaseXML{ + Name: i.FromLinter, ClassName: i.Pos.String(), - Status: strings.TrimSuffix(source, "; "), + Failure: failureXML{ + Message: i.Text, + Content: strings.Join(i.SourceLines, "\n"), + }, } testSuite.TestCases = append(testSuite.TestCases, tc) - suites[fromLinter] = testSuite + suites[suiteName] = testSuite } var res testSuitesXML diff --git a/tests/tools/vendor/github.com/pkg/errors/.travis.yml b/tests/tools/vendor/github.com/pkg/errors/.travis.yml index 588ceca183f..d4b92663bac 100644 --- a/tests/tools/vendor/github.com/pkg/errors/.travis.yml +++ b/tests/tools/vendor/github.com/pkg/errors/.travis.yml @@ -1,10 +1,14 @@ language: go go_import_path: github.com/pkg/errors go: - - 1.4.3 - - 1.5.4 - - 1.6.2 - - 1.7.1 + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x - tip script: diff --git a/tests/tools/vendor/github.com/pkg/errors/README.md b/tests/tools/vendor/github.com/pkg/errors/README.md index 273db3c98ae..6483ba2afb5 100644 --- a/tests/tools/vendor/github.com/pkg/errors/README.md +++ b/tests/tools/vendor/github.com/pkg/errors/README.md @@ -1,4 +1,4 @@ -# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) Package errors provides simple error handling primitives. @@ -47,6 +47,6 @@ We welcome pull requests, bug fixes and issue reports. With that said, the bar f Before proposing a change, please discuss your change by raising an issue. -## Licence +## License BSD-2-Clause diff --git a/tests/tools/vendor/github.com/pkg/errors/errors.go b/tests/tools/vendor/github.com/pkg/errors/errors.go index 842ee80456d..7421f326ffe 100644 --- a/tests/tools/vendor/github.com/pkg/errors/errors.go +++ b/tests/tools/vendor/github.com/pkg/errors/errors.go @@ -6,7 +6,7 @@ // return err // } // -// which applied recursively up the call stack results in error reports +// which when applied recursively up the call stack results in error reports // without context or debugging information. The errors package allows // programmers to add context to the failure path in their code in a way // that does not destroy the original value of the error. @@ -15,16 +15,17 @@ // // The errors.Wrap function returns a new error that adds context to the // original error by recording a stack trace at the point Wrap is called, -// and the supplied message. For example +// together with the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { // return errors.Wrap(err, "read failed") // } // -// If additional control is required the errors.WithStack and errors.WithMessage -// functions destructure errors.Wrap into its component operations of annotating -// an error with a stack trace and an a message, respectively. +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. // // Retrieving the cause of an error // @@ -38,7 +39,7 @@ // } // // can be inspected by errors.Cause. errors.Cause will recursively retrieve -// the topmost error which does not implement causer, which is assumed to be +// the topmost error that does not implement causer, which is assumed to be // the original cause. For example: // // switch err := errors.Cause(err).(type) { @@ -48,16 +49,16 @@ // // unknown error // } // -// causer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. // // Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can -// be formatted by the fmt package. The following verbs are supported +// be formatted by the fmt package. The following verbs are supported: // // %s print the error. If the error has a Cause it will be -// printed recursively +// printed recursively. // %v see %s // %+v extended format. Each Frame of the error's StackTrace will // be printed in detail. @@ -65,13 +66,13 @@ // Retrieving the stack trace of an error or wrapper // // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are -// invoked. This information can be retrieved with the following interface. +// invoked. This information can be retrieved with the following interface: // // type stackTracer interface { // StackTrace() errors.StackTrace // } // -// Where errors.StackTrace is defined as +// The returned errors.StackTrace type is defined as // // type StackTrace []Frame // @@ -85,8 +86,8 @@ // } // } // -// stackTracer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. // // See the documentation for Frame.Format for more details. package errors @@ -192,7 +193,7 @@ func Wrap(err error, message string) error { } // Wrapf returns an error annotating err with a stack trace -// at the point Wrapf is call, and the format specifier. +// at the point Wrapf is called, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { @@ -220,6 +221,18 @@ func WithMessage(err error, message string) error { } } +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + type withMessage struct { cause error msg string diff --git a/tests/tools/vendor/github.com/pkg/errors/stack.go b/tests/tools/vendor/github.com/pkg/errors/stack.go index 6b1f2891a5a..2874a048cf3 100644 --- a/tests/tools/vendor/github.com/pkg/errors/stack.go +++ b/tests/tools/vendor/github.com/pkg/errors/stack.go @@ -46,7 +46,8 @@ func (f Frame) line() int { // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+s path of source file relative to the compile time GOPATH +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) // %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { switch verb { @@ -79,6 +80,14 @@ func (f Frame) Format(s fmt.State, verb rune) { // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -136,43 +145,3 @@ func funcname(name string) string { i = strings.Index(name, ".") return name[i+1:] } - -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file -} diff --git a/tests/tools/vendor/github.com/timakin/bodyclose/passes/bodyclose/bodyclose.go b/tests/tools/vendor/github.com/timakin/bodyclose/passes/bodyclose/bodyclose.go index 1ea79f148d8..2d62eb2fe0f 100644 --- a/tests/tools/vendor/github.com/timakin/bodyclose/passes/bodyclose/bodyclose.go +++ b/tests/tools/vendor/github.com/timakin/bodyclose/passes/bodyclose/bodyclose.go @@ -38,7 +38,9 @@ type runner struct { skipFile map[*ast.File]bool } -func (r *runner) run(pass *analysis.Pass) (interface{}, error) { +// run executes an analysis for the pass. The receiver is passed +// by value because this func is called in parallel for different passes. +func (r runner) run(pass *analysis.Pass) (interface{}, error) { r.pass = pass funcs := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).SrcFuncs @@ -227,7 +229,7 @@ func (r *runner) isCloseCall(ccall ssa.Instruction) bool { return true } case *ssa.Call: - if ccall.Call.Method.Name() == r.closeMthd.Name() { + if ccall.Call.Method != nil && ccall.Call.Method.Name() == r.closeMthd.Name() { return true } case *ssa.ChangeInterface: diff --git a/tests/tools/vendor/github.com/ultraware/funlen/LICENSE b/tests/tools/vendor/github.com/ultraware/funlen/LICENSE new file mode 100644 index 00000000000..dca75556d8f --- /dev/null +++ b/tests/tools/vendor/github.com/ultraware/funlen/LICENSE @@ -0,0 +1,7 @@ +Copyright 2018 Ultraware Consultancy and Development B.V. + +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. diff --git a/tests/tools/vendor/github.com/ultraware/funlen/README.md b/tests/tools/vendor/github.com/ultraware/funlen/README.md new file mode 100644 index 00000000000..ca7e9a0f755 --- /dev/null +++ b/tests/tools/vendor/github.com/ultraware/funlen/README.md @@ -0,0 +1,69 @@ +# Funlen linter + +Funlen is a linter that checks for long functions. It can checks both on the number of lines and the number of statements. + +The default limits are 50 lines and 35 statements. You can configure these with the `-l` and `-s` flags. + +Example code: + +```go +package main + +import "fmt" + +func fiveStatements() { + fmt.Println(1) + fmt.Println(2) + fmt.Println(3) + fmt.Println(4) + fmt.Println(5) +} + +func sevenLines() { + fmt.Println(1) + + fmt.Println(2) + + fmt.Println(3) + + fmt.Println(4) +} +``` + +Reults in: + +``` +$ funlen -l=6 -s=4 . +main.go:5:6:Function 'fiveStatements' has too many statements (5 > 4) +main.go:13:6:Function 'sevenLines' is too long (7 > 6) +``` + +## Installation guide + +```bash +go get git.ultraware.nl/NiseVoid/funlen +``` + +### Gometalinter + +You can add funlen to gometalinter and enable it. + +`.gometalinter.json`: + +```json +{ + "Linters": { + "funlen": "funlen -l=50 -s=35:PATH:LINE:COL:MESSAGE" + }, + + "Enable": [ + "funlen" + ] +} +``` + +commandline: + +```bash +gometalinter --linter "funlen:funlen -l=50 -s=35:PATH:LINE:COL:MESSAGE" --enable "funlen" +``` diff --git a/tests/tools/vendor/github.com/ultraware/funlen/main.go b/tests/tools/vendor/github.com/ultraware/funlen/main.go new file mode 100644 index 00000000000..5a1ceeb791b --- /dev/null +++ b/tests/tools/vendor/github.com/ultraware/funlen/main.go @@ -0,0 +1,98 @@ +package funlen + +import ( + "fmt" + "go/ast" + "go/token" + "reflect" +) + +const defaultLineLimit = 60 +const defaultStmtLimit = 40 + +// Run runs this linter on the provided code +func Run(file *ast.File, fset *token.FileSet, lineLimit, stmtLimit int) []Message { + if lineLimit == 0 { + lineLimit = defaultLineLimit + } + if stmtLimit == 0 { + stmtLimit = defaultStmtLimit + } + + var msgs []Message + for _, f := range file.Decls { + decl, ok := f.(*ast.FuncDecl) + if !ok { + continue + } + + if stmts := parseStmts(decl.Body.List); stmts > stmtLimit { + msgs = append(msgs, makeStmtMessage(fset, decl.Name, stmts, stmtLimit)) + continue + } + + if lines := getLines(fset, decl); lines > lineLimit { + msgs = append(msgs, makeLineMessage(fset, decl.Name, lines, lineLimit)) + } + } + + return msgs +} + +// Message contains a message +type Message struct { + Pos token.Position + Message string +} + +func makeLineMessage(fset *token.FileSet, funcInfo *ast.Ident, lines, lineLimit int) Message { + return Message{ + fset.Position(funcInfo.Pos()), + fmt.Sprintf("Function '%s' is too long (%d > %d)\n", funcInfo.Name, lines, lineLimit), + } +} + +func makeStmtMessage(fset *token.FileSet, funcInfo *ast.Ident, stmts, stmtLimit int) Message { + return Message{ + fset.Position(funcInfo.Pos()), + fmt.Sprintf("Function '%s' has too many statements (%d > %d)\n", funcInfo.Name, stmts, stmtLimit), + } +} + +func getLines(fset *token.FileSet, f *ast.FuncDecl) int { // nolint: interfacer + return fset.Position(f.End()).Line - fset.Position(f.Pos()).Line - 1 +} + +func parseStmts(s []ast.Stmt) (total int) { + for _, v := range s { + total++ + switch stmt := v.(type) { + case *ast.BlockStmt: + total += parseStmts(stmt.List) - 1 + case *ast.ForStmt, *ast.RangeStmt, *ast.IfStmt, + *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt: + total += parseBodyListStmts(stmt) + case *ast.CaseClause: + total += parseStmts(stmt.Body) + case *ast.AssignStmt: + total += checkInlineFunc(stmt.Rhs[0]) + case *ast.GoStmt: + total += checkInlineFunc(stmt.Call.Fun) + case *ast.DeferStmt: + total += checkInlineFunc(stmt.Call.Fun) + } + } + return +} + +func checkInlineFunc(stmt ast.Expr) int { + if block, ok := stmt.(*ast.FuncLit); ok { + return parseStmts(block.Body.List) + } + return 0 +} + +func parseBodyListStmts(t interface{}) int { + i := reflect.ValueOf(t).Elem().FieldByName(`Body`).Elem().FieldByName(`List`).Interface() + return parseStmts(i.([]ast.Stmt)) +} diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/analysis.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/analysis.go index 8eb73162593..bc58c31c9f0 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/analysis.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/analysis.go @@ -128,11 +128,13 @@ type Pass struct { // See comments for ExportObjectFact. ExportPackageFact func(fact Fact) - // AllPackageFacts returns a new slice containing all package facts in unspecified order. + // 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 in unspecified order. + // 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 @@ -161,6 +163,15 @@ func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) { pass.Report(Diagnostic{Pos: pos, Message: msg}) } +// reportNodef is a helper function that reports a Diagnostic using the +// range denoted by the AST node. +// +// WARNING: This is an experimental API and may change in the future. +func (pass *Pass) reportNodef(node ast.Node, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + pass.Report(Diagnostic{Pos: node.Pos(), End: node.End(), Message: msg}) +} + func (pass *Pass) String() string { return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path()) } @@ -202,14 +213,3 @@ func (pass *Pass) String() string { type Fact interface { AFact() // dummy method to avoid type errors } - -// A Diagnostic is a message associated with a source location. -// -// 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. -type Diagnostic struct { - Pos token.Pos - Category string // optional - Message string -} diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/diagnostic.go new file mode 100644 index 00000000000..744072cd798 --- /dev/null +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/diagnostic.go @@ -0,0 +1,48 @@ +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 +} + +// 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 +} diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index 1e4fac85954..d499f3c3299 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -107,7 +107,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t // cgo files of a package (those that import "C"). Such files are not // Go, so there may be gaps in type information around C.f references. // -// This checker was initially written in vet to inpect raw cgo source +// This checker was initially written in vet to inspect raw cgo source // files using partial type information. However, Analyzers in the new // analysis API are presented with the type-checked, "cooked" Go ASTs // resulting from cgo-processing files, so we must choose between @@ -133,7 +133,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t // func (T) f(int) string { ... } // // we synthesize a new ast.File, shown below, that dot-imports the -// orginal "cooked" package using a special name ("·this·"), so that all +// original "cooked" package using a special name ("·this·"), so that all // references to package members resolve correctly. (References to // unexported names cause an "unexported" error, which we ignore.) // diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/composite/whitelist.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/composite/whitelist.go index ab609f279bc..1e5f5fd20b5 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/composite/whitelist.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/composite/whitelist.go @@ -24,6 +24,7 @@ var unkeyedLiteral = map[string]bool{ "image.Uniform": true, "unicode.Range16": true, + "unicode.Range32": true, // These three structs are used in generated test main files, // but the generator can be trusted. diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go index 75655c5bad4..51600ffc7eb 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go @@ -102,10 +102,11 @@ func run(pass *analysis.Pass) (interface{}, error) { inspect.Preorder(nodeFilter, func(n ast.Node) { switch n := n.(type) { case *ast.FuncDecl: - fn := pass.TypesInfo.Defs[n.Name].(*types.Func) - funcDecls[fn] = &declInfo{decl: n} - decls = append(decls, fn) - + // Type information may be incomplete. + if fn, ok := pass.TypesInfo.Defs[n.Name].(*types.Func); ok { + funcDecls[fn] = &declInfo{decl: n} + decls = append(decls, fn) + } case *ast.FuncLit: funcLits[n] = new(litInfo) lits = append(lits, n) diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index f59e95dc219..f0d7e44c651 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -67,15 +67,20 @@ of arguments with no format string. ` // isWrapper is a fact indicating that a function is a print or printf wrapper. -type isWrapper struct{ Printf bool } +type isWrapper struct{ Kind funcKind } func (f *isWrapper) AFact() {} func (f *isWrapper) String() string { - if f.Printf { + switch f.Kind { + case kindPrintf: return "printfWrapper" - } else { + case kindPrint: return "printWrapper" + case kindErrorf: + return "errorfWrapper" + default: + return "unknownWrapper" } } @@ -112,7 +117,11 @@ func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper { if !ok || fdecl.Body == nil { return nil } - fn := info.Defs[fdecl.Name].(*types.Func) + fn, ok := info.Defs[fdecl.Name].(*types.Func) + // Type information may be incomplete. + if !ok { + return nil + } sig := fn.Type().(*types.Signature) if !sig.Variadic() { @@ -223,16 +232,20 @@ func match(info *types.Info, arg ast.Expr, param *types.Var) bool { return ok && info.ObjectOf(id) == param } +type funcKind int + const ( - kindPrintf = 1 - kindPrint = 2 + kindUnknown funcKind = iota + kindPrintf = iota + kindPrint + kindErrorf ) // checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly. // It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...). -func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind int) { +func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind funcKind) { matched := kind == kindPrint || - kind == kindPrintf && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format) + kind != kindUnknown && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format) if !matched { return } @@ -262,7 +275,7 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k fn := w.obj var fact isWrapper if !pass.ImportObjectFact(fn, &fact) { - fact.Printf = kind == kindPrintf + fact.Kind = kind pass.ExportObjectFact(fn, &fact) for _, caller := range w.callers { checkPrintfFwd(pass, caller.w, caller.call, kind) @@ -414,42 +427,42 @@ func checkCall(pass *analysis.Pass) { call := n.(*ast.CallExpr) fn, kind := printfNameAndKind(pass, call) switch kind { - case kindPrintf: - checkPrintf(pass, call, fn) + case kindPrintf, kindErrorf: + checkPrintf(pass, kind, call, fn) case kindPrint: checkPrint(pass, call, fn) } }) } -func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind int) { +func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind funcKind) { fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func) if fn == nil { return nil, 0 } - var fact isWrapper - if pass.ImportObjectFact(fn, &fact) { - if fact.Printf { - return fn, kindPrintf - } else { - return fn, kindPrint - } - } - _, ok := isPrint[fn.FullName()] if !ok { // Next look up just "printf", for use with -printf.funcs. _, ok = isPrint[strings.ToLower(fn.Name())] } if ok { - if strings.HasSuffix(fn.Name(), "f") { + if fn.Name() == "Errorf" { + kind = kindErrorf + } else if strings.HasSuffix(fn.Name(), "f") { kind = kindPrintf } else { kind = kindPrint } + return fn, kind + } + + var fact isWrapper + if pass.ImportObjectFact(fn, &fact) { + return fn, fact.Kind } - return fn, kind + + return fn, kindUnknown } // isFormatter reports whether t satisfies fmt.Formatter. @@ -491,7 +504,7 @@ type formatState struct { } // checkPrintf checks a call to a formatted print routine such as Printf. -func checkPrintf(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { +func checkPrintf(pass *analysis.Pass, kind funcKind, call *ast.CallExpr, fn *types.Func) { format, idx := formatString(pass, call) if idx < 0 { if false { @@ -511,6 +524,7 @@ func checkPrintf(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { argNum := firstArg maxArgNum := firstArg anyIndex := false + anyW := false for i, w := 0, 0; i < len(format); i += w { w = 1 if format[i] != '%' { @@ -527,6 +541,17 @@ func checkPrintf(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if state.hasIndex { anyIndex = true } + if state.verb == 'w' { + if kind != kindErrorf { + pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w", state.name) + return + } + if anyW { + pass.Reportf(call.Pos(), "%s call has more than one error-wrapping directive %%w", state.name) + return + } + anyW = true + } if len(state.argNums) > 0 { // Continue with the next sequential argument. argNum = state.argNums[len(state.argNums)-1] + 1 @@ -697,6 +722,7 @@ const ( argFloat argComplex argPointer + argError anyType printfArgType = ^0 ) @@ -739,7 +765,7 @@ var printVerbs = []printVerb{ {'T', "-", anyType}, {'U', "-#", argRune | argInt}, {'v', allFlags, anyType}, - {'w', noFlag, anyType}, + {'w', allFlags, argError}, {'x', sharpNumFlag, argRune | argInt | argString | argPointer}, {'X', sharpNumFlag, argRune | argInt | argString | argPointer}, } diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go index 12286fd5df5..5000d9acc9e 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go @@ -37,6 +37,12 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, return true // probably a type check problem } } + + // %w accepts only errors. + if t == argError { + return types.ConvertibleTo(typ, errorType) + } + // If the type implements fmt.Formatter, we have nothing to check. if isFormatter(typ) { return true diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go index bcdb0429200..e09160379f6 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go @@ -40,8 +40,12 @@ func run(pass *analysis.Pass) (interface{}, error) { (*ast.StructType)(nil), } inspect.Preorder(nodeFilter, func(n ast.Node) { - styp := pass.TypesInfo.Types[n.(*ast.StructType)].Type.(*types.Struct) - var seen map[[2]string]token.Pos + styp, ok := pass.TypesInfo.Types[n.(*ast.StructType)].Type.(*types.Struct) + // Type information may be incomplete. + if !ok { + return + } + var seen namesSeen for i := 0; i < styp.NumFields(); i++ { field := styp.Field(i) tag := styp.Tag(i) @@ -51,11 +55,38 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } +// namesSeen keeps track of encoding tags by their key, name, and nested level +// from the initial struct. The level is taken into account because equal +// encoding key names only conflict when at the same level; otherwise, the lower +// level shadows the higher level. +type namesSeen map[uniqueName]token.Pos + +type uniqueName struct { + key string // "xml" or "json" + name string // the encoding name + level int // anonymous struct nesting level +} + +func (s *namesSeen) Get(key, name string, level int) (token.Pos, bool) { + if *s == nil { + *s = make(map[uniqueName]token.Pos) + } + pos, ok := (*s)[uniqueName{key, name, level}] + return pos, ok +} + +func (s *namesSeen) Set(key, name string, level int, pos token.Pos) { + if *s == nil { + *s = make(map[uniqueName]token.Pos) + } + (*s)[uniqueName{key, name, level}] = pos +} + var checkTagDups = []string{"json", "xml"} var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} // checkCanonicalFieldTag checks a single struct field tag. -func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *map[[2]string]token.Pos) { +func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *namesSeen) { switch pass.Pkg.Path() { case "encoding/json", "encoding/xml": // These packages know how to use their own APIs. @@ -64,7 +95,7 @@ func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, s } for _, key := range checkTagDups { - checkTagDuplicates(pass, tag, key, field, field, seen) + checkTagDuplicates(pass, tag, key, field, field, seen, 1) } if err := validateStructTag(tag); err != nil { @@ -95,28 +126,29 @@ func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, s // checkTagDuplicates checks a single struct field tag to see if any tags are // duplicated. nearest is the field that's closest to the field being checked, // while still being part of the top-level struct type. -func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) { +func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *types.Var, seen *namesSeen, level int) { val := reflect.StructTag(tag).Get(key) if val == "-" { // Ignored, even if the field is anonymous. return } if val == "" || val[0] == ',' { - if field.Anonymous() { - typ, ok := field.Type().Underlying().(*types.Struct) - if !ok { - return - } - for i := 0; i < typ.NumFields(); i++ { - field := typ.Field(i) - if !field.Exported() { - continue - } - tag := typ.Tag(i) - checkTagDuplicates(pass, tag, key, nearest, field, seen) + if !field.Anonymous() { + // Ignored if the field isn't anonymous. + return + } + typ, ok := field.Type().Underlying().(*types.Struct) + if !ok { + return + } + for i := 0; i < typ.NumFields(); i++ { + field := typ.Field(i) + if !field.Exported() { + continue } + tag := typ.Tag(i) + checkTagDuplicates(pass, tag, key, nearest, field, seen, level+1) } - // Ignored if the field isn't anonymous. return } if key == "xml" && field.Name() == "XMLName" { @@ -139,10 +171,7 @@ func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *ty } val = val[:i] } - if *seen == nil { - *seen = map[[2]string]token.Pos{} - } - if pos, ok := (*seen)[[2]string{key, val}]; ok { + if pos, ok := seen.Get(key, val, level); ok { alsoPos := pass.Fset.Position(pos) alsoPos.Column = 0 @@ -161,7 +190,7 @@ func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *ty pass.Reportf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, alsoPos) } else { - (*seen)[[2]string{key, val}] = field.Pos() + seen.Set(key, val, level, field.Pos()) } } diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go index 5dd060800cc..8232276186a 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go @@ -20,7 +20,10 @@ const Doc = `check for common mistaken usages of tests and examples The tests checker walks Test, Benchmark and Example functions checking malformed names, wrong signatures and examples documenting non-existent -identifiers.` +identifiers. + +Please see the documentation for package testing in golang.org/pkg/testing +for the conventions that are enforced for Tests, Benchmarks, and Examples.` var Analyzer = &analysis.Analyzer{ Name: "tests", diff --git a/tests/tools/vendor/golang.org/x/tools/go/analysis/validate.go b/tests/tools/vendor/golang.org/x/tools/go/analysis/validate.go index 6e6cf4984fe..b984ab6c2da 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/analysis/validate.go +++ b/tests/tools/vendor/golang.org/x/tools/go/analysis/validate.go @@ -10,7 +10,7 @@ import ( // Checks include: // that the name is a valid identifier; // that analyzer names are unique; -// that the Requires graph is acylic; +// that the Requires graph is acyclic; // that analyzer fact types are unique; // that each fact type is a pointer. func Validate(analyzers []*Analyzer) error { diff --git a/tests/tools/vendor/golang.org/x/tools/go/cfg/builder.go b/tests/tools/vendor/golang.org/x/tools/go/cfg/builder.go index 24e1aba0339..7f95a2961a9 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/cfg/builder.go +++ b/tests/tools/vendor/golang.org/x/tools/go/cfg/builder.go @@ -149,7 +149,7 @@ func (b *builder) branchStmt(s *ast.BranchStmt) { } case token.FALLTHROUGH: - for t := b.targets; t != nil; t = t.tail { + for t := b.targets; t != nil && block == nil; t = t.tail { block = t._fallthrough } diff --git a/tests/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go b/tests/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go index e3c31078251..3288a0bfc7f 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go +++ b/tests/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go @@ -976,10 +976,11 @@ const ( aliasTag ) +var predeclOnce sync.Once var predecl []types.Type // initialized lazily func predeclared() []types.Type { - if predecl == nil { + predeclOnce.Do(func() { // initialize lazily to be sure that all // elements have been initialized before predecl = []types.Type{ // basic types @@ -1026,7 +1027,7 @@ func predeclared() []types.Type { // used internally by gc; never used by this package or in .a files anyType{}, } - } + }) return predecl } diff --git a/tests/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/tests/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index fdc7da05689..ea15d57be1a 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/tests/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -82,15 +82,28 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u args = append(args, buildFlags...) args = append(args, "--", "unsafe") stdout, err := InvokeGo(ctx, env, dir, usesExportData, args...) + var goarch, compiler string if err != nil { - return nil, err - } - fields := strings.Fields(stdout.String()) - if len(fields) < 2 { - return nil, fmt.Errorf("could not determine GOARCH and Go compiler") + if strings.Contains(err.Error(), "cannot find main module") { + // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. + // TODO(matloob): Is this a problem in practice? + envout, enverr := InvokeGo(ctx, env, dir, usesExportData, "env", "GOARCH") + if enverr != nil { + return nil, err + } + goarch = strings.TrimSpace(envout.String()) + compiler = "gc" + } else { + return nil, err + } + } else { + fields := strings.Fields(stdout.String()) + if len(fields) < 2 { + return nil, fmt.Errorf("could not determine GOARCH and Go compiler") + } + goarch = fields[0] + compiler = fields[1] } - goarch := fields[0] - compiler := fields[1] return types.SizesFor(compiler, goarch), nil } diff --git a/tests/tools/vendor/golang.org/x/tools/go/loader/doc.go b/tests/tools/vendor/golang.org/x/tools/go/loader/doc.go index 9b51c9ecde0..c5aa31c1a02 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/loader/doc.go +++ b/tests/tools/vendor/golang.org/x/tools/go/loader/doc.go @@ -7,7 +7,8 @@ // of dependencies. The ASTs and the derived facts are retained for // later use. // -// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE. +// Deprecated: This is an older API and does not have support +// for modules. Use golang.org/x/tools/go/packages instead. // // The package defines two primary types: Config, which specifies a // set of initial packages to load and various other options; and @@ -201,5 +202,3 @@ package loader // the error. // // The result of using concurrency is about a 2.5x speedup for stdlib_test. - -// TODO(adonovan): overhaul the package documentation. diff --git a/tests/tools/vendor/golang.org/x/tools/go/loader/loader.go b/tests/tools/vendor/golang.org/x/tools/go/loader/loader.go index de34b809c47..bc12ca33d1a 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/loader/loader.go +++ b/tests/tools/vendor/golang.org/x/tools/go/loader/loader.go @@ -811,7 +811,15 @@ func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, err // Import of incomplete package: this indicates a cycle. fromPath := from.Pkg.Path() if cycle := imp.findPath(path, fromPath); cycle != nil { - cycle = append([]string{fromPath}, cycle...) + // Normalize cycle: start from alphabetically largest node. + pos, start := -1, "" + for i, s := range cycle { + if pos < 0 || s > start { + pos, start = i, s + } + } + cycle = append(cycle, cycle[:pos]...)[pos:] // rotate cycle to start from largest + cycle = append(cycle, cycle[0]) // add start node to end to show cycliness return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> ")) } diff --git a/tests/tools/vendor/golang.org/x/tools/go/packages/external.go b/tests/tools/vendor/golang.org/x/tools/go/packages/external.go index 22ff769ef2b..b696b687097 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/packages/external.go +++ b/tests/tools/vendor/golang.org/x/tools/go/packages/external.go @@ -16,14 +16,29 @@ import ( "strings" ) -// Driver +// The Driver Protocol +// +// The driver, given the inputs to a call to Load, returns metadata about the packages specified. +// This allows for different build systems to support go/packages by telling go/packages how the +// packages' source is organized. +// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in +// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package +// documentation in doc.go for the full description of the patterns that need to be supported. +// A driver receives as a JSON-serialized driverRequest struct in standard input and will +// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output. + +// driverRequest is used to provide the portion of Load's Config that is needed by a driver. type driverRequest struct { - Command string `json:"command"` - Mode LoadMode `json:"mode"` - Env []string `json:"env"` - BuildFlags []string `json:"build_flags"` - Tests bool `json:"tests"` - Overlay map[string][]byte `json:"overlay"` + Mode LoadMode `json:"mode"` + // Env specifies the environment the underlying build system should be run in. + Env []string `json:"env"` + // BuildFlags are flags that should be passed to the underlying build system. + BuildFlags []string `json:"build_flags"` + // Tests specifies whether the patterns should also return test packages. + Tests bool `json:"tests"` + // Overlay maps file paths (relative to the driver's working directory) to the byte contents + // of overlay files. + Overlay map[string][]byte `json:"overlay"` } // findExternalDriver returns the file path of a tool that supplies diff --git a/tests/tools/vendor/golang.org/x/tools/go/packages/golist.go b/tests/tools/vendor/golang.org/x/tools/go/packages/golist.go index 3a0d4b01236..970e8ca8b0e 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/packages/golist.go +++ b/tests/tools/vendor/golang.org/x/tools/go/packages/golist.go @@ -13,6 +13,7 @@ import ( "log" "os" "os/exec" + "path" "path/filepath" "reflect" "regexp" @@ -71,6 +72,28 @@ func (r *responseDeduper) addRoot(id string) { r.dr.Roots = append(r.dr.Roots, id) } +// goInfo contains global information from the go tool. +type goInfo struct { + rootDirs map[string]string + env goEnv +} + +type goEnv struct { + modulesOn bool +} + +func determineEnv(cfg *Config) goEnv { + buf, err := invokeGo(cfg, "env", "GOMOD") + if err != nil { + return goEnv{} + } + gomod := bytes.TrimSpace(buf.Bytes()) + + env := goEnv{} + env.modulesOn = len(gomod) > 0 + return env +} + // goListDriver uses the go list command to interpret the patterns and produce // the build system package structure. // See driver for more details. @@ -86,6 +109,28 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { }() } + // start fetching rootDirs + var info goInfo + var rootDirsReady, envReady = make(chan struct{}), make(chan struct{}) + go func() { + info.rootDirs = determineRootDirs(cfg) + close(rootDirsReady) + }() + go func() { + info.env = determineEnv(cfg) + close(envReady) + }() + getGoInfo := func() *goInfo { + <-rootDirsReady + <-envReady + return &info + } + + // always pass getGoInfo to golistDriver + golistDriver := func(cfg *Config, patterns ...string) (*driverResponse, error) { + return golistDriver(cfg, getGoInfo, patterns...) + } + // Determine files requested in contains patterns var containFiles []string var packagesNamed []string @@ -147,7 +192,7 @@ extractQueries: var containsCandidates []string if len(containFiles) != 0 { - if err := runContainsQueries(cfg, golistDriver, response, containFiles); err != nil { + if err := runContainsQueries(cfg, golistDriver, response, containFiles, getGoInfo); err != nil { return nil, err } } @@ -158,7 +203,7 @@ extractQueries: } } - modifiedPkgs, needPkgs, err := processGolistOverlay(cfg, response.dr) + modifiedPkgs, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) if err != nil { return nil, err } @@ -166,13 +211,25 @@ extractQueries: containsCandidates = append(containsCandidates, modifiedPkgs...) containsCandidates = append(containsCandidates, needPkgs...) } - if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs); err != nil { + if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs, getGoInfo); err != nil { return nil, err } // Check candidate packages for containFiles. if len(containFiles) > 0 { for _, id := range containsCandidates { - pkg := response.seenPackages[id] + pkg, ok := response.seenPackages[id] + if !ok { + response.addPackage(&Package{ + ID: id, + Errors: []Error{ + { + Kind: ListError, + Msg: fmt.Sprintf("package %s expected but not seen", id), + }, + }, + }) + continue + } for _, f := range containFiles { for _, g := range pkg.GoFiles { if sameFile(f, g) { @@ -186,26 +243,33 @@ extractQueries: return response.dr, nil } -func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string) error { +func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string, getGoInfo func() *goInfo) error { if len(pkgs) == 0 { return nil } - dr, err := driver(cfg, pkgs...) + drivercfg := *cfg + if getGoInfo().env.modulesOn { + drivercfg.BuildFlags = append(drivercfg.BuildFlags, "-mod=readonly") + } + dr, err := driver(&drivercfg, pkgs...) + if err != nil { return err } for _, pkg := range dr.Packages { response.addPackage(pkg) } - _, needPkgs, err := processGolistOverlay(cfg, response.dr) + _, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) if err != nil { return err } - addNeededOverlayPackages(cfg, driver, response, needPkgs) + if err := addNeededOverlayPackages(cfg, driver, response, needPkgs, getGoInfo); err != nil { + return err + } return nil } -func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, queries []string) error { +func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, queries []string, goInfo func() *goInfo) error { for _, query := range queries { // TODO(matloob): Do only one query per directory. fdir := filepath.Dir(query) @@ -216,8 +280,31 @@ func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, q return fmt.Errorf("could not determine absolute path of file= query path %q: %v", query, err) } dirResponse, err := driver(cfg, pattern) - if err != nil { - return err + if err != nil || (len(dirResponse.Packages) == 1 && len(dirResponse.Packages[0].Errors) == 1) { + // There was an error loading the package. Try to load the file as an ad-hoc package. + // Usually the error will appear in a returned package, but may not if we're in modules mode + // and the ad-hoc is located outside a module. + var queryErr error + dirResponse, queryErr = driver(cfg, query) + if queryErr != nil { + // Return the original error if the attempt to fall back failed. + return err + } + // Special case to handle issue #33482: + // If this is a file= query for ad-hoc packages where the file only exists on an overlay, + // and exists outside of a module, add the file in for the package. + if len(dirResponse.Packages) == 1 && len(dirResponse.Packages) == 1 && + dirResponse.Packages[0].ID == "command-line-arguments" && len(dirResponse.Packages[0].GoFiles) == 0 { + filename := filepath.Join(pattern, filepath.Base(query)) // avoid recomputing abspath + // TODO(matloob): check if the file is outside of a root dir? + for path := range cfg.Overlay { + if path == filename { + dirResponse.Packages[0].Errors = nil + dirResponse.Packages[0].GoFiles = []string{path} + dirResponse.Packages[0].CompiledGoFiles = []string{path} + } + } + } } isRoot := make(map[string]bool, len(dirResponse.Roots)) for _, root := range dirResponse.Roots { @@ -294,9 +381,7 @@ func runNamedQueries(cfg *Config, driver driver, response *responseDeduper, quer startWalk := time.Now() gopathwalk.Walk(roots, add, gopathwalk.Options{ModulesEnabled: modRoot != "", Debug: debug}) - if debug { - log.Printf("%v for walk", time.Since(startWalk)) - } + cfg.Logf("%v for walk", time.Since(startWalk)) // Weird special case: the top-level package in a module will be in // whatever directory the user checked the repository out into. It's @@ -547,7 +632,7 @@ func otherFiles(p *jsonPackage) [][]string { // golistDriver uses the "go list" command to expand the pattern // words and return metadata for the specified packages. dir may be // "" and env may be nil, as per os/exec.Command. -func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { +func golistDriver(cfg *Config, rootsDirs func() *goInfo, words ...string) (*driverResponse, error) { // go list uses the following identifiers in ImportPath and Imports: // // "p" -- importable package or main (command) @@ -588,6 +673,20 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { return nil, fmt.Errorf("package missing import path: %+v", p) } + // Work around https://golang.org/issue/33157: + // go list -e, when given an absolute path, will find the package contained at + // that directory. But when no package exists there, it will return a fake package + // with an error and the ImportPath set to the absolute path provided to go list. + // Try toto convert that absolute path to what its package path would be if it's + // contained in a known module or GOPATH entry. This will allow the package to be + // properly "reclaimed" when overlays are processed. + if filepath.IsAbs(p.ImportPath) && p.Error != nil { + pkgPath, ok := getPkgPath(p.ImportPath, rootsDirs) + if ok { + p.ImportPath = pkgPath + } + } + if old, found := seen[p.ImportPath]; found { if !reflect.DeepEqual(p, old) { return nil, fmt.Errorf("internal error: go list gives conflicting information for package %v", p.ImportPath) @@ -681,7 +780,7 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { if p.Error != nil { pkg.Errors = append(pkg.Errors, Error{ Pos: p.Error.Pos, - Msg: p.Error.Err, + Msg: strings.TrimSpace(p.Error.Err), // Trim to work around golang.org/issue/32363. }) } @@ -691,6 +790,27 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { return &response, nil } +// getPkgPath finds the package path of a directory if it's relative to a root directory. +func getPkgPath(dir string, goInfo func() *goInfo) (string, bool) { + for rdir, rpath := range goInfo().rootDirs { + // TODO(matloob): This doesn't properly handle symlinks. + r, err := filepath.Rel(rdir, dir) + if err != nil { + continue + } + if rpath != "" { + // We choose only ore root even though the directory even it can belong in multiple modules + // or GOPATH entries. This is okay because we only need to work with absolute dirs when a + // file is missing from disk, for instance when gopls calls go/packages in an overlay. + // Once the file is saved, gopls, or the next invocation of the tool will get the correct + // result straight from golist. + // TODO(matloob): Implement module tiebreaking? + return path.Join(rpath, filepath.ToSlash(r)), true + } + } + return "", false +} + // absJoin absolutizes and flattens the lists of files. func absJoin(dir string, fileses ...[]string) (res []string) { for _, files := range fileses { @@ -711,7 +831,8 @@ func golistargs(cfg *Config, words []string) []string { fmt.Sprintf("-compiled=%t", cfg.Mode&(NeedCompiledGoFiles|NeedSyntax|NeedTypesInfo|NeedTypesSizes) != 0), fmt.Sprintf("-test=%t", cfg.Tests), fmt.Sprintf("-export=%t", usesExportData(cfg)), - fmt.Sprintf("-deps=%t", cfg.Mode&NeedDeps != 0), + fmt.Sprintf("-deps=%t", cfg.Mode&NeedDeps != 0 || + cfg.Mode&NeedTypesInfo != 0), // Dependencies are required to do typechecking on sources, which is required for the TypesInfo. // go list doesn't let you pass -test and -find together, // probably because you'd just get the TestMain. fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0), @@ -737,11 +858,9 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { cmd.Dir = cfg.Dir cmd.Stdout = stdout cmd.Stderr = stderr - if debug { - defer func(start time.Time) { - log.Printf("%s for %v, stderr: <<%s>>\n", time.Since(start), cmdDebugStr(cmd, args...), stderr) - }(time.Now()) - } + defer func(start time.Time) { + cfg.Logf("%s for %v, stderr: <<%s>>\n", time.Since(start), cmdDebugStr(cmd, args...), stderr) + }(time.Now()) if err := cmd.Run(); err != nil { // Check for 'go' executable not being found. @@ -761,6 +880,19 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { return nil, goTooOldError{fmt.Errorf("unsupported version of go: %s: %s", exitErr, stderr)} } + // Related to #24854 + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "unexpected directory layout") { + return nil, fmt.Errorf("%s", stderr.String()) + } + + // Is there an error running the C compiler in cgo? This will be reported in the "Error" field + // and should be suppressed by go list -e. + // + // This condition is not perfect yet because the error message can include other error messages than runtime/cgo. + if len(stderr.String()) > 0 && strings.HasPrefix(stderr.String(), "# runtime/cgo\n") { + return stdout, nil + } + // This error only appears in stderr. See golang.org/cl/166398 for a fix in go list to show // the error in the Err section of stdout in case -e option is provided. // This fix is provided for backwards compatibility. @@ -770,13 +902,49 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { return bytes.NewBufferString(output), nil } + // Similar to the previous error, but currently lacks a fix in Go. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must all be in one directory") { + output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Backwards compatibility for Go 1.11 because 1.12 and 1.13 put the directory in the ImportPath. + // If the package doesn't exist, put the absolute path of the directory into the error message, + // as Go 1.13 list does. + const noSuchDirectory = "no such directory" + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), noSuchDirectory) { + errstr := stderr.String() + abspath := strings.TrimSpace(errstr[strings.Index(errstr, noSuchDirectory)+len(noSuchDirectory):]) + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + abspath, strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + // Workaround for #29280: go list -e has incorrect behavior when an ad-hoc package doesn't exist. + // Note that the error message we look for in this case is different that the one looked for above. if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no such file or directory") { output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, strings.Trim(stderr.String(), "\n")) return bytes.NewBufferString(output), nil } + // Workaround for an instance of golang.org/issue/26755: go list -e will return a non-zero exit + // status if there's a dependency on a package that doesn't exist. But it should return + // a zero exit status and set an error on that package. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") { + // try to extract package name from string + stderrStr := stderr.String() + var importPath string + colon := strings.Index(stderrStr, ":") + if colon > 0 && strings.HasPrefix(stderrStr, "go build ") { + importPath = stderrStr[len("go build "):colon] + } + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + importPath, strings.Trim(stderrStr, "\n")) + return bytes.NewBufferString(output), nil + } + // Export mode entails a build. // If that build fails, errors appear on stderr // (despite the -e flag) and the Export field is blank. diff --git a/tests/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/tests/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go index 33a0a28f2c4..941b0f47d26 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/tests/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -1,8 +1,12 @@ package packages import ( + "bytes" + "encoding/json" + "fmt" "go/parser" "go/token" + "path" "path/filepath" "strconv" "strings" @@ -12,74 +16,167 @@ import ( // files that don't exist on disk to an overlay. The results can be // sometimes incorrect. // TODO(matloob): Handle unsupported cases, including the following: -// - test files -// - adding test and non-test files to test variants of packages // - determining the correct package to add given a new import path -// - creating packages that don't exist -func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs, needPkgs []string, err error) { +func processGolistOverlay(cfg *Config, response *responseDeduper, rootDirs func() *goInfo) (modifiedPkgs, needPkgs []string, err error) { havePkgs := make(map[string]string) // importPath -> non-test package ID needPkgsSet := make(map[string]bool) modifiedPkgsSet := make(map[string]bool) - for _, pkg := range response.Packages { + for _, pkg := range response.dr.Packages { // This is an approximation of import path to id. This can be // wrong for tests, vendored packages, and a number of other cases. havePkgs[pkg.PkgPath] = pkg.ID } -outer: - for path, contents := range cfg.Overlay { - base := filepath.Base(path) - if strings.HasSuffix(path, "_test.go") { - // Overlays don't support adding new test files yet. - // TODO(matloob): support adding new test files. + // If no new imports are added, it is safe to avoid loading any needPkgs. + // Otherwise, it's hard to tell which package is actually being loaded + // (due to vendoring) and whether any modified package will show up + // in the transitive set of dependencies (because new imports are added, + // potentially modifying the transitive set of dependencies). + var overlayAddsImports bool + + for opath, contents := range cfg.Overlay { + base := filepath.Base(opath) + dir := filepath.Dir(opath) + var pkg *Package + var testVariantOf *Package // if opath is a test file, this is the package it is testing + var fileExists bool + isTest := strings.HasSuffix(opath, "_test.go") + pkgName, ok := extractPackageName(opath, contents) + if !ok { + // Don't bother adding a file that doesn't even have a parsable package statement + // to the overlay. continue } - dir := filepath.Dir(path) - for _, pkg := range response.Packages { - var dirContains, fileExists bool - for _, f := range pkg.GoFiles { - if sameFile(filepath.Dir(f), dir) { - dirContains = true + nextPackage: + for _, p := range response.dr.Packages { + if pkgName != p.Name && p.ID != "command-line-arguments" { + continue + } + for _, f := range p.GoFiles { + if !sameFile(filepath.Dir(f), dir) { + continue } + if isTest && !hasTestFiles(p) { + // TODO(matloob): Are there packages other than the 'production' variant + // of a package that this can match? This shouldn't match the test main package + // because the file is generated in another directory. + testVariantOf = p + continue nextPackage + } + pkg = p if filepath.Base(f) == base { fileExists = true } } - // The overlay could have included an entirely new package. - isNewPackage := extractPackage(pkg, path, contents) - if dirContains || isNewPackage { - if !fileExists { - pkg.GoFiles = append(pkg.GoFiles, path) // TODO(matloob): should the file just be added to GoFiles? - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, path) - modifiedPkgsSet[pkg.ID] = true - } - imports, err := extractImports(path, contents) + } + // The overlay could have included an entirely new package. + if pkg == nil { + // Try to find the module or gopath dir the file is contained in. + // Then for modules, add the module opath to the beginning. + var pkgPath string + for rdir, rpath := range rootDirs().rootDirs { + // TODO(matloob): This doesn't properly handle symlinks. + r, err := filepath.Rel(rdir, dir) if err != nil { - // Let the parser or type checker report errors later. - continue outer + continue + } + pkgPath = filepath.ToSlash(r) + if rpath != "" { + pkgPath = path.Join(rpath, pkgPath) + } + // We only create one new package even it can belong in multiple modules or GOPATH entries. + // This is okay because tools (such as the LSP) that use overlays will recompute the overlay + // once the file is saved, and golist will do the right thing. + // TODO(matloob): Implement module tiebreaking? + break + } + if pkgPath == "" { + continue + } + isXTest := strings.HasSuffix(pkgName, "_test") + if isXTest { + pkgPath += "_test" + } + id := pkgPath + if isTest && !isXTest { + id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) + } + // Try to reclaim a package with the same id if it exists in the response. + for _, p := range response.dr.Packages { + if reclaimPackage(p, id, opath, contents) { + pkg = p + break } - for _, imp := range imports { - _, found := pkg.Imports[imp] - if !found { - needPkgsSet[imp] = true - // TODO(matloob): Handle cases when the following block isn't correct. - // These include imports of test variants, imports of vendored packages, etc. - id, ok := havePkgs[imp] - if !ok { - id = imp - } - pkg.Imports[imp] = &Package{ID: id} - } + } + // Otherwise, create a new package + if pkg == nil { + pkg = &Package{PkgPath: pkgPath, ID: id, Name: pkgName, Imports: make(map[string]*Package)} + response.addPackage(pkg) + havePkgs[pkg.PkgPath] = id + // Add the production package's sources for a test variant. + if isTest && !isXTest && testVariantOf != nil { + pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) + } + } + } + if !fileExists { + pkg.GoFiles = append(pkg.GoFiles, opath) + // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior + // if the file will be ignored due to its build tags. + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath) + modifiedPkgsSet[pkg.ID] = true + } + imports, err := extractImports(opath, contents) + if err != nil { + // Let the parser or type checker report errors later. + continue + } + for _, imp := range imports { + _, found := pkg.Imports[imp] + if !found { + overlayAddsImports = true + // TODO(matloob): Handle cases when the following block isn't correct. + // These include imports of test variants, imports of vendored packages, etc. + id, ok := havePkgs[imp] + if !ok { + id = imp } - continue outer + pkg.Imports[imp] = &Package{ID: id} + } + } + continue + } + + // toPkgPath tries to guess the package path given the id. + // This isn't always correct -- it's certainly wrong for + // vendored packages' paths. + toPkgPath := func(id string) string { + // TODO(matloob): Handle vendor paths. + i := strings.IndexByte(id, ' ') + if i >= 0 { + return id[:i] + } + return id + } + + // Do another pass now that new packages have been created to determine the + // set of missing packages. + for _, pkg := range response.dr.Packages { + for _, imp := range pkg.Imports { + pkgPath := toPkgPath(imp.ID) + if _, ok := havePkgs[pkgPath]; !ok { + needPkgsSet[pkgPath] = true } } } - needPkgs = make([]string, 0, len(needPkgsSet)) - for pkg := range needPkgsSet { - needPkgs = append(needPkgs, pkg) + if overlayAddsImports { + needPkgs = make([]string, 0, len(needPkgsSet)) + for pkg := range needPkgsSet { + needPkgs = append(needPkgs, pkg) + } } modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) for pkg := range modifiedPkgsSet { @@ -88,6 +185,55 @@ outer: return modifiedPkgs, needPkgs, err } +func hasTestFiles(p *Package) bool { + for _, f := range p.GoFiles { + if strings.HasSuffix(f, "_test.go") { + return true + } + } + return false +} + +// determineRootDirs returns a mapping from directories code can be contained in to the +// corresponding import path prefixes of those directories. +// Its result is used to try to determine the import path for a package containing +// an overlay file. +func determineRootDirs(cfg *Config) map[string]string { + // Assume modules first: + out, err := invokeGo(cfg, "list", "-m", "-json", "all") + if err != nil { + return determineRootDirsGOPATH(cfg) + } + m := map[string]string{} + type jsonMod struct{ Path, Dir string } + for dec := json.NewDecoder(out); dec.More(); { + mod := new(jsonMod) + if err := dec.Decode(mod); err != nil { + return m // Give up and return an empty map. Package won't be found for overlay. + } + if mod.Dir != "" && mod.Path != "" { + // This is a valid module; add it to the map. + m[mod.Dir] = mod.Path + } + } + return m +} + +func determineRootDirsGOPATH(cfg *Config) map[string]string { + m := map[string]string{} + out, err := invokeGo(cfg, "env", "GOPATH") + if err != nil { + // Could not determine root dir mapping. Everything is best-effort, so just return an empty map. + // When we try to find the import path for a directory, there will be no root-dir match and + // we'll give up. + return m + } + for _, p := range filepath.SplitList(string(bytes.TrimSpace(out.Bytes()))) { + m[filepath.Join(p, "src")] = "" + } + return m +} + func extractImports(filename string, contents []byte) ([]string, error) { f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? if err != nil { @@ -105,13 +251,16 @@ func extractImports(filename string, contents []byte) ([]string, error) { return res, nil } -// extractPackage attempts to extract a package defined in an overlay. +// reclaimPackage attempts to reuse a package that failed to load in an overlay. // // If the package has errors and has no Name, GoFiles, or Imports, // then it's possible that it doesn't yet exist on disk. -func extractPackage(pkg *Package, filename string, contents []byte) bool { +func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool { // TODO(rstambler): Check the message of the actual error? // It differs between $GOPATH and module mode. + if pkg.ID != id { + return false + } if len(pkg.Errors) != 1 { return false } @@ -124,15 +273,21 @@ func extractPackage(pkg *Package, filename string, contents []byte) bool { if len(pkg.Imports) > 0 { return false } - f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset? - if err != nil { - return false - } - // TODO(rstambler): This doesn't work for main packages. - if filepath.Base(pkg.PkgPath) != f.Name.Name { + pkgName, ok := extractPackageName(filename, contents) + if !ok { return false } - pkg.Name = f.Name.Name + pkg.Name = pkgName pkg.Errors = nil return true } + +func extractPackageName(filename string, contents []byte) (string, bool) { + // TODO(rstambler): Check the message of the actual error? + // It differs between $GOPATH and module mode. + f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset? + if err != nil { + return "", false + } + return f.Name.Name, true +} diff --git a/tests/tools/vendor/golang.org/x/tools/go/packages/packages.go b/tests/tools/vendor/golang.org/x/tools/go/packages/packages.go index eedd43bb6b2..4ca2b117320 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/packages/packages.go +++ b/tests/tools/vendor/golang.org/x/tools/go/packages/packages.go @@ -25,24 +25,16 @@ import ( "golang.org/x/tools/go/gcexportdata" ) -// A LoadMode specifies the amount of detail to return when loading. -// Higher-numbered modes cause Load to return more information, -// but may be slower. Load may return more information than requested. +// A LoadMode controls the amount of detail to return when loading. +// The bits below can be combined to specify which fields should be +// filled in the result packages. +// The zero value is a special case, equivalent to combining +// the NeedName, NeedFiles, and NeedCompiledGoFiles bits. +// ID and Errors (if present) will always be filled. +// Load may return more information than requested. type LoadMode int const ( - // The following constants are used to specify which fields of the Package - // should be filled when loading is done. As a special case to provide - // backwards compatibility, a LoadMode of 0 is equivalent to LoadFiles. - // For all other LoadModes, the bits below specify which fields will be filled - // in the result packages. - // WARNING: This part of the go/packages API is EXPERIMENTAL. It might - // be changed or removed up until April 15 2019. After that date it will - // be frozen. - // TODO(matloob): Remove this comment on April 15. - - // ID and Errors (if present) will always be filled. - // NeedName adds Name and PkgPath. NeedName LoadMode = 1 << iota @@ -77,30 +69,24 @@ const ( ) const ( - // LoadFiles finds the packages and computes their source file lists. - // Package fields: ID, Name, Errors, GoFiles, CompiledGoFiles, and OtherFiles. + // Deprecated: LoadFiles exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles - // LoadImports adds import information for each package - // and its dependencies. - // Package fields added: Imports. + // Deprecated: LoadImports exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. LoadImports = LoadFiles | NeedImports | NeedDeps - // LoadTypes adds type information for package-level - // declarations in the packages matching the patterns. - // Package fields added: Types, TypesSizes, Fset, and IllTyped. - // This mode uses type information provided by the build system when - // possible, and may fill in the ExportFile field. + // Deprecated: LoadTypes exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. LoadTypes = LoadImports | NeedTypes | NeedTypesSizes - // LoadSyntax adds typed syntax trees for the packages matching the patterns. - // Package fields added: Syntax, and TypesInfo, for direct pattern matches only. + // Deprecated: LoadSyntax exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo - // LoadAllSyntax adds typed syntax trees for the packages matching the patterns - // and all dependencies. - // Package fields added: Types, Fset, IllTyped, Syntax, and TypesInfo, - // for all packages in the import graph. + // Deprecated: LoadAllSyntax exists for historical compatibility + // and should not be used. Please directly specify the needed fields using the Need values. LoadAllSyntax = LoadSyntax ) @@ -117,6 +103,12 @@ type Config struct { // If Context is nil, the load cannot be cancelled. Context context.Context + // Logf is the logger for the config. + // If the user provides a logger, debug logging is enabled. + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the logger is nil, default to log.Printf. + Logf func(format string, args ...interface{}) + // Dir is the directory in which to run the build system's query tool // that provides information about the packages. // If Dir is empty, the tool is run in the current directory. @@ -275,9 +267,9 @@ type Package struct { Imports map[string]*Package // Types provides type information for the package. - // Modes LoadTypes and above set this field for packages matching the - // patterns; type information for dependencies may be missing or incomplete. - // Mode LoadAllSyntax sets this field for all packages, including dependencies. + // The NeedTypes LoadMode bit sets this field for packages matching the + // patterns; type information for dependencies may be missing or incomplete, + // unless NeedDeps and NeedImports are also set. Types *types.Package // Fset provides position information for Types, TypesInfo, and Syntax. @@ -290,8 +282,9 @@ type Package struct { // Syntax is the package's syntax trees, for the files listed in CompiledGoFiles. // - // Mode LoadSyntax sets this field for packages matching the patterns. - // Mode LoadAllSyntax sets this field for all packages, including dependencies. + // The NeedSyntax LoadMode bit populates this field for packages matching the patterns. + // If NeedDeps and NeedImports are also set, this field will also be populated + // for dependencies. Syntax []*ast.File // TypesInfo provides type information about the package's syntax trees. @@ -442,9 +435,20 @@ func newLoader(cfg *Config) *loader { } if cfg != nil { ld.Config = *cfg + // If the user has provided a logger, use it. + ld.Config.Logf = cfg.Logf + } + if ld.Config.Logf == nil { + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the user has not provided a logger, default to log.Printf. + if debug { + ld.Config.Logf = log.Printf + } else { + ld.Config.Logf = func(format string, args ...interface{}) {} + } } if ld.Config.Mode == 0 { - ld.Config.Mode = LoadFiles // Preserve zero behavior of Mode for backwards compatibility. + ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility. } if ld.Config.Env == nil { ld.Config.Env = os.Environ() @@ -493,7 +497,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { lpkg := &loaderPackage{ Package: pkg, needtypes: (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && rootIndex < 0) || rootIndex >= 0, - needsrc: (ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && rootIndex < 0) || rootIndex >= 0 || + needsrc: (ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && ld.Mode&NeedDeps != 0 && rootIndex < 0) || rootIndex >= 0 || len(ld.Overlay) > 0 || // Overlays can invalidate export data. TODO(matloob): make this check fine-grained based on dependencies on overlaid files pkg.ExportFile == "" && pkg.PkgPath != "unsafe", } @@ -540,28 +544,36 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { lpkg.color = grey stack = append(stack, lpkg) // push stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports - lpkg.Imports = make(map[string]*Package, len(stubs)) - for importPath, ipkg := range stubs { - var importErr error - imp := ld.pkgs[ipkg.ID] - if imp == nil { - // (includes package "C" when DisableCgo) - importErr = fmt.Errorf("missing package: %q", ipkg.ID) - } else if imp.color == grey { - importErr = fmt.Errorf("import cycle: %s", stack) - } - if importErr != nil { - if lpkg.importErrors == nil { - lpkg.importErrors = make(map[string]error) + // If NeedTypesInfo we need dependencies (at least for the roots) to typecheck the package. + // If NeedImports isn't set, the imports fields will all be zeroed out. + // If NeedDeps isn't also set we want to keep the stubs. + if ld.Mode&NeedTypesInfo != 0 || (ld.Mode&NeedImports != 0 && ld.Mode&NeedDeps != 0) { + lpkg.Imports = make(map[string]*Package, len(stubs)) + for importPath, ipkg := range stubs { + var importErr error + imp := ld.pkgs[ipkg.ID] + if imp == nil { + // (includes package "C" when DisableCgo) + importErr = fmt.Errorf("missing package: %q", ipkg.ID) + } else if imp.color == grey { + importErr = fmt.Errorf("import cycle: %s", stack) + } + if importErr != nil { + if lpkg.importErrors == nil { + lpkg.importErrors = make(map[string]error) + } + lpkg.importErrors[importPath] = importErr + continue } - lpkg.importErrors[importPath] = importErr - continue - } - if visit(imp) { - lpkg.needsrc = true + // If !NeedDeps, just fill Imports for the root. No need to recurse further. + if ld.Mode&NeedDeps != 0 { + if visit(imp) { + lpkg.needsrc = true + } + } + lpkg.Imports[importPath] = imp.Package } - lpkg.Imports[importPath] = imp.Package } if lpkg.needsrc { srcPkgs = append(srcPkgs, lpkg) @@ -575,7 +587,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { return lpkg.needsrc } - if ld.Mode&(NeedImports|NeedDeps) == 0 { + if ld.Mode&(NeedImports|NeedDeps|NeedTypesInfo) == 0 { // We do this to drop the stub import packages that we are not even going to try to resolve. for _, lpkg := range initial { lpkg.Imports = nil @@ -687,7 +699,7 @@ func (ld *loader) loadRecursive(lpkg *loaderPackage) { // loadPackage loads the specified package. // It must be called only once per Package, // after immediate dependencies are loaded. -// Precondition: ld.Mode >= LoadTypes. +// Precondition: ld.Mode & NeedTypes. func (ld *loader) loadPackage(lpkg *loaderPackage) { if lpkg.PkgPath == "unsafe" { // Fill in the blanks to avoid surprises. @@ -1080,5 +1092,9 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error } func usesExportData(cfg *Config) bool { - return cfg.Mode&NeedExportsFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedTypesInfo == 0 + return cfg.Mode&NeedExportsFile != 0 || + // If NeedTypes but not NeedTypesInfo we won't typecheck using sources, so we need export data. + (cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedTypesInfo == 0) || + // If NeedTypesInfo but not NeedDeps, we're typechecking a package using its sources plus its dependencies' export data + (cfg.Mode&NeedTypesInfo != 0 && cfg.Mode&NeedDeps == 0) } diff --git a/tests/tools/vendor/golang.org/x/tools/go/ssa/ssautil/load.go b/tests/tools/vendor/golang.org/x/tools/go/ssa/ssautil/load.go index 72710becf8f..659d19fdbba 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/ssa/ssautil/load.go +++ b/tests/tools/vendor/golang.org/x/tools/go/ssa/ssautil/load.go @@ -101,7 +101,7 @@ func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (* // // The mode parameter controls diagnostics and checking during SSA construction. // -// Deprecated: use golang.org/x/tools/go/packages and the Packages +// Deprecated: Use golang.org/x/tools/go/packages and the Packages // function instead; see ssa.ExampleLoadPackages. // func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program { diff --git a/tests/tools/vendor/golang.org/x/tools/go/ssa/testmain.go b/tests/tools/vendor/golang.org/x/tools/go/ssa/testmain.go index 8ec15ba5051..4bf8d98f3a6 100644 --- a/tests/tools/vendor/golang.org/x/tools/go/ssa/testmain.go +++ b/tests/tools/vendor/golang.org/x/tools/go/ssa/testmain.go @@ -27,7 +27,8 @@ import ( // (as defined by "go test") defined in the specified package, // and its TestMain function, if any. // -// Deprecated: use x/tools/go/packages to access synthetic testmain packages. +// Deprecated: Use golang.org/x/tools/go/packages to access synthetic +// testmain packages. func FindTests(pkg *Package) (tests, benchmarks, examples []*Function, main *Function) { prog := pkg.Prog @@ -112,7 +113,8 @@ func isTest(name, prefix string) bool { // Subsequent calls to prog.AllPackages include the new package. // The package pkg must belong to the program prog. // -// Deprecated: use x/tools/go/packages to access synthetic testmain packages. +// Deprecated: Use golang.org/x/tools/go/packages to access synthetic +// testmain packages. func (prog *Program) CreateTestMainPackage(pkg *Package) *Package { if pkg.Prog != prog { log.Fatal("Package does not belong to Program") diff --git a/tests/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/tests/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go index 04bb96a3627..60eb67b697c 100644 --- a/tests/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ b/tests/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -59,15 +59,27 @@ func SrcDirsRoots(ctx *build.Context) []Root { // paths of the containing source directory and the package directory. // add will be called concurrently. func Walk(roots []Root, add func(root Root, dir string), opts Options) { + WalkSkip(roots, add, func(Root, string) bool { return false }, opts) +} + +// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. +// For each package found, add will be called (concurrently) with the absolute +// paths of the containing source directory and the package directory. +// For each directory that will be scanned, skip will be called (concurrently) +// with the absolute paths of the containing source directory and the directory. +// If skip returns false on a directory it will be processed. +// add will be called concurrently. +// skip will be called concurrently. +func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { for _, root := range roots { - walkDir(root, add, opts) + walkDir(root, add, skip, opts) } } -func walkDir(root Root, add func(Root, string), opts Options) { +func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) { if _, err := os.Stat(root.Path); os.IsNotExist(err) { if opts.Debug { - log.Printf("skipping nonexistant directory: %v", root.Path) + log.Printf("skipping nonexistent directory: %v", root.Path) } return } @@ -77,6 +89,7 @@ func walkDir(root Root, add func(Root, string), opts Options) { w := &walker{ root: root, add: add, + skip: skip, opts: opts, } w.init() @@ -91,9 +104,10 @@ func walkDir(root Root, add func(Root, string), opts Options) { // walker is the callback for fastwalk.Walk. type walker struct { - root Root // The source directory to scan. - add func(Root, string) // The callback that will be invoked for every possible Go package dir. - opts Options // Options passed to Walk by the user. + root Root // The source directory to scan. + add func(Root, string) // The callback that will be invoked for every possible Go package dir. + skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. + opts Options // Options passed to Walk by the user. ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. } @@ -151,12 +165,16 @@ func (w *walker) getIgnoredDirs(path string) []string { return ignoredDirs } -func (w *walker) shouldSkipDir(fi os.FileInfo) bool { +func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { for _, ignoredDir := range w.ignoredDirs { if os.SameFile(fi, ignoredDir) { return true } } + if w.skip != nil { + // Check with the user specified callback. + return w.skip(w.root, dir) + } return false } @@ -184,7 +202,7 @@ func (w *walker) walk(path string, typ os.FileMode) error { return filepath.SkipDir } fi, err := os.Lstat(path) - if err == nil && w.shouldSkipDir(fi) { + if err == nil && w.shouldSkipDir(fi, path) { return filepath.SkipDir } return nil @@ -224,7 +242,7 @@ func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool { if !ts.IsDir() { return false } - if w.shouldSkipDir(ts) { + if w.shouldSkipDir(ts, dir) { return false } // Check for symlink loops by statting each directory component diff --git a/tests/tools/vendor/golang.org/x/tools/internal/imports/fix.go b/tests/tools/vendor/golang.org/x/tools/internal/imports/fix.go index 3af3a142972..bcfbb07ed87 100644 --- a/tests/tools/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/tests/tools/vendor/golang.org/x/tools/internal/imports/fix.go @@ -13,7 +13,6 @@ import ( "go/parser" "go/token" "io/ioutil" - "log" "os" "os/exec" "path" @@ -68,10 +67,27 @@ func importGroup(env *ProcessEnv, importPath string) int { return 0 } -// An importInfo represents a single import statement. -type importInfo struct { - importPath string // import path, e.g. "crypto/rand". - name string // import name, e.g. "crand", or "" if none. +type ImportFixType int + +const ( + AddImport ImportFixType = iota + DeleteImport + SetImportName +) + +type ImportFix struct { + // StmtInfo represents the import statement this fix will add, remove, or change. + StmtInfo ImportInfo + // IdentName is the identifier that this fix will add or remove. + IdentName string + // FixType is the type of fix this is (AddImport, DeleteImport, SetImportName). + FixType ImportFixType +} + +// An ImportInfo represents a single import statement. +type ImportInfo struct { + ImportPath string // import path, e.g. "crypto/rand". + Name string // import name, e.g. "crand", or "" if none. } // A packageInfo represents what's known about a package. @@ -169,10 +185,10 @@ func collectReferences(f *ast.File) references { return refs } -// collectImports returns all the imports in f, keyed by their package name as -// determined by pathToName. Unnamed imports (., _) and "C" are ignored. -func collectImports(f *ast.File) []*importInfo { - var imports []*importInfo +// collectImports returns all the imports in f. +// Unnamed imports (., _) and "C" are ignored. +func collectImports(f *ast.File) []*ImportInfo { + var imports []*ImportInfo for _, imp := range f.Imports { var name string if imp.Name != nil { @@ -182,9 +198,9 @@ func collectImports(f *ast.File) []*importInfo { continue } path := strings.Trim(imp.Path.Value, `"`) - imports = append(imports, &importInfo{ - name: name, - importPath: path, + imports = append(imports, &ImportInfo{ + Name: name, + ImportPath: path, }) } return imports @@ -192,9 +208,9 @@ func collectImports(f *ast.File) []*importInfo { // findMissingImport searches pass's candidates for an import that provides // pkg, containing all of syms. -func (p *pass) findMissingImport(pkg string, syms map[string]bool) *importInfo { +func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { for _, candidate := range p.candidates { - pkgInfo, ok := p.knownPackages[candidate.importPath] + pkgInfo, ok := p.knownPackages[candidate.ImportPath] if !ok { continue } @@ -234,27 +250,33 @@ type pass struct { otherFiles []*ast.File // sibling files. // Intermediate state, generated by load. - existingImports map[string]*importInfo + existingImports map[string]*ImportInfo allRefs references missingRefs references // Inputs to fix. These can be augmented between successive fix calls. lastTry bool // indicates that this is the last call and fix should clean up as best it can. - candidates []*importInfo // candidate imports in priority order. + candidates []*ImportInfo // candidate imports in priority order. knownPackages map[string]*packageInfo // information about all known packages. } // loadPackageNames saves the package names for everything referenced by imports. -func (p *pass) loadPackageNames(imports []*importInfo) error { +func (p *pass) loadPackageNames(imports []*ImportInfo) error { + if p.env.Debug { + p.env.Logf("loading package names for %v packages", len(imports)) + defer func() { + p.env.Logf("done loading package names for %v packages", len(imports)) + }() + } var unknown []string for _, imp := range imports { - if _, ok := p.knownPackages[imp.importPath]; ok { + if _, ok := p.knownPackages[imp.ImportPath]; ok { continue } - unknown = append(unknown, imp.importPath) + unknown = append(unknown, imp.ImportPath) } - names, err := p.env.getResolver().loadPackageNames(unknown, p.srcDir) + names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir) if err != nil { return err } @@ -271,24 +293,24 @@ func (p *pass) loadPackageNames(imports []*importInfo) error { // importIdentifier returns the identifier that imp will introduce. It will // guess if the package name has not been loaded, e.g. because the source // is not available. -func (p *pass) importIdentifier(imp *importInfo) string { - if imp.name != "" { - return imp.name +func (p *pass) importIdentifier(imp *ImportInfo) string { + if imp.Name != "" { + return imp.Name } - known := p.knownPackages[imp.importPath] + known := p.knownPackages[imp.ImportPath] if known != nil && known.name != "" { return known.name } - return importPathToAssumedName(imp.importPath) + return importPathToAssumedName(imp.ImportPath) } // load reads in everything necessary to run a pass, and reports whether the // file already has all the imports it needs. It fills in p.missingRefs with the // file's missing symbols, if any, or removes unused imports if not. -func (p *pass) load() bool { +func (p *pass) load() ([]*ImportFix, bool) { p.knownPackages = map[string]*packageInfo{} p.missingRefs = references{} - p.existingImports = map[string]*importInfo{} + p.existingImports = map[string]*ImportInfo{} // Load basic information about the file in question. p.allRefs = collectReferences(p.f) @@ -313,9 +335,9 @@ func (p *pass) load() bool { err := p.loadPackageNames(append(imports, p.candidates...)) if err != nil { if p.env.Debug { - log.Printf("loading package names: %v", err) + p.env.Logf("loading package names: %v", err) } - return false + return nil, false } } for _, imp := range imports { @@ -334,18 +356,18 @@ func (p *pass) load() bool { } } if len(p.missingRefs) != 0 { - return false + return nil, false } return p.fix() } // fix attempts to satisfy missing imports using p.candidates. If it finds -// everything, or if p.lastTry is true, it adds the imports it found, -// removes anything unused, and returns true. -func (p *pass) fix() bool { +// everything, or if p.lastTry is true, it updates fixes to add the imports it found, +// delete anything unused, and update import names, and returns true. +func (p *pass) fix() ([]*ImportFix, bool) { // Find missing imports. - var selected []*importInfo + var selected []*ImportInfo for left, rights := range p.missingRefs { if imp := p.findMissingImport(left, rights); imp != nil { selected = append(selected, imp) @@ -353,10 +375,11 @@ func (p *pass) fix() bool { } if !p.lastTry && len(selected) != len(p.missingRefs) { - return false + return nil, false } // Found everything, or giving up. Add the new imports and remove any unused. + var fixes []*ImportFix for _, imp := range p.existingImports { // We deliberately ignore globals here, because we can't be sure // they're in the same package. People do things like put multiple @@ -364,28 +387,80 @@ func (p *pass) fix() bool { // remove imports if they happen to have the same name as a var in // a different package. if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { - astutil.DeleteNamedImport(p.fset, p.f, imp.name, imp.importPath) + fixes = append(fixes, &ImportFix{ + StmtInfo: *imp, + IdentName: p.importIdentifier(imp), + FixType: DeleteImport, + }) + continue + } + + // An existing import may need to update its import name to be correct. + if name := p.importSpecName(imp); name != imp.Name { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: name, + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: SetImportName, + }) } } for _, imp := range selected { - astutil.AddNamedImport(p.fset, p.f, imp.name, imp.importPath) + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: p.importSpecName(imp), + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: AddImport, + }) } - if p.loadRealPackageNames { - for _, imp := range p.f.Imports { - if imp.Name != nil { - continue - } - path := strings.Trim(imp.Path.Value, `""`) - ident := p.importIdentifier(&importInfo{importPath: path}) - if ident != importPathToAssumedName(path) { - imp.Name = &ast.Ident{Name: ident, NamePos: imp.Pos()} + return fixes, true +} + +// importSpecName gets the import name of imp in the import spec. +// +// When the import identifier matches the assumed import name, the import name does +// not appear in the import spec. +func (p *pass) importSpecName(imp *ImportInfo) string { + // If we did not load the real package names, or the name is already set, + // we just return the existing name. + if !p.loadRealPackageNames || imp.Name != "" { + return imp.Name + } + + ident := p.importIdentifier(imp) + if ident == importPathToAssumedName(imp.ImportPath) { + return "" // ident not needed since the assumed and real names are the same. + } + return ident +} + +// apply will perform the fixes on f in order. +func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) { + for _, fix := range fixes { + switch fix.FixType { + case DeleteImport: + astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case AddImport: + astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case SetImportName: + // Find the matching import path and change the name. + for _, spec := range f.Imports { + path := strings.Trim(spec.Path.Value, `"`) + if path == fix.StmtInfo.ImportPath { + spec.Name = &ast.Ident{ + Name: fix.StmtInfo.Name, + NamePos: spec.Pos(), + } + } } } } - - return true } // assumeSiblingImportsValid assumes that siblings' use of packages is valid, @@ -394,15 +469,15 @@ func (p *pass) assumeSiblingImportsValid() { for _, f := range p.otherFiles { refs := collectReferences(f) imports := collectImports(f) - importsByName := map[string]*importInfo{} + importsByName := map[string]*ImportInfo{} for _, imp := range imports { importsByName[p.importIdentifier(imp)] = imp } for left, rights := range refs { if imp, ok := importsByName[left]; ok { - if _, ok := stdlib[imp.importPath]; ok { + if _, ok := stdlib[imp.ImportPath]; ok { // We have the stdlib in memory; no need to guess. - rights = stdlib[imp.importPath] + rights = stdlib[imp.ImportPath] } p.addCandidate(imp, &packageInfo{ // no name; we already know it. @@ -415,9 +490,9 @@ func (p *pass) assumeSiblingImportsValid() { // addCandidate adds a candidate import to p, and merges in the information // in pkg. -func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { +func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { p.candidates = append(p.candidates, imp) - if existing, ok := p.knownPackages[imp.importPath]; ok { + if existing, ok := p.knownPackages[imp.ImportPath]; ok { if existing.name == "" { existing.name = pkg.name } @@ -425,7 +500,7 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { existing.exports[export] = true } } else { - p.knownPackages[imp.importPath] = pkg + p.knownPackages[imp.ImportPath] = pkg } } @@ -437,13 +512,24 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { var fixImports = fixImportsDefault func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error { - abs, err := filepath.Abs(filename) + fixes, err := getFixes(fset, f, filename, env) if err != nil { return err } + apply(fset, f, fixes) + return err +} + +// getFixes gets the import fixes that need to be made to f in order to fix the imports. +// It does not modify the ast. +func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { + abs, err := filepath.Abs(filename) + if err != nil { + return nil, err + } srcDir := filepath.Dir(abs) if env.Debug { - log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) + env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) } // First pass: looking only at f, and using the naive algorithm to @@ -451,8 +537,8 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // complete. We can't add any imports yet, because we don't know // if missing references are actually package vars. p := &pass{fset: fset, f: f, srcDir: srcDir} - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } otherFiles := parseOtherFiles(fset, srcDir, filename) @@ -460,15 +546,15 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // Second pass: add information from other files in the same package, // like their package vars and imports. p.otherFiles = otherFiles - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } // Now we can try adding imports from the stdlib. p.assumeSiblingImportsValid() addStdlibCandidates(p, p.missingRefs) - if p.fix() { - return nil + if fixes, done := p.fix(); done { + return fixes, nil } // Third pass: get real package names where we had previously used @@ -477,25 +563,50 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P p = &pass{fset: fset, f: f, srcDir: srcDir, env: env} p.loadRealPackageNames = true p.otherFiles = otherFiles - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } addStdlibCandidates(p, p.missingRefs) p.assumeSiblingImportsValid() - if p.fix() { - return nil + if fixes, done := p.fix(); done { + return fixes, nil } // Go look for candidates in $GOPATH, etc. We don't necessarily load // the real exports of sibling imports, so keep assuming their contents. if err := addExternalCandidates(p, p.missingRefs, filename); err != nil { - return err + return nil, err } p.lastTry = true - p.fix() - return nil + fixes, _ := p.fix() + return fixes, nil +} + +// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed. +func getAllCandidates(filename string, env *ProcessEnv) ([]ImportFix, error) { + // TODO(suzmue): scan for additional candidates and filter out + // current package. + + // Get the stdlib candidates and sort by import path. + var paths []string + for importPath := range stdlib { + paths = append(paths, importPath) + } + sort.Strings(paths) + + var imports []ImportFix + for _, importPath := range paths { + imports = append(imports, ImportFix{ + StmtInfo: ImportInfo{ + ImportPath: importPath, + }, + IdentName: path.Base(importPath), + FixType: AddImport, + }) + } + return imports, nil } // ProcessEnv contains environment variables and settings that affect the use of @@ -506,13 +617,16 @@ type ProcessEnv struct { // If non-empty, these will be used instead of the // process-wide values. - GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS string - WorkingDir string + GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS, GOSUMDB string + WorkingDir string // If true, use go/packages regardless of the environment. ForceGoPackages bool - resolver resolver + // Logf is the default logger for the ProcessEnv. + Logf func(format string, args ...interface{}) + + resolver Resolver } func (e *ProcessEnv) env() []string { @@ -527,25 +641,29 @@ func (e *ProcessEnv) env() []string { add("GO111MODULE", e.GO111MODULE) add("GOPROXY", e.GOPROXY) add("GOFLAGS", e.GOFLAGS) + add("GOSUMDB", e.GOSUMDB) if e.WorkingDir != "" { add("PWD", e.WorkingDir) } return env } -func (e *ProcessEnv) getResolver() resolver { +func (e *ProcessEnv) GetResolver() Resolver { if e.resolver != nil { return e.resolver } if e.ForceGoPackages { - return &goPackagesResolver{env: e} + e.resolver = &goPackagesResolver{env: e} + return e.resolver } out, err := e.invokeGo("env", "GOMOD") if err != nil || len(bytes.TrimSpace(out.Bytes())) == 0 { - return &gopathResolver{env: e} + e.resolver = &gopathResolver{env: e} + return e.resolver } - return &moduleResolver{env: e} + e.resolver = &ModuleResolver{env: e} + return e.resolver } func (e *ProcessEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config { @@ -573,7 +691,7 @@ func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) { cmd.Dir = e.WorkingDir if e.Debug { - defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) + defer func(start time.Time) { e.Logf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) } if err := cmd.Run(); err != nil { return nil, fmt.Errorf("running go: %v (stderr:\n%s)", err, stderr) @@ -595,7 +713,7 @@ func cmdDebugStr(cmd *exec.Cmd) string { func addStdlibCandidates(pass *pass, refs references) { add := func(pkg string) { pass.addCandidate( - &importInfo{importPath: pkg}, + &ImportInfo{ImportPath: pkg}, &packageInfo{name: path.Base(pkg), exports: stdlib[pkg]}) } for left := range refs { @@ -613,20 +731,27 @@ func addStdlibCandidates(pass *pass, refs references) { } } -// A resolver does the build-system-specific parts of goimports. -type resolver interface { +// A Resolver does the build-system-specific parts of goimports. +type Resolver interface { // loadPackageNames loads the package names in importPaths. loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) // scan finds (at least) the packages satisfying refs. The returned slice is unordered. scan(refs references) ([]*pkg, error) + // loadExports returns the set of exported symbols in the package at dir. + // It returns an error if the package name in dir does not match expectPackage. + // loadExports may be called concurrently. + loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) } -// gopathResolver implements resolver for GOPATH and module workspaces using go/packages. +// gopackagesResolver implements resolver for GOPATH and module workspaces using go/packages. type goPackagesResolver struct { env *ProcessEnv } func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + if len(importPaths) == 0 { + return nil, nil + } cfg := r.env.newPackagesConfig(packages.LoadFiles) pkgs, err := packages.Load(cfg, importPaths...) if err != nil { @@ -670,15 +795,35 @@ func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) { return scan, nil } +func (r *goPackagesResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if pkg.goPackage == nil { + return nil, fmt.Errorf("goPackage not set") + } + exports := map[string]bool{} + fset := token.NewFileSet() + for _, fname := range pkg.goPackage.CompiledGoFiles { + f, err := parser.ParseFile(fset, fname, nil, 0) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", fname, err) + } + for name := range f.Scope.Objects { + if ast.IsExported(name) { + exports[name] = true + } + } + } + return exports, nil +} + func addExternalCandidates(pass *pass, refs references, filename string) error { - dirScan, err := pass.env.getResolver().scan(refs) + dirScan, err := pass.env.GetResolver().scan(refs) if err != nil { return err } // Search for imports matching potential package references. type result struct { - imp *importInfo + imp *ImportInfo pkg *packageInfo } results := make(chan result, len(refs)) @@ -698,7 +843,7 @@ func addExternalCandidates(pass *pass, refs references, filename string) error { go func(pkgName string, symbols map[string]bool) { defer wg.Done() - found, err := findImport(ctx, pass.env, dirScan, pkgName, symbols, filename) + found, err := findImport(ctx, pass, dirScan, pkgName, symbols, filename) if err != nil { firstErrOnce.Do(func() { @@ -712,8 +857,8 @@ func addExternalCandidates(pass *pass, refs references, filename string) error { return // No matching package. } - imp := &importInfo{ - importPath: found.importPathShort, + imp := &ImportInfo{ + ImportPath: found.importPathShort, } pkg := &packageInfo{ @@ -780,7 +925,7 @@ func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) ( return names, nil } -// importPathToNameGoPath finds out the actual package name, as declared in its .go files. +// importPathToName finds out the actual package name, as declared in its .go files. // If there's a problem, it returns "". func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) { // Fast path for standard library without going to disk. @@ -800,8 +945,8 @@ func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName s } // packageDirToName is a faster version of build.Import if -// the only thing desired is the package name. It uses build.FindOnly -// to find the directory and then only parses one file in the package, +// the only thing desired is the package name. Given a directory, +// packageDirToName then only parses one file in the package, // trusting that the files in the directory are consistent. func packageDirToName(dir string) (packageName string, err error) { d, err := os.Open(dir) @@ -922,6 +1067,10 @@ func (r *gopathResolver) scan(_ references) ([]*pkg, error) { return result, nil } +func (r *gopathResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + // VendorlessPath returns the devendorized version of the import path ipath. // For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b". func VendorlessPath(ipath string) string { @@ -935,33 +1084,11 @@ func VendorlessPath(ipath string) string { return ipath } -// loadExports returns the set of exported symbols in the package at dir. -// It returns nil on error or if the package name in dir does not match expectPackage. -func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg *pkg) (map[string]bool, error) { - if env.Debug { - log.Printf("loading exports in dir %s (seeking package %s)", pkg.dir, expectPackage) - } - if pkg.goPackage != nil { - exports := map[string]bool{} - fset := token.NewFileSet() - for _, fname := range pkg.goPackage.CompiledGoFiles { - f, err := parser.ParseFile(fset, fname, nil, 0) - if err != nil { - return nil, fmt.Errorf("parsing %s: %v", fname, err) - } - for name := range f.Scope.Objects { - if ast.IsExported(name) { - exports[name] = true - } - } - } - return exports, nil - } - +func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, expectPackage string, dir string) (map[string]bool, error) { exports := make(map[string]bool) // Look for non-test, buildable .go files which could provide exports. - all, err := ioutil.ReadDir(pkg.dir) + all, err := ioutil.ReadDir(dir) if err != nil { return nil, err } @@ -971,7 +1098,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { continue } - match, err := env.buildContext().MatchFile(pkg.dir, fi.Name()) + match, err := env.buildContext().MatchFile(dir, fi.Name()) if err != nil || !match { continue } @@ -979,7 +1106,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg } if len(files) == 0 { - return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", pkg.dir) + return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir) } fset := token.NewFileSet() @@ -990,7 +1117,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg default: } - fullFile := filepath.Join(pkg.dir, fi.Name()) + fullFile := filepath.Join(dir, fi.Name()) f, err := parser.ParseFile(fset, fullFile, nil, 0) if err != nil { return nil, fmt.Errorf("parsing %s: %v", fullFile, err) @@ -1002,7 +1129,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg continue } if pkgName != expectPackage { - return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName) + return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName) } for name := range f.Scope.Objects { if ast.IsExported(name) { @@ -1017,14 +1144,14 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg exportList = append(exportList, k) } sort.Strings(exportList) - log.Printf("loaded exports in dir %v (package %v): %v", pkg.dir, expectPackage, strings.Join(exportList, ", ")) + env.Logf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", ")) } return exports, nil } // findImport searches for a package with the given symbols. // If no package is found, findImport returns ("", false, nil) -func findImport(ctx context.Context, env *ProcessEnv, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) { +func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) { pkgDir, err := filepath.Abs(filename) if err != nil { return nil, err @@ -1034,7 +1161,12 @@ func findImport(ctx context.Context, env *ProcessEnv, dirScan []*pkg, pkgName st // Find candidate packages, looking only at their directory names first. var candidates []pkgDistance for _, pkg := range dirScan { - if pkg.dir != pkgDir && pkgIsCandidate(filename, pkgName, pkg) { + if pkg.dir == pkgDir && pass.f.Name.Name == pkgName { + // The candidate is in the same directory and has the + // same package name. Don't try to import ourselves. + continue + } + if pkgIsCandidate(filename, pkgName, pkg) { candidates = append(candidates, pkgDistance{ pkg: pkg, distance: distance(pkgDir, pkg.dir), @@ -1047,9 +1179,9 @@ func findImport(ctx context.Context, env *ProcessEnv, dirScan []*pkg, pkgName st // ones. Note that this sorts by the de-vendored name, so // there's no "penalty" for vendoring. sort.Sort(byDistanceOrImportPathShortLength(candidates)) - if env.Debug { + if pass.env.Debug { for i, c := range candidates { - log.Printf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) + pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) } } @@ -1086,10 +1218,13 @@ func findImport(ctx context.Context, env *ProcessEnv, dirScan []*pkg, pkgName st wg.Done() }() - exports, err := loadExports(ctx, env, pkgName, c.pkg) + if pass.env.Debug { + pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName) + } + exports, err := pass.env.GetResolver().loadExports(ctx, pkgName, c.pkg) if err != nil { - if env.Debug { - log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) + if pass.env.Debug { + pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) } resc <- nil return diff --git a/tests/tools/vendor/golang.org/x/tools/internal/imports/imports.go b/tests/tools/vendor/golang.org/x/tools/internal/imports/imports.go index 62533376042..2c074cb2db3 100644 --- a/tests/tools/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/tests/tools/vendor/golang.org/x/tools/internal/imports/imports.go @@ -13,12 +13,14 @@ import ( "bytes" "fmt" "go/ast" + "go/build" "go/format" "go/parser" "go/printer" "go/token" "io" "io/ioutil" + "log" "regexp" "strconv" "strings" @@ -41,13 +43,10 @@ type Options struct { } // Process implements golang.org/x/tools/imports.Process with explicit context in env. -func Process(filename string, src []byte, opt *Options) ([]byte, error) { - if src == nil { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - src = b +func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err } fileSet := token.NewFileSet() @@ -61,7 +60,93 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) { return nil, err } } + return formatFile(fileSet, file, src, adjust, opt) +} + +// FixImports returns a list of fixes to the imports that, when applied, +// will leave the imports in the same state as Process. +// +// Note that filename's directory influences which imports can be chosen, +// so it is important that filename be accurate. +func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, _, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + return getFixes(fileSet, file, filename, opt.Env) +} + +// ApplyFix will apply all of the fixes to the file and format it. +func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, adjust, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + // Apply the fixes to the file. + apply(fileSet, file, fixes) + + return formatFile(fileSet, file, src, adjust, opt) +} + +// GetAllCandidates gets all of the standard library candidate packages to import in +// sorted order on import path. +func GetAllCandidates(filename string, opt *Options) (pkgs []ImportFix, err error) { + _, opt, err = initialize(filename, []byte{}, opt) + if err != nil { + return nil, err + } + return getAllCandidates(filename, opt.Env) +} + +// initialize sets the values for opt and src. +// If they are provided, they are not changed. Otherwise opt is set to the +// default values and src is read from the file system. +func initialize(filename string, src []byte, opt *Options) ([]byte, *Options, error) { + // Use defaults if opt is nil. + if opt == nil { + opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} + } + + // Set the env if the user has not provided it. + if opt.Env == nil { + opt.Env = &ProcessEnv{ + GOPATH: build.Default.GOPATH, + GOROOT: build.Default.GOROOT, + } + } + + // Set the logger if the user has not provided it. + if opt.Env.Logf == nil { + opt.Env.Logf = log.Printf + } + + if src == nil { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, nil, err + } + src = b + } + + return src, opt, nil +} +func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { + mergeImports(opt.Env, fileSet, file) sortImports(opt.Env, fileSet, file) imps := astutil.Imports(fileSet, file) var spacesBefore []string // import paths we need spaces before @@ -89,7 +174,7 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) { printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} var buf bytes.Buffer - err = printConfig.Fprint(&buf, fileSet, file) + err := printConfig.Fprint(&buf, fileSet, file) if err != nil { return nil, err } diff --git a/tests/tools/vendor/golang.org/x/tools/internal/imports/mod.go b/tests/tools/vendor/golang.org/x/tools/internal/imports/mod.go index a072214eee9..271c7d28329 100644 --- a/tests/tools/vendor/golang.org/x/tools/internal/imports/mod.go +++ b/tests/tools/vendor/golang.org/x/tools/internal/imports/mod.go @@ -2,9 +2,10 @@ package imports import ( "bytes" + "context" "encoding/json" + "fmt" "io/ioutil" - "log" "os" "path" "path/filepath" @@ -19,37 +20,41 @@ import ( "golang.org/x/tools/internal/module" ) -// moduleResolver implements resolver for modules using the go command as little +// ModuleResolver implements resolver for modules using the go command as little // as feasible. -type moduleResolver struct { - env *ProcessEnv +type ModuleResolver struct { + env *ProcessEnv + moduleCacheDir string - initialized bool - main *moduleJSON - modsByModPath []*moduleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*moduleJSON // ...or Dir. + Initialized bool + Main *ModuleJSON + ModsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path... + ModsByDir []*ModuleJSON // ...or Dir. + + // moduleCacheInfo stores information about the module cache. + moduleCacheInfo *moduleCacheInfo } -type moduleJSON struct { +type ModuleJSON struct { Path string // module path Version string // module version Versions []string // available module versions (with -versions) - Replace *moduleJSON // replaced by this module + Replace *ModuleJSON // replaced by this module Time *time.Time // time version was created - Update *moduleJSON // available update, if any (with -u) + Update *ModuleJSON // available update, if any (with -u) Main bool // is this the main module? Indirect bool // is this module only an indirect dependency of main module? Dir string // directory holding files for this module, if any GoMod string // path to go.mod file for this module, if any - Error *moduleErrorJSON // error loading module + Error *ModuleErrorJSON // error loading module } -type moduleErrorJSON struct { +type ModuleErrorJSON struct { Err string // the error itself } -func (r *moduleResolver) init() error { - if r.initialized { +func (r *ModuleResolver) init() error { + if r.Initialized { return nil } stdout, err := r.env.invokeGo("list", "-m", "-json", "...") @@ -57,54 +62,71 @@ func (r *moduleResolver) init() error { return err } for dec := json.NewDecoder(stdout); dec.More(); { - mod := &moduleJSON{} + mod := &ModuleJSON{} if err := dec.Decode(mod); err != nil { return err } if mod.Dir == "" { if r.env.Debug { - log.Printf("module %v has not been downloaded and will be ignored", mod.Path) + r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path) } // Can't do anything with a module that's not downloaded. continue } - r.modsByModPath = append(r.modsByModPath, mod) - r.modsByDir = append(r.modsByDir, mod) + r.ModsByModPath = append(r.ModsByModPath, mod) + r.ModsByDir = append(r.ModsByDir, mod) if mod.Main { - r.main = mod + r.Main = mod } } - sort.Slice(r.modsByModPath, func(i, j int) bool { + sort.Slice(r.ModsByModPath, func(i, j int) bool { count := func(x int) int { - return strings.Count(r.modsByModPath[x].Path, "/") + return strings.Count(r.ModsByModPath[x].Path, "/") } return count(j) < count(i) // descending order }) - sort.Slice(r.modsByDir, func(i, j int) bool { + sort.Slice(r.ModsByDir, func(i, j int) bool { count := func(x int) int { - return strings.Count(r.modsByDir[x].Dir, "/") + return strings.Count(r.ModsByDir[x].Dir, "/") } return count(j) < count(i) // descending order }) - r.initialized = true + if r.moduleCacheInfo == nil { + r.moduleCacheInfo = &moduleCacheInfo{ + modCacheDirInfo: make(map[string]*directoryPackageInfo), + } + } + + r.Initialized = true return nil } // findPackage returns the module and directory that contains the package at // the given import path, or returns nil, "" if no module is in scope. -func (r *moduleResolver) findPackage(importPath string) (*moduleJSON, string) { - for _, m := range r.modsByModPath { +func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) { + for _, m := range r.ModsByModPath { if !strings.HasPrefix(importPath, m.Path) { continue } pathInModule := importPath[len(m.Path):] pkgDir := filepath.Join(m.Dir, pathInModule) - if dirIsNestedModule(pkgDir, m) { + if r.dirIsNestedModule(pkgDir, m) { continue } + if info, ok := r.moduleCacheInfo.Load(pkgDir); ok { + if packageScanned, err := info.reachedStatus(directoryScanned); packageScanned { + if err != nil { + // There was some error with scanning this directory. + // It does not contain a valid package. + continue + } + return m, pkgDir + } + } + pkgFiles, err := ioutil.ReadDir(pkgDir) if err != nil { continue @@ -124,7 +146,7 @@ func (r *moduleResolver) findPackage(importPath string) (*moduleJSON, string) { // findModuleByDir returns the module that contains dir, or nil if no such // module is in scope. -func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON { +func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON { // This is quite tricky and may not be correct. dir could be: // - a package in the main module. // - a replace target underneath the main module's directory. @@ -135,12 +157,12 @@ func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON { // - in /vendor/ in -mod=vendor mode. // - nested module? Dunno. // Rumor has it that replace targets cannot contain other replace targets. - for _, m := range r.modsByDir { + for _, m := range r.ModsByDir { if !strings.HasPrefix(dir, m.Dir) { continue } - if dirIsNestedModule(dir, m) { + if r.dirIsNestedModule(dir, m) { continue } @@ -151,18 +173,28 @@ func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON { // dirIsNestedModule reports if dir is contained in a nested module underneath // mod, not actually in mod. -func dirIsNestedModule(dir string, mod *moduleJSON) bool { +func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool { if !strings.HasPrefix(dir, mod.Dir) { return false } - mf := findModFile(dir) + if r.dirInModuleCache(dir) { + // Nested modules in the module cache are pruned, + // so it cannot be a nested module. + return false + } + mf := r.findModFile(dir) if mf == "" { return false } return filepath.Dir(mf) != mod.Dir } -func findModFile(dir string) string { +func (r *ModuleResolver) findModFile(dir string) string { + if r.dirInModuleCache(dir) { + matches := modCacheRegexp.FindStringSubmatch(dir) + index := strings.Index(dir, matches[1]+"@"+matches[2]) + return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod") + } for { f := filepath.Join(dir, "go.mod") info, err := os.Stat(f) @@ -177,7 +209,14 @@ func findModFile(dir string) string { } } -func (r *moduleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { +func (r *ModuleResolver) dirInModuleCache(dir string) bool { + if r.moduleCacheDir == "" { + return false + } + return strings.HasPrefix(dir, r.moduleCacheDir) +} + +func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { if err := r.init(); err != nil { return nil, err } @@ -196,7 +235,7 @@ func (r *moduleResolver) loadPackageNames(importPaths []string, srcDir string) ( return names, nil } -func (r *moduleResolver) scan(_ references) ([]*pkg, error) { +func (r *ModuleResolver) scan(_ references) ([]*pkg, error) { if err := r.init(); err != nil { return nil, err } @@ -205,15 +244,16 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) { roots := []gopathwalk.Root{ {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT}, } - if r.main != nil { - roots = append(roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule}) + if r.Main != nil { + roots = append(roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule}) } - for _, p := range filepath.SplitList(r.env.GOPATH) { - roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache}) + if r.moduleCacheDir == "" { + r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod") } + roots = append(roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache}) // Walk replace targets, just in case they're not in any of the above. - for _, mod := range r.modsByModPath { + for _, mod := range r.ModsByModPath { if mod.Replace != nil { roots = append(roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther}) } @@ -223,90 +263,181 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) { dupCheck := make(map[string]bool) var mu sync.Mutex - gopathwalk.Walk(roots, func(root gopathwalk.Root, dir string) { + // Packages in the module cache are immutable. If we have + // already seen this package on a previous scan of the module + // cache, return that result. + skip := func(root gopathwalk.Root, dir string) bool { mu.Lock() defer mu.Unlock() + // If we have already processed this directory on this walk, skip it. + if _, dup := dupCheck[dir]; dup { + return true + } + + // If we have saved this directory information, skip it. + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + return false + } + // This directory can be skipped as long as we have already scanned it. + // Packages with errors will continue to have errors, so there is no need + // to rescan them. + packageScanned, _ := info.reachedStatus(directoryScanned) + return packageScanned + } + add := func(root gopathwalk.Root, dir string) { + mu.Lock() + defer mu.Unlock() if _, dup := dupCheck[dir]; dup { return } - dupCheck[dir] = true + info, err := r.scanDirForPackage(root, dir) + if err != nil { + return + } + if root.Type == gopathwalk.RootModuleCache { + // Save this package information in the cache and return. + // Packages from the module cache are added after Walk. + r.moduleCacheInfo.Store(dir, info) + return + } - subdir := "" - if dir != root.Path { - subdir = dir[len(root.Path)+len("/"):] + // Skip this package if there was an error loading package info. + if info.err != nil { + return } - importPath := filepath.ToSlash(subdir) - if strings.HasPrefix(importPath, "vendor/") { - // Ignore vendor dirs. If -mod=vendor is on, then things - // should mostly just work, but when it's not vendor/ - // is a mess. There's no easy way to tell if it's on. - // We can still find things in the mod cache and - // map them into /vendor when -mod=vendor is on. + + // The rest of this function canonicalizes the packages using the results + // of initializing the resolver from 'go list -m'. + res, err := r.canonicalize(info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { return } - switch root.Type { - case gopathwalk.RootCurrentModule: - importPath = path.Join(r.main.Path, filepath.ToSlash(subdir)) - case gopathwalk.RootModuleCache: - matches := modCacheRegexp.FindStringSubmatch(subdir) - modPath, err := module.DecodePath(filepath.ToSlash(matches[1])) - if err != nil { - if r.env.Debug { - log.Printf("decoding module cache path %q: %v", subdir, err) - } - return - } - importPath = path.Join(modPath, filepath.ToSlash(matches[3])) - case gopathwalk.RootGOROOT: - importPath = subdir - } - - // Check if the directory is underneath a module that's in scope. - if mod := r.findModuleByDir(dir); mod != nil { - // It is. If dir is the target of a replace directive, - // our guessed import path is wrong. Use the real one. - if mod.Dir == dir { - importPath = mod.Path - } else { - dirInMod := dir[len(mod.Dir)+len("/"):] - importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) - } - } else { - // The package is in an unknown module. Check that it's - // not obviously impossible to import. - var modFile string - switch root.Type { - case gopathwalk.RootModuleCache: - matches := modCacheRegexp.FindStringSubmatch(subdir) - modFile = filepath.Join(matches[1], "@", matches[2], "go.mod") - default: - modFile = findModFile(dir) - } - modBytes, err := ioutil.ReadFile(modFile) - if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) { - // The module's declared path does not match - // its expected path. It probably needs a - // replace directive we don't have. - return - } + result = append(result, res) + } + + gopathwalk.WalkSkip(roots, add, skip, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true}) + + // Add the packages from the modules in the mod cache that were skipped. + for _, dir := range r.moduleCacheInfo.Keys() { + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + continue } - // We may have discovered a package that has a different version - // in scope already. Canonicalize to that one if possible. - if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { - dir = canonicalDir + + // Skip this directory if we were not able to get the package information successfully. + if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { + continue } - result = append(result, &pkg{ - importPathShort: VendorlessPath(importPath), - dir: dir, - }) - }, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true}) + res, err := r.canonicalize(info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { + continue + } + result = append(result, res) + } + return result, nil } +// canonicalize gets the result of canonicalizing the packages using the results +// of initializing the resolver from 'go list -m'. +func (r *ModuleResolver) canonicalize(importPath, dir string, needsReplace bool) (res *pkg, err error) { + // Check if the directory is underneath a module that's in scope. + if mod := r.findModuleByDir(dir); mod != nil { + // It is. If dir is the target of a replace directive, + // our guessed import path is wrong. Use the real one. + if mod.Dir == dir { + importPath = mod.Path + } else { + dirInMod := dir[len(mod.Dir)+len("/"):] + importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) + } + } else if needsReplace { + return nil, fmt.Errorf("needed this package to be in scope: %s", dir) + } + + // We may have discovered a package that has a different version + // in scope already. Canonicalize to that one if possible. + if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { + dir = canonicalDir + } + return &pkg{ + importPathShort: VendorlessPath(importPath), + dir: dir, + }, nil +} + +func (r *ModuleResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if err := r.init(); err != nil { + return nil, err + } + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + +func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) (directoryPackageInfo, error) { + subdir := "" + if dir != root.Path { + subdir = dir[len(root.Path)+len("/"):] + } + importPath := filepath.ToSlash(subdir) + if strings.HasPrefix(importPath, "vendor/") { + // Ignore vendor dirs. If -mod=vendor is on, then things + // should mostly just work, but when it's not vendor/ + // is a mess. There's no easy way to tell if it's on. + // We can still find things in the mod cache and + // map them into /vendor when -mod=vendor is on. + return directoryPackageInfo{}, fmt.Errorf("vendor directory") + } + switch root.Type { + case gopathwalk.RootCurrentModule: + importPath = path.Join(r.Main.Path, filepath.ToSlash(subdir)) + case gopathwalk.RootModuleCache: + matches := modCacheRegexp.FindStringSubmatch(subdir) + if len(matches) == 0 { + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("invalid module cache path: %v", subdir), + }, nil + } + modPath, err := module.DecodePath(filepath.ToSlash(matches[1])) + if err != nil { + if r.env.Debug { + r.env.Logf("decoding module cache path %q: %v", subdir, err) + } + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("decoding module cache path %q: %v", subdir, err), + }, nil + } + importPath = path.Join(modPath, filepath.ToSlash(matches[3])) + case gopathwalk.RootGOROOT: + importPath = subdir + } + + // Check that this package is not obviously impossible to import. + modFile := r.findModFile(dir) + + var needsReplace bool + modBytes, err := ioutil.ReadFile(modFile) + if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) { + // The module's declared path does not match + // its expected path. It probably needs a + // replace directive we don't have. + needsReplace = true + } + + return directoryPackageInfo{ + status: directoryScanned, + dir: dir, + nonCanonicalImportPath: importPath, + needsReplace: needsReplace, + }, nil +} + // modCacheRegexp splits a path in a module cache into module, module version, and package. var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) diff --git a/tests/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/tests/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go new file mode 100644 index 00000000000..f96b92d0099 --- /dev/null +++ b/tests/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go @@ -0,0 +1,121 @@ +package imports + +import ( + "sync" +) + +// ModuleResolver implements Resolver for modules using the go command as little +// as feasible. +// +// To find packages to import, the resolver needs to know about all of the +// the packages that could be imported. This includes packages that are +// already in modules that are in (1) the current module, (2) replace targets, +// and (3) packages in the module cache. Packages in (1) and (2) may change over +// time, as the client may edit the current module and locally replaced modules. +// The module cache (which includes all of the packages in (3)) can only +// ever be added to. +// +// The resolver can thus save state about packages in the module cache +// and guarantee that this will not change over time. To obtain information +// about new modules added to the module cache, the module cache should be +// rescanned. +// +// It is OK to serve information about modules that have been deleted, +// as they do still exist. +// TODO(suzmue): can we share information with the caller about +// what module needs to be downloaded to import this package? + +type directoryPackageStatus int + +const ( + _ directoryPackageStatus = iota + directoryScanned +) + +type directoryPackageInfo struct { + // status indicates the extent to which this struct has been filled in. + status directoryPackageStatus + // err is non-nil when there was an error trying to reach status. + err error + + // Set when status > directoryScanned. + + // dir is the absolute directory of this package. + dir string + // nonCanonicalImportPath is the expected import path for this package. + // This may not be an import path that can be used to import this package. + nonCanonicalImportPath string + // needsReplace is true if the nonCanonicalImportPath does not match the + // the modules declared path, making it impossible to import without a + // replace directive. + needsReplace bool +} + +// reachedStatus returns true when info has a status at least target and any error associated with +// an attempt to reach target. +func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (bool, error) { + if info.err == nil { + return info.status >= target, nil + } + if info.status == target { + return true, info.err + } + return true, nil +} + +// moduleCacheInfo is a concurrency safe map for storing information about +// the directories in the module cache. +// +// The information in this cache is built incrementally. Entries are initialized in scan. +// No new keys should be added in any other functions, as all directories containing +// packages are identified in scan. +// +// Other functions, including loadExports and findPackage, may update entries in this cache +// as they discover new things about the directory. +// +// We do not need to protect the data in the cache for multiple writes, because it only stores +// module cache directories, which do not change. If two competing stores take place, there will be +// one store that wins. Although this could result in a loss of information it will not be incorrect +// and may just result in recomputing the same result later. +// +// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc) +type moduleCacheInfo struct { + mu sync.Mutex + // modCacheDirInfo stores information about packages in + // module cache directories. Keyed by absolute directory. + modCacheDirInfo map[string]*directoryPackageInfo +} + +// Store stores the package info for dir. +func (d *moduleCacheInfo) Store(dir string, info directoryPackageInfo) { + d.mu.Lock() + defer d.mu.Unlock() + d.modCacheDirInfo[dir] = &directoryPackageInfo{ + status: info.status, + err: info.err, + dir: info.dir, + nonCanonicalImportPath: info.nonCanonicalImportPath, + needsReplace: info.needsReplace, + } +} + +// Load returns a copy of the directoryPackageInfo for absolute directory dir. +func (d *moduleCacheInfo) Load(dir string) (directoryPackageInfo, bool) { + d.mu.Lock() + defer d.mu.Unlock() + info, ok := d.modCacheDirInfo[dir] + if !ok { + return directoryPackageInfo{}, false + } + return *info, true +} + +// Keys returns the keys currently present in d. +func (d *moduleCacheInfo) Keys() (keys []string) { + d.mu.Lock() + defer d.mu.Unlock() + for key := range d.modCacheDirInfo { + keys = append(keys, key) + } + return keys +} diff --git a/tests/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go b/tests/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go index 0a156fe2ef9..226279471d3 100644 --- a/tests/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go +++ b/tests/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go @@ -58,6 +58,53 @@ func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { } } +// mergeImports merges all the import declarations into the first one. +// Taken from golang.org/x/tools/ast/astutil. +func mergeImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { + if len(f.Decls) <= 1 { + return + } + + // Merge all the import declarations into the first one. + var first *ast.GenDecl + for i := 0; i < len(f.Decls); i++ { + decl := f.Decls[i] + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { + continue + } + if first == nil { + first = gen + continue // Don't touch the first one. + } + // We now know there is more than one package in this import + // declaration. Ensure that it ends up parenthesized. + first.Lparen = first.Pos() + // Move the imports of the other import declaration to the first one. + for _, spec := range gen.Specs { + spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() + first.Specs = append(first.Specs, spec) + } + f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) + i-- + } +} + +// declImports reports whether gen contains an import of path. +// Taken from golang.org/x/tools/ast/astutil. +func declImports(gen *ast.GenDecl, path string) bool { + if gen.Tok != token.IMPORT { + return false + } + for _, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + if importPath(impspec) == path { + return true + } + } + return false +} + func importPath(s ast.Spec) string { t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) if err == nil { diff --git a/tests/tools/vendor/modules.txt b/tests/tools/vendor/modules.txt index aad3a2c6a83..8cdf136ea23 100644 --- a/tests/tools/vendor/modules.txt +++ b/tests/tools/vendor/modules.txt @@ -1,15 +1,16 @@ # github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml -# github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2 +# github.com/OpenPeeDeeP/depguard v1.0.0 github.com/OpenPeeDeeP/depguard # github.com/cpuguy83/go-md2man v1.0.10 +## explicit github.com/cpuguy83/go-md2man github.com/cpuguy83/go-md2man/md2man # github.com/fatih/color v1.6.0 github.com/fatih/color # github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify -# github.com/go-critic/go-critic v0.0.0-20181204210945-1df300866540 +# github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540 github.com/go-critic/go-critic/checkers github.com/go-critic/go-critic/checkers/internal/lintutil # github.com/go-lintpack/lintpack v0.5.2 @@ -52,12 +53,12 @@ github.com/golangci/dupl/printer github.com/golangci/dupl/suffixtree github.com/golangci/dupl/syntax github.com/golangci/dupl/syntax/golang -# github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6 +# github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 github.com/golangci/errcheck/golangci github.com/golangci/errcheck/internal/errcheck # github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 github.com/golangci/go-misc/deadcode -# github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196 +# github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c github.com/golangci/go-tools/arg github.com/golangci/go-tools/callgraph github.com/golangci/go-tools/callgraph/static @@ -82,10 +83,11 @@ github.com/golangci/go-tools/version github.com/golangci/goconst # github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee github.com/golangci/gocyclo/pkg/gocyclo -# github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98 +# github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98 github.com/golangci/gofmt/gofmt github.com/golangci/gofmt/goimports -# github.com/golangci/golangci-lint v1.17.1 +# github.com/golangci/golangci-lint v1.18.0 +## explicit github.com/golangci/golangci-lint/cmd/golangci-lint github.com/golangci/golangci-lint/pkg/commands github.com/golangci/golangci-lint/pkg/config @@ -107,12 +109,12 @@ github.com/golangci/golangci-lint/pkg/report github.com/golangci/golangci-lint/pkg/result github.com/golangci/golangci-lint/pkg/result/processors github.com/golangci/golangci-lint/pkg/timeutils -# github.com/golangci/gosec v0.0.0-20180901114220-66fb7fc33547 +# github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547 github.com/golangci/gosec github.com/golangci/gosec/rules -# github.com/golangci/ineffassign v0.0.0-20180808204949-42439a7714cc +# github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc github.com/golangci/ineffassign -# github.com/golangci/lint-1 v0.0.0-20180610141402-ee948d087217 +# github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217 github.com/golangci/lint-1 # github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca github.com/golangci/maligned @@ -173,6 +175,7 @@ github.com/nbutton23/zxcvbn-go/matching github.com/nbutton23/zxcvbn-go/scoring github.com/nbutton23/zxcvbn-go/utils/math # github.com/onsi/ginkgo v1.8.0 +## explicit github.com/onsi/ginkgo/config github.com/onsi/ginkgo/ginkgo github.com/onsi/ginkgo/ginkgo/convert @@ -196,7 +199,7 @@ github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty github.com/onsi/ginkgo/types # github.com/pelletier/go-toml v1.1.0 github.com/pelletier/go-toml -# github.com/pkg/errors v0.8.0 +# github.com/pkg/errors v0.8.1 github.com/pkg/errors # github.com/russross/blackfriday v1.5.2 github.com/russross/blackfriday @@ -217,9 +220,12 @@ github.com/spf13/jwalterweatherman github.com/spf13/pflag # github.com/spf13/viper v1.0.2 github.com/spf13/viper -# github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb +# github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec github.com/timakin/bodyclose/passes/bodyclose +# github.com/ultraware/funlen v0.0.1 +github.com/ultraware/funlen # github.com/vbatts/git-validation v1.0.0 +## explicit github.com/vbatts/git-validation github.com/vbatts/git-validation/git github.com/vbatts/git-validation/rules/danglingwhitespace @@ -233,7 +239,7 @@ golang.org/x/sys/unix golang.org/x/text/transform golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd +# golang.org/x/tools v0.0.0-20190909030654-5b82db07426d golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/passes/asmdecl golang.org/x/tools/go/analysis/passes/assign @@ -291,7 +297,7 @@ gopkg.in/yaml.v2 mvdan.cc/interfacer/check # mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b mvdan.cc/lint -# mvdan.cc/unparam v0.0.0-20190124213536-fbb59629db34 +# mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 mvdan.cc/unparam/check # sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 sourcegraph.com/sqs/pbtypes