├── testdata ├── testingpkg │ ├── tests.go │ └── tests_test.go ├── tagtest │ ├── file1.go │ └── file2.go ├── divergent │ ├── buf.go │ └── buf_test.go ├── cgo │ ├── cgo3.go │ ├── cgo2.go │ ├── cgo4.go │ └── cgo.go ├── buildtag │ ├── buildtag.go │ └── buildtag_bad.go ├── asm │ ├── asm4.s │ └── asm.go ├── method.go ├── unused.go ├── assign.go ├── nilfunc.go ├── incomplete │ └── examples_test.go ├── copylock_range.go ├── shadow.go ├── httpresponse.go ├── unsafeptr.go ├── atomic.go ├── rangeloop.go ├── composite.go ├── lostcancel.go ├── copylock_func.go ├── shift.go ├── bool.go ├── structtag.go ├── copylock.go └── asm8.s ├── all └── whitelist │ ├── plan9_386.txt │ ├── android_amd64.txt │ ├── netbsd_amd64.txt │ ├── openbsd_amd64.txt │ ├── netbsd.txt │ ├── plan9_amd64.txt │ ├── plan9_arm.txt │ ├── freebsd_arm.txt │ ├── openbsd_arm.txt │ ├── darwin_amd64.txt │ ├── android_arm.txt │ ├── mips64x.txt │ ├── readme.txt │ ├── linux_arm64.txt │ ├── windows.txt │ ├── netbsd_arm.txt │ ├── linux_ppc64x.txt │ ├── freebsd_amd64.txt │ ├── dragonfly_amd64.txt │ ├── darwin_386.txt │ ├── android_386.txt │ ├── solaris_amd64.txt │ ├── darwin_arm.txt │ ├── linux_amd64.txt │ ├── mips.txt │ ├── mipsle.txt │ ├── darwin_arm64.txt │ ├── nacl_arm.txt │ ├── linux_arm.txt │ ├── mipsx.txt │ ├── s390x.txt │ ├── windows_amd64.txt │ ├── linux_386.txt │ ├── arm64.txt │ ├── windows_386.txt │ ├── ppc64x.txt │ ├── nacl_386.txt │ ├── openbsd_386.txt │ ├── arm.txt │ ├── freebsd_386.txt │ ├── amd64.txt │ ├── netbsd_386.txt │ ├── 386.txt │ ├── nacl_amd64p32.txt │ └── all.txt ├── lib ├── whitelist │ └── whitelist.go └── cfg │ ├── cfg_test.go │ └── cfg.go ├── golangci.go ├── assign.go ├── LICENSE ├── nilfunc.go ├── README ├── atomic.go ├── shift.go ├── composite.go ├── unused.go ├── dead.go ├── rangeloop.go ├── unsafeptr.go ├── cgo.go ├── httpresponse.go ├── bool.go ├── tests.go ├── method.go ├── doc.go ├── structtag.go ├── copylock.go ├── shadow.go └── deadcode.go /testdata/testingpkg/tests.go: -------------------------------------------------------------------------------- 1 | package testdata 2 | -------------------------------------------------------------------------------- /all/whitelist/plan9_386.txt: -------------------------------------------------------------------------------- 1 | // plan9/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_plan9_386.s: [386] setldt: function setldt missing Go declaration 4 | -------------------------------------------------------------------------------- /all/whitelist/android_amd64.txt: -------------------------------------------------------------------------------- 1 | // android/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration 4 | -------------------------------------------------------------------------------- /all/whitelist/netbsd_amd64.txt: -------------------------------------------------------------------------------- 1 | // netbsd/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_netbsd_amd64.s: [amd64] settls: function settls missing Go declaration 4 | -------------------------------------------------------------------------------- /all/whitelist/openbsd_amd64.txt: -------------------------------------------------------------------------------- 1 | // openbsd/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_openbsd_amd64.s: [amd64] settls: function settls missing Go declaration 4 | -------------------------------------------------------------------------------- /all/whitelist/netbsd.txt: -------------------------------------------------------------------------------- 1 | // netbsd-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] sigreturn_tramp: function sigreturn_tramp missing Go declaration 4 | -------------------------------------------------------------------------------- /all/whitelist/plan9_amd64.txt: -------------------------------------------------------------------------------- 1 | // plan9/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_plan9_amd64.s: [amd64] setldt: function setldt missing Go declaration 4 | runtime/sys_plan9_amd64.s: [amd64] settls: function settls missing Go declaration 5 | -------------------------------------------------------------------------------- /all/whitelist/plan9_arm.txt: -------------------------------------------------------------------------------- 1 | // plan9/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 4 | runtime/sys_plan9_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 5 | -------------------------------------------------------------------------------- /testdata/tagtest/file1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build testtag 6 | 7 | package main 8 | 9 | func main() { 10 | } 11 | -------------------------------------------------------------------------------- /testdata/tagtest/file2.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !testtag 6 | 7 | package main 8 | 9 | func ignore() { 10 | } 11 | -------------------------------------------------------------------------------- /all/whitelist/freebsd_arm.txt: -------------------------------------------------------------------------------- 1 | // freebsd/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 4 | runtime/sys_freebsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 5 | -------------------------------------------------------------------------------- /all/whitelist/openbsd_arm.txt: -------------------------------------------------------------------------------- 1 | // openbsd/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 4 | runtime/sys_openbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 5 | -------------------------------------------------------------------------------- /all/whitelist/darwin_amd64.txt: -------------------------------------------------------------------------------- 1 | // darwin/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration 4 | runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time 5 | -------------------------------------------------------------------------------- /all/whitelist/android_arm.txt: -------------------------------------------------------------------------------- 1 | // android/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP) 4 | runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP) 5 | runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 6 | -------------------------------------------------------------------------------- /all/whitelist/mips64x.txt: -------------------------------------------------------------------------------- 1 | // mips64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/duff_mips64x.s: [GOARCH] duffzero: function duffzero missing Go declaration 4 | runtime/tls_mips64x.s: [GOARCH] save_g: function save_g missing Go declaration 5 | runtime/tls_mips64x.s: [GOARCH] load_g: function load_g missing Go declaration 6 | -------------------------------------------------------------------------------- /all/whitelist/readme.txt: -------------------------------------------------------------------------------- 1 | This directory contains whitelists for vet complaints about the standard library and commands. 2 | They are line-based and unordered, although counts of duplicated lines matter. 3 | Each line matches vet's output, except that line numbers are removed to avoid churn. 4 | There are also os-, arch-, and bitwidth-specific whitelists. 5 | -------------------------------------------------------------------------------- /all/whitelist/linux_arm64.txt: -------------------------------------------------------------------------------- 1 | // linux/arm64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_arm64.s: [arm64] access: function access missing Go declaration 4 | runtime/sys_linux_arm64.s: [arm64] connect: function connect missing Go declaration 5 | runtime/sys_linux_arm64.s: [arm64] socket: function socket missing Go declaration 6 | -------------------------------------------------------------------------------- /all/whitelist/windows.txt: -------------------------------------------------------------------------------- 1 | // windows-specific vet whitelist. See readme.txt for details. 2 | 3 | // Issue 18609 4 | crypto/x509/root_windows.go: unreachable code 5 | 6 | runtime/sys_windows_ARCHSUFF.s: [GOARCH] sigtramp: function sigtramp missing Go declaration 7 | runtime/sys_windows_ARCHSUFF.s: [GOARCH] onosstack: unknown variable usec; offset 0 is fn+0(FP) 8 | -------------------------------------------------------------------------------- /testdata/divergent/buf.go: -------------------------------------------------------------------------------- 1 | // Test of examples with divergent packages. 2 | 3 | // Package buf ... 4 | package buf 5 | 6 | // Buf is a ... 7 | type Buf []byte 8 | 9 | // Append ... 10 | func (*Buf) Append([]byte) {} 11 | 12 | func (Buf) Reset() {} 13 | 14 | func (Buf) Len() int { return 0 } 15 | 16 | // DefaultBuf is a ... 17 | var DefaultBuf Buf 18 | -------------------------------------------------------------------------------- /all/whitelist/netbsd_arm.txt: -------------------------------------------------------------------------------- 1 | // netbsd/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 4 | runtime/sys_netbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 5 | syscall/asm_netbsd_arm.s: [arm] Syscall9: unknown variable trap; offset 0 is num+0(FP) 6 | -------------------------------------------------------------------------------- /testdata/cgo/cgo3.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Used by TestVetVerbose to test that vet -v doesn't fail because it 6 | // can't find "C". 7 | 8 | package testdata 9 | 10 | import "C" 11 | 12 | func F() { 13 | } 14 | -------------------------------------------------------------------------------- /all/whitelist/linux_ppc64x.txt: -------------------------------------------------------------------------------- 1 | // linux/ppc64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration 4 | runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration 5 | runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame 6 | -------------------------------------------------------------------------------- /testdata/cgo/cgo2.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Test the cgo checker on a file that doesn't use cgo. 6 | 7 | package testdata 8 | 9 | var _ = C.f(*p(**p)) 10 | 11 | // Passing a pointer (via the slice), but C isn't cgo. 12 | var _ = C.f([]int{3}) 13 | -------------------------------------------------------------------------------- /all/whitelist/freebsd_amd64.txt: -------------------------------------------------------------------------------- 1 | // freebsd/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_freebsd_amd64.s: [amd64] settls: function settls missing Go declaration 4 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP) 5 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP) 6 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP) 7 | -------------------------------------------------------------------------------- /all/whitelist/dragonfly_amd64.txt: -------------------------------------------------------------------------------- 1 | // dragonfly/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_dragonfly_amd64.s: [amd64] settls: function settls missing Go declaration 4 | 5 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP) 6 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP) 7 | syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP) 8 | -------------------------------------------------------------------------------- /all/whitelist/darwin_386.txt: -------------------------------------------------------------------------------- 1 | // darwin/386-specific vet whitelist. See readme.txt for details. 2 | 3 | // Ok 4 | 5 | runtime/sys_darwin_386.s: [386] now: function now missing Go declaration 6 | runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration 7 | runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration 8 | runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time 9 | -------------------------------------------------------------------------------- /all/whitelist/android_386.txt: -------------------------------------------------------------------------------- 1 | // android/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration 4 | 5 | // These SP references occur after a stack-altering call. They're fine. 6 | runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP) 7 | runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP) 8 | runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP) 9 | -------------------------------------------------------------------------------- /all/whitelist/solaris_amd64.txt: -------------------------------------------------------------------------------- 1 | // solaris/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_solaris_amd64.s: [amd64] settls: function settls missing Go declaration 4 | runtime/sys_solaris_amd64.s: [amd64] pipe1: function pipe1 missing Go declaration 5 | runtime/sys_solaris_amd64.s: [amd64] asmsysvicall6: function asmsysvicall6 missing Go declaration 6 | runtime/sys_solaris_amd64.s: [amd64] usleep2: function usleep2 missing Go declaration 7 | -------------------------------------------------------------------------------- /testdata/cgo/cgo4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Test the cgo checker on a file that doesn't use cgo, but has an 6 | // import named "C". 7 | 8 | package testdata 9 | 10 | import C "fmt" 11 | 12 | var _ = C.Println(*p(**p)) 13 | 14 | // Passing a pointer (via a slice), but C is fmt, not cgo. 15 | var _ = C.Println([]int{3}) 16 | -------------------------------------------------------------------------------- /all/whitelist/darwin_arm.txt: -------------------------------------------------------------------------------- 1 | // darwin/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | // False positives due to comments in assembly. 4 | // To be removed. See CL 27154. 5 | 6 | runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP) 7 | 8 | 9 | // Ok. 10 | 11 | runtime/sys_darwin_arm.s: [arm] bsdthread_start: function bsdthread_start missing Go declaration 12 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 13 | -------------------------------------------------------------------------------- /all/whitelist/linux_amd64.txt: -------------------------------------------------------------------------------- 1 | // linux/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration 4 | 5 | // Android-specific; stubs missing on other linux platforms. 6 | runtime/sys_linux_amd64.s: [amd64] access: function access missing Go declaration 7 | runtime/sys_linux_amd64.s: [amd64] connect: function connect missing Go declaration 8 | runtime/sys_linux_amd64.s: [amd64] socket: function socket missing Go declaration 9 | -------------------------------------------------------------------------------- /testdata/buildtag/buildtag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the buildtag checker. 6 | 7 | // +builder // ERROR "possible malformed \+build comment" 8 | // +build !ignore 9 | 10 | package testdata 11 | 12 | // +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" 13 | 14 | var _ = 3 15 | -------------------------------------------------------------------------------- /all/whitelist/mips.txt: -------------------------------------------------------------------------------- 1 | // mips-specific (big endian) vet whitelist. See readme.txt for details. 2 | 3 | // Work around if-def'd code. Will be fixed by golang.org/issue/17544. 4 | runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_lo+0(FP); expected sec_lo+4(FP) 5 | runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_hi+4(FP); expected sec_hi+0(FP) 6 | runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_lo+0(FP); expected ret_lo+4(FP) 7 | runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_hi+4(FP); expected ret_hi+0(FP) 8 | -------------------------------------------------------------------------------- /all/whitelist/mipsle.txt: -------------------------------------------------------------------------------- 1 | // mipsle-specific vet whitelist. See readme.txt for details. 2 | 3 | // Work around if-def'd code. Will be fixed by golang.org/issue/17544. 4 | runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_lo+4(FP); expected sec_lo+0(FP) 5 | runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_hi+0(FP); expected sec_hi+4(FP) 6 | runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_lo+4(FP); expected ret_lo+0(FP) 7 | runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_hi+0(FP); expected ret_hi+4(FP) 8 | -------------------------------------------------------------------------------- /testdata/asm/asm4.s: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build amd64 6 | // +build vet_test 7 | 8 | // Test cases for symbolic NOSPLIT etc. on TEXT symbols. 9 | 10 | TEXT ·noprof(SB),NOPROF,$0-8 11 | RET 12 | 13 | TEXT ·dupok(SB),DUPOK,$0-8 14 | RET 15 | 16 | TEXT ·nosplit(SB),NOSPLIT,$0 17 | RET 18 | 19 | TEXT ·rodata(SB),RODATA,$0-8 20 | RET 21 | 22 | TEXT ·noptr(SB),NOPTR|NOSPLIT,$0 23 | RET 24 | 25 | TEXT ·wrapper(SB),WRAPPER,$0-8 26 | RET 27 | -------------------------------------------------------------------------------- /testdata/method.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the canonical method checker. 6 | 7 | // This file contains the code to check canonical methods. 8 | 9 | package testdata 10 | 11 | import ( 12 | "fmt" 13 | ) 14 | 15 | type MethodTest int 16 | 17 | func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan" 18 | } 19 | 20 | type MethodTestInterface interface { 21 | ReadByte() byte // ERROR "should have signature ReadByte" 22 | } 23 | -------------------------------------------------------------------------------- /all/whitelist/darwin_arm64.txt: -------------------------------------------------------------------------------- 1 | // darwin/arm64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) 4 | runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) 5 | runtime/sys_darwin_arm64.s: [arm64] bsdthread_create: RET without writing to 4-byte ret+24(FP) 6 | runtime/sys_darwin_arm64.s: [arm64] bsdthread_start: function bsdthread_start missing Go declaration 7 | runtime/sys_darwin_arm64.s: [arm64] bsdthread_register: RET without writing to 4-byte ret+0(FP) 8 | runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration 9 | -------------------------------------------------------------------------------- /all/whitelist/nacl_arm.txt: -------------------------------------------------------------------------------- 1 | // nacl/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration 4 | runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: naclWrite is in package syscall 5 | runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: now is in package syscall 6 | runtime/sys_nacl_arm.s: [arm] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration 7 | runtime/sys_nacl_arm.s: [arm] nacl_sysinfo: function nacl_sysinfo missing Go declaration 8 | runtime/sys_nacl_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 9 | -------------------------------------------------------------------------------- /all/whitelist/linux_arm.txt: -------------------------------------------------------------------------------- 1 | // linux/arm-specific vet whitelist. See readme.txt for details. 2 | 3 | 4 | // These SP references occur after a stack-altering call. They're fine. 5 | runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP) 6 | runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP) 7 | 8 | // Special functions. 9 | runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration 10 | runtime/sys_linux_arm.s: [arm] access: function access missing Go declaration 11 | runtime/sys_linux_arm.s: [arm] connect: function connect missing Go declaration 12 | runtime/sys_linux_arm.s: [arm] socket: function socket missing Go declaration 13 | -------------------------------------------------------------------------------- /all/whitelist/mipsx.txt: -------------------------------------------------------------------------------- 1 | // mips/mipsle-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration 7 | runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration 8 | runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP) 9 | runtime/sys_linux_mipsx.s: [GOARCH] clone: 4(R29) should be flags+0(FP) 10 | runtime/sys_linux_mipsx.s: [GOARCH] clone: 8(R29) should be stk+4(FP) 11 | -------------------------------------------------------------------------------- /all/whitelist/s390x.txt: -------------------------------------------------------------------------------- 1 | internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes 2 | internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: cmpstring is in package runtime 3 | runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration 4 | runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl_xc missing Go declaration 5 | runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration 6 | runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration 7 | runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration 8 | -------------------------------------------------------------------------------- /all/whitelist/windows_amd64.txt: -------------------------------------------------------------------------------- 1 | // windows/amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_windows_amd64.s: [amd64] ctrlhandler: 16(SP) should be _type+0(FP) 4 | runtime/sys_windows_amd64.s: [amd64] ctrlhandler: RET without writing to 4-byte ret+8(FP) 5 | runtime/sys_windows_amd64.s: [amd64] callbackasm1: function callbackasm1 missing Go declaration 6 | runtime/sys_windows_amd64.s: [amd64] tstart_stdcall: RET without writing to 4-byte ret+8(FP) 7 | runtime/sys_windows_amd64.s: [amd64] settls: function settls missing Go declaration 8 | runtime/sys_windows_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time 9 | runtime/zcallback_windows.s: [amd64] callbackasm: function callbackasm missing Go declaration 10 | -------------------------------------------------------------------------------- /testdata/buildtag/buildtag_bad.go: -------------------------------------------------------------------------------- 1 | // This file contains misplaced or malformed build constraints. 2 | // The Go tool will skip it, because the constraints are invalid. 3 | // It serves only to test the tag checker during make test. 4 | 5 | // Mention +build // ERROR "possible malformed \+build comment" 6 | 7 | // +build !!bang // ERROR "invalid double negative in build constraint" 8 | // +build @#$ // ERROR "invalid non-alphanumeric build constraint" 9 | 10 | // +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" 11 | package bad 12 | 13 | // This is package 'bad' rather than 'main' so the erroneous build 14 | // tag doesn't end up looking like a package doc for the vet command 15 | // when examined by godoc. 16 | -------------------------------------------------------------------------------- /all/whitelist/linux_386.txt: -------------------------------------------------------------------------------- 1 | // linux/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration 4 | 5 | // These SP references occur after a stack-altering call. They're fine. 6 | runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP) 7 | runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP) 8 | runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP) 9 | 10 | // Android-specific; stubs missing on other linux platforms. 11 | runtime/sys_linux_386.s: [386] access: function access missing Go declaration 12 | runtime/sys_linux_386.s: [386] connect: function connect missing Go declaration 13 | runtime/sys_linux_386.s: [386] socket: function socket missing Go declaration 14 | -------------------------------------------------------------------------------- /all/whitelist/arm64.txt: -------------------------------------------------------------------------------- 1 | // arm64-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | // Intentionally missing declarations. 7 | runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration 8 | runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration 9 | runtime/duff_arm64.s: [arm64] duffcopy: function duffcopy missing Go declaration 10 | runtime/tls_arm64.s: [arm64] load_g: function load_g missing Go declaration 11 | runtime/tls_arm64.s: [arm64] save_g: function save_g missing Go declaration 12 | -------------------------------------------------------------------------------- /all/whitelist/windows_386.txt: -------------------------------------------------------------------------------- 1 | // windows/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_windows_386.s: [386] profileloop: use of 4(SP) points beyond argument frame 4 | runtime/sys_windows_386.s: [386] ctrlhandler: 4(SP) should be _type+0(FP) 5 | runtime/sys_windows_386.s: [386] setldt: function setldt missing Go declaration 6 | runtime/zcallback_windows.s: [386] callbackasm: function callbackasm missing Go declaration 7 | runtime/sys_windows_386.s: [386] callbackasm1+0: function callbackasm1+0 missing Go declaration 8 | runtime/sys_windows_386.s: [386] tstart: function tstart missing Go declaration 9 | runtime/sys_windows_386.s: [386] tstart_stdcall: RET without writing to 4-byte ret+4(FP) 10 | runtime/sys_windows_386.s: [386] cannot check cross-package assembly function: now is in package time 11 | -------------------------------------------------------------------------------- /all/whitelist/ppc64x.txt: -------------------------------------------------------------------------------- 1 | // ppc64-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration 7 | runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame 8 | runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration 9 | runtime/duff_ppc64x.s: [GOARCH] duffzero: function duffzero missing Go declaration 10 | runtime/tls_ppc64x.s: [GOARCH] save_g: function save_g missing Go declaration 11 | runtime/tls_ppc64x.s: [GOARCH] load_g: function load_g missing Go declaration 12 | -------------------------------------------------------------------------------- /testdata/unused.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the unusedresult checker. 6 | 7 | package testdata 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | ) 14 | 15 | func _() { 16 | fmt.Errorf("") // ERROR "result of fmt.Errorf call not used" 17 | _ = fmt.Errorf("") 18 | 19 | errors.New("") // ERROR "result of errors.New call not used" 20 | 21 | err := errors.New("") 22 | err.Error() // ERROR "result of \(error\).Error call not used" 23 | 24 | var buf bytes.Buffer 25 | buf.String() // ERROR "result of \(bytes.Buffer\).String call not used" 26 | 27 | fmt.Sprint("") // ERROR "result of fmt.Sprint call not used" 28 | fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used" 29 | } 30 | -------------------------------------------------------------------------------- /testdata/assign.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the useless-assignment checker. 6 | 7 | package testdata 8 | 9 | import "math/rand" 10 | 11 | type ST struct { 12 | x int 13 | l []int 14 | } 15 | 16 | func (s *ST) SetX(x int, ch chan int) { 17 | // Accidental self-assignment; it should be "s.x = x" 18 | x = x // ERROR "self-assignment of x to x" 19 | // Another mistake 20 | s.x = s.x // ERROR "self-assignment of s.x to s.x" 21 | 22 | s.l[0] = s.l[0] // ERROR "self-assignment of s.l.0. to s.l.0." 23 | 24 | // Bail on any potential side effects to avoid false positives 25 | s.l[num()] = s.l[num()] 26 | rng := rand.New(rand.NewSource(0)) 27 | s.l[rng.Intn(len(s.l))] = s.l[rng.Intn(len(s.l))] 28 | s.l[<-ch] = s.l[<-ch] 29 | } 30 | 31 | func num() int { return 2 } 32 | -------------------------------------------------------------------------------- /testdata/nilfunc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package testdata 6 | 7 | func F() {} 8 | 9 | type T struct { 10 | F func() 11 | } 12 | 13 | func (T) M() {} 14 | 15 | var Fv = F 16 | 17 | func Comparison() { 18 | var t T 19 | var fn func() 20 | if fn == nil || Fv == nil || t.F == nil { 21 | // no error; these func vars or fields may be nil 22 | } 23 | if F == nil { // ERROR "comparison of function F == nil is always false" 24 | panic("can't happen") 25 | } 26 | if t.M == nil { // ERROR "comparison of function M == nil is always false" 27 | panic("can't happen") 28 | } 29 | if F != nil { // ERROR "comparison of function F != nil is always true" 30 | if t.M != nil { // ERROR "comparison of function M != nil is always true" 31 | return 32 | } 33 | } 34 | panic("can't happen") 35 | } 36 | -------------------------------------------------------------------------------- /all/whitelist/nacl_386.txt: -------------------------------------------------------------------------------- 1 | // nacl/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: naclWrite is in package syscall 4 | runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: now is in package syscall 5 | runtime/sys_nacl_386.s: [386] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration 6 | runtime/sys_nacl_386.s: [386] setldt: function setldt missing Go declaration 7 | runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame 8 | runtime/sys_nacl_386.s: [386] sigtramp: use of 4(SP) points beyond argument frame 9 | runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt 10 | runtime/sys_nacl_386.s: [386] sigtramp: use of 8(SP) points beyond argument frame 11 | runtime/sys_nacl_386.s: [386] sigtramp: use of 12(SP) points beyond argument frame 12 | runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame 13 | runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt 14 | -------------------------------------------------------------------------------- /lib/whitelist/whitelist.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package whitelist defines exceptions for the vet tool. 6 | package whitelist 7 | 8 | // UnkeyedLiteral is a white list of types in the standard packages 9 | // that are used with unkeyed literals we deem to be acceptable. 10 | var UnkeyedLiteral = map[string]bool{ 11 | // These image and image/color struct types are frozen. We will never add fields to them. 12 | "image/color.Alpha16": true, 13 | "image/color.Alpha": true, 14 | "image/color.CMYK": true, 15 | "image/color.Gray16": true, 16 | "image/color.Gray": true, 17 | "image/color.NRGBA64": true, 18 | "image/color.NRGBA": true, 19 | "image/color.NYCbCrA": true, 20 | "image/color.RGBA64": true, 21 | "image/color.RGBA": true, 22 | "image/color.YCbCr": true, 23 | "image.Point": true, 24 | "image.Rectangle": true, 25 | "image.Uniform": true, 26 | 27 | "unicode.Range16": true, 28 | } 29 | -------------------------------------------------------------------------------- /all/whitelist/openbsd_386.txt: -------------------------------------------------------------------------------- 1 | // openbsd/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable signo 4 | runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable info 5 | runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable context 6 | runtime/sys_openbsd_386.s: [386] setldt: function setldt missing Go declaration 7 | runtime/sys_openbsd_386.s: [386] settls: function settls missing Go declaration 8 | syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) 9 | syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) 10 | syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) 11 | syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) 12 | syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) 13 | syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) 14 | syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) 15 | syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) 16 | syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) 17 | syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) 18 | -------------------------------------------------------------------------------- /golangci.go: -------------------------------------------------------------------------------- 1 | package govet 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | "strings" 7 | 8 | "golang.org/x/tools/go/loader" 9 | ) 10 | 11 | type Issue struct { 12 | Pos token.Position 13 | Message string 14 | } 15 | 16 | var foundIssues []Issue 17 | 18 | func Analyze(files []*ast.File, fset *token.FileSet, pkgInfo *loader.PackageInfo, checkShadowing bool, pg astFilePathGetter) ([]Issue, error) { 19 | foundIssues = nil 20 | *source = false // import type data for "fmt" from installed packages 21 | 22 | if checkShadowing { 23 | experimental["shadow"] = false 24 | } 25 | for name, setting := range report { 26 | if *setting == unset && !experimental[name] { 27 | *setting = setTrue 28 | } 29 | } 30 | 31 | initPrintFlags() 32 | initUnusedFlags() 33 | 34 | filesRun = true 35 | for _, f := range files { 36 | name := fset.Position(f.Pos()).Filename 37 | if !strings.HasSuffix(name, "_test.go") { 38 | includesNonTest = true 39 | } 40 | } 41 | pkg, err := doPackage(nil, pkgInfo, fset, files, pg) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | if pkg == nil { 47 | return nil, nil 48 | } 49 | 50 | return foundIssues, nil 51 | } 52 | -------------------------------------------------------------------------------- /all/whitelist/arm.txt: -------------------------------------------------------------------------------- 1 | // arm-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | // Intentionally missing declarations. 7 | runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration 8 | runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration 9 | runtime/asm_arm.s: [arm] usplitR0: function usplitR0 missing Go declaration 10 | runtime/asm_arm.s: [arm] addmoduledata: function addmoduledata missing Go declaration 11 | runtime/duff_arm.s: [arm] duffzero: function duffzero missing Go declaration 12 | runtime/duff_arm.s: [arm] duffcopy: function duffcopy missing Go declaration 13 | runtime/tls_arm.s: [arm] save_g: function save_g missing Go declaration 14 | runtime/tls_arm.s: [arm] load_g: function load_g missing Go declaration 15 | runtime/tls_arm.s: [arm] _initcgo: function _initcgo missing Go declaration 16 | 17 | runtime/internal/atomic/asm_arm.s: [arm] cas: function cas missing Go declaration 18 | -------------------------------------------------------------------------------- /all/whitelist/freebsd_386.txt: -------------------------------------------------------------------------------- 1 | // freebsd/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_freebsd_386.s: [386] thr_start: unknown variable mm 4 | runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable signo 5 | runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable info 6 | runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context 7 | runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context 8 | runtime/sys_freebsd_386.s: [386] setldt: function setldt missing Go declaration 9 | runtime/sys_freebsd_386.s: [386] i386_set_ldt: function i386_set_ldt missing Go declaration 10 | syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) 11 | syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) 12 | syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) 13 | syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) 14 | syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) 15 | syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) 16 | syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) 17 | syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) 18 | syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) 19 | syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) 20 | -------------------------------------------------------------------------------- /testdata/asm/asm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | // This file contains declarations to test the assembly in test_asm.s. 8 | 9 | package testdata 10 | 11 | type S struct { 12 | i int32 13 | b bool 14 | s string 15 | } 16 | 17 | func arg1(x int8, y uint8) 18 | func arg2(x int16, y uint16) 19 | func arg4(x int32, y uint32) 20 | func arg8(x int64, y uint64) 21 | func argint(x int, y uint) 22 | func argptr(x *byte, y *byte, c chan int, m map[int]int, f func()) 23 | func argstring(x, y string) 24 | func argslice(x, y []string) 25 | func argiface(x interface{}, y interface { 26 | m() 27 | }) 28 | func argcomplex(x complex64, y complex128) 29 | func argstruct(x S, y struct{}) 30 | func argarray(x [2]S) 31 | func returnint() int 32 | func returnbyte(x int) byte 33 | func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte) 34 | func returnintmissing() int 35 | func leaf(x, y int) int 36 | 37 | func noprof(x int) 38 | func dupok(x int) 39 | func nosplit(x int) 40 | func rodata(x int) 41 | func noptr(x int) 42 | func wrapper(x int) 43 | 44 | func f15271() (x uint32) 45 | func f17584(x float32, y complex64) 46 | 47 | func noframe1(x int32) 48 | func noframe2(x int32) 49 | -------------------------------------------------------------------------------- /testdata/incomplete/examples_test.go: -------------------------------------------------------------------------------- 1 | // Test of examples. 2 | 3 | package testdata 4 | 5 | func Example() {} // OK because is package-level. 6 | 7 | func Example_suffix() // OK because refers to suffix annotation. 8 | 9 | func Example_BadSuffix() // OK because non-test package was excluded. No false positives wanted. 10 | 11 | func ExampleBuf() // OK because non-test package was excluded. No false positives wanted. 12 | 13 | func ExampleBuf_Append() {} // OK because non-test package was excluded. No false positives wanted. 14 | 15 | func ExampleBuf_Clear() {} // OK because non-test package was excluded. No false positives wanted. 16 | 17 | func ExampleBuf_suffix() {} // OK because refers to suffix annotation. 18 | 19 | func ExampleBuf_Append_Bad() {} // OK because non-test package was excluded. No false positives wanted. 20 | 21 | func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. 22 | 23 | func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" 24 | 25 | func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" 26 | 27 | // "Puffer" is German for "Buffer". 28 | 29 | func ExamplePuffer() // OK because non-test package was excluded. No false positives wanted. 30 | 31 | func ExamplePuffer_Append() // OK because non-test package was excluded. No false positives wanted. 32 | 33 | func ExamplePuffer_suffix() // OK because non-test package was excluded. No false positives wanted. 34 | -------------------------------------------------------------------------------- /all/whitelist/amd64.txt: -------------------------------------------------------------------------------- 1 | // amd64-specific vet whitelist. See readme.txt for details. 2 | 3 | // False positives. 4 | 5 | // Nothing much to do about cross-package assembly. Unfortunate. 6 | internal/bytealg/compare_amd64.s: [amd64] cannot check cross-package assembly function: Compare is in package bytes 7 | internal/bytealg/compare_amd64.s: [amd64] cannot check cross-package assembly function: cmpstring is in package runtime 8 | 9 | // reflect trampolines intentionally omit arg size. Same for morestack. 10 | runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame 11 | runtime/asm_amd64.s: [amd64] morestack: use of 16(SP) points beyond argument frame 12 | runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame 13 | 14 | // Intentionally missing declarations. These are special assembly routines. 15 | // Some are jumped into from other routines, with values in specific registers. 16 | // duff* have direct calls from the compiler. 17 | // Others use the platform ABI. 18 | // There is no sensible corresponding Go prototype. 19 | runtime/asm_amd64.s: [amd64] aeshashbody: function aeshashbody missing Go declaration 20 | runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go declaration 21 | runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration 22 | runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration 23 | runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration 24 | -------------------------------------------------------------------------------- /testdata/divergent/buf_test.go: -------------------------------------------------------------------------------- 1 | // Test of examples with divergent packages. 2 | 3 | package buf_test 4 | 5 | func Example() {} // OK because is package-level. 6 | 7 | func Example_suffix() {} // OK because refers to suffix annotation. 8 | 9 | func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" 10 | 11 | func ExampleBuf() {} // OK because refers to known top-level type. 12 | 13 | func ExampleBuf_Append() {} // OK because refers to known method. 14 | 15 | func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear" 16 | 17 | func ExampleBuf_suffix() {} // OK because refers to suffix annotation. 18 | 19 | func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad" 20 | 21 | func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. 22 | 23 | func ExampleDefaultBuf() {} // OK because refers to top-level identifier. 24 | 25 | func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" 26 | 27 | func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" 28 | 29 | // "Puffer" is German for "Buffer". 30 | 31 | func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer" 32 | 33 | func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" 34 | 35 | func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" 36 | -------------------------------------------------------------------------------- /assign.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | This file contains the code to check for useless assignments. 7 | */ 8 | 9 | package govet 10 | 11 | import ( 12 | "go/ast" 13 | "go/token" 14 | "reflect" 15 | ) 16 | 17 | func init() { 18 | register("assign", 19 | "check for useless assignments", 20 | checkAssignStmt, 21 | assignStmt) 22 | } 23 | 24 | // TODO: should also check for assignments to struct fields inside methods 25 | // that are on T instead of *T. 26 | 27 | // checkAssignStmt checks for assignments of the form " = ". 28 | // These are almost always useless, and even when they aren't they are usually a mistake. 29 | func checkAssignStmt(f *File, node ast.Node) { 30 | stmt := node.(*ast.AssignStmt) 31 | if stmt.Tok != token.ASSIGN { 32 | return // ignore := 33 | } 34 | if len(stmt.Lhs) != len(stmt.Rhs) { 35 | // If LHS and RHS have different cardinality, they can't be the same. 36 | return 37 | } 38 | for i, lhs := range stmt.Lhs { 39 | rhs := stmt.Rhs[i] 40 | if hasSideEffects(f, lhs) || hasSideEffects(f, rhs) { 41 | continue // expressions may not be equal 42 | } 43 | if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { 44 | continue // short-circuit the heavy-weight gofmt check 45 | } 46 | le := f.gofmt(lhs) 47 | re := f.gofmt(rhs) 48 | if le == re { 49 | f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /all/whitelist/netbsd_386.txt: -------------------------------------------------------------------------------- 1 | // netbsd/386-specific vet whitelist. See readme.txt for details. 2 | 3 | runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] settls: function settls missing Go declaration 4 | 5 | runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 140(SP) points beyond argument frame 6 | runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame 7 | runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame 8 | runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable signo 9 | runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable info 10 | runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable context 11 | runtime/sys_netbsd_386.s: [386] setldt: function setldt missing Go declaration 12 | runtime/sys_netbsd_386.s: [386] setldt: use of 16(SP) points beyond argument frame 13 | 14 | syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) 15 | syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) 16 | syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) 17 | syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) 18 | syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) 19 | syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) 20 | syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) 21 | syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) 22 | syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) 23 | syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /all/whitelist/386.txt: -------------------------------------------------------------------------------- 1 | // 386-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_386.s: [386] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_386.s: [386] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | // startup code uses non-standard calling convention and intentionally 7 | // omits args. 8 | runtime/asm_386.s: [386] rt0_go: use of 4(SP) points beyond argument frame 9 | 10 | // reflect trampolines intentionally omit arg size. Same for morestack. 11 | runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame 12 | runtime/asm_386.s: [386] morestack: use of 8(SP) points beyond argument frame 13 | runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame 14 | 15 | // Intentionally missing declarations. These are special assembly routines. 16 | runtime/asm_386.s: [386] ldt0setup: function ldt0setup missing Go declaration 17 | runtime/asm_386.s: [386] emptyfunc: function emptyfunc missing Go declaration 18 | runtime/asm_386.s: [386] aeshashbody: function aeshashbody missing Go declaration 19 | runtime/asm_386.s: [386] addmoduledata: function addmoduledata missing Go declaration 20 | runtime/duff_386.s: [386] duffzero: function duffzero missing Go declaration 21 | runtime/duff_386.s: [386] duffcopy: function duffcopy missing Go declaration 22 | 23 | runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go declaration 24 | runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration 25 | 26 | runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration 27 | -------------------------------------------------------------------------------- /nilfunc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | This file contains the code to check for useless function comparisons. 7 | A useless comparison is one like f == nil as opposed to f() == nil. 8 | */ 9 | 10 | package govet 11 | 12 | import ( 13 | "go/ast" 14 | "go/token" 15 | "go/types" 16 | ) 17 | 18 | func init() { 19 | register("nilfunc", 20 | "check for comparisons between functions and nil", 21 | checkNilFuncComparison, 22 | binaryExpr) 23 | } 24 | 25 | func checkNilFuncComparison(f *File, node ast.Node) { 26 | e := node.(*ast.BinaryExpr) 27 | 28 | // Only want == or != comparisons. 29 | if e.Op != token.EQL && e.Op != token.NEQ { 30 | return 31 | } 32 | 33 | // Only want comparisons with a nil identifier on one side. 34 | var e2 ast.Expr 35 | switch { 36 | case f.isNil(e.X): 37 | e2 = e.Y 38 | case f.isNil(e.Y): 39 | e2 = e.X 40 | default: 41 | return 42 | } 43 | 44 | // Only want identifiers or selector expressions. 45 | var obj types.Object 46 | switch v := e2.(type) { 47 | case *ast.Ident: 48 | obj = f.pkg.uses[v] 49 | case *ast.SelectorExpr: 50 | obj = f.pkg.uses[v.Sel] 51 | default: 52 | return 53 | } 54 | 55 | // Only want functions. 56 | if _, ok := obj.(*types.Func); !ok { 57 | return 58 | } 59 | 60 | f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ) 61 | } 62 | 63 | // isNil reports whether the provided expression is the built-in nil 64 | // identifier. 65 | func (f *File) isNil(e ast.Expr) bool { 66 | return f.pkg.types[e].Type == types.Typ[types.UntypedNil] 67 | } 68 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Vet is a tool that checks correctness of Go programs. It runs a suite of tests, 2 | each tailored to check for a particular class of errors. Examples include incorrect 3 | Printf format verbs and malformed build tags. 4 | 5 | Over time many checks have been added to vet's suite, but many more have been 6 | rejected as not appropriate for the tool. The criteria applied when selecting which 7 | checks to add are: 8 | 9 | Correctness: 10 | 11 | Vet's checks are about correctness, not style. A vet check must identify real or 12 | potential bugs that could cause incorrect compilation or execution. A check that 13 | only identifies stylistic points or alternative correct approaches to a situation 14 | is not acceptable. 15 | 16 | Frequency: 17 | 18 | Vet is run every day by many programmers, often as part of every compilation or 19 | submission. The cost in execution time is considerable, especially in aggregate, 20 | so checks must be likely enough to find real problems that they are worth the 21 | overhead of the added check. A new check that finds only a handful of problems 22 | across all existing programs, even if the problem is significant, is not worth 23 | adding to the suite everyone runs daily. 24 | 25 | Precision: 26 | 27 | Most of vet's checks are heuristic and can generate both false positives (flagging 28 | correct programs) and false negatives (not flagging incorrect ones). The rate of 29 | both these failures must be very small. A check that is too noisy will be ignored 30 | by the programmer overwhelmed by the output; a check that misses too many of the 31 | cases it's looking for will give a false sense of security. Neither is acceptable. 32 | A vet check must be accurate enough that everything it reports is worth examining, 33 | and complete enough to encourage real confidence. 34 | -------------------------------------------------------------------------------- /testdata/copylock_range.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the copylock checker's 6 | // range statement analysis. 7 | 8 | package testdata 9 | 10 | import "sync" 11 | 12 | func rangeMutex() { 13 | var mu sync.Mutex 14 | var i int 15 | 16 | var s []sync.Mutex 17 | for range s { 18 | } 19 | for i = range s { 20 | } 21 | for i := range s { 22 | } 23 | for i, _ = range s { 24 | } 25 | for i, _ := range s { 26 | } 27 | for _, mu = range s { // ERROR "range var mu copies lock: sync.Mutex" 28 | } 29 | for _, m := range s { // ERROR "range var m copies lock: sync.Mutex" 30 | } 31 | for i, mu = range s { // ERROR "range var mu copies lock: sync.Mutex" 32 | } 33 | for i, m := range s { // ERROR "range var m copies lock: sync.Mutex" 34 | } 35 | 36 | var a [3]sync.Mutex 37 | for _, m := range a { // ERROR "range var m copies lock: sync.Mutex" 38 | } 39 | 40 | var m map[sync.Mutex]sync.Mutex 41 | for k := range m { // ERROR "range var k copies lock: sync.Mutex" 42 | } 43 | for mu, _ = range m { // ERROR "range var mu copies lock: sync.Mutex" 44 | } 45 | for k, _ := range m { // ERROR "range var k copies lock: sync.Mutex" 46 | } 47 | for _, mu = range m { // ERROR "range var mu copies lock: sync.Mutex" 48 | } 49 | for _, v := range m { // ERROR "range var v copies lock: sync.Mutex" 50 | } 51 | 52 | var c chan sync.Mutex 53 | for range c { 54 | } 55 | for mu = range c { // ERROR "range var mu copies lock: sync.Mutex" 56 | } 57 | for v := range c { // ERROR "range var v copies lock: sync.Mutex" 58 | } 59 | 60 | // Test non-idents in range variables 61 | var t struct { 62 | i int 63 | mu sync.Mutex 64 | } 65 | for t.i, t.mu = range s { // ERROR "range var t.mu copies lock: sync.Mutex" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /testdata/shadow.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the shadowed variable checker. 6 | // Some of these errors are caught by the compiler (shadowed return parameters for example) 7 | // but are nonetheless useful tests. 8 | 9 | package testdata 10 | 11 | import "os" 12 | 13 | func ShadowRead(f *os.File, buf []byte) (err error) { 14 | var x int 15 | if f != nil { 16 | err := 3 // OK - different type. 17 | _ = err 18 | } 19 | if f != nil { 20 | _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" 21 | if err != nil { 22 | return err 23 | } 24 | i := 3 // OK 25 | _ = i 26 | } 27 | if f != nil { 28 | x := one() // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" 29 | var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" 30 | if x == 1 && err != nil { 31 | return err 32 | } 33 | } 34 | for i := 0; i < 10; i++ { 35 | i := i // OK: obviously intentional idiomatic redeclaration 36 | go func() { 37 | println(i) 38 | }() 39 | } 40 | var shadowTemp interface{} 41 | switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration 42 | case int: 43 | println("OK") 44 | _ = shadowTemp 45 | } 46 | if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration 47 | var f *os.File // OK because f is not mentioned later in the function. 48 | // The declaration of x is a shadow because x is mentioned below. 49 | var x int // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" 50 | _, _, _ = x, f, shadowTemp 51 | } 52 | // Use a couple of variables to trigger shadowing errors. 53 | _, _ = err, x 54 | return 55 | } 56 | 57 | func one() int { 58 | return 1 59 | } 60 | -------------------------------------------------------------------------------- /all/whitelist/nacl_amd64p32.txt: -------------------------------------------------------------------------------- 1 | // nacl/amd64p32-specific vet whitelist. See readme.txt for details. 2 | 3 | internal/bytealg/compare_amd64p32.s: [amd64p32] cannot check cross-package assembly function: Compare is in package bytes 4 | internal/bytealg/compare_amd64p32.s: [amd64p32] cannot check cross-package assembly function: cmpstring is in package runtime 5 | 6 | // reflect trampolines intentionally omit arg size. Same for morestack. 7 | runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame 8 | runtime/asm_amd64p32.s: [amd64p32] morestack: use of 16(SP) points beyond argument frame 9 | runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame 10 | 11 | runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt 12 | runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt 13 | runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt 14 | runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt 15 | runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt 16 | runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_sysinfo: function nacl_sysinfo missing Go declaration 17 | runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: naclWrite is in package syscall 18 | runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: now is in package syscall 19 | runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration 20 | runtime/sys_nacl_amd64p32.s: [amd64p32] settls: function settls missing Go declaration 21 | 22 | // Clearer using FP than SP, but that requires named offsets. 23 | runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argc 24 | runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv 25 | 26 | runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP) 27 | 28 | runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration 29 | -------------------------------------------------------------------------------- /testdata/cgo/cgo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the cgo checker. 6 | 7 | package testdata 8 | 9 | // void f(void *); 10 | import "C" 11 | 12 | import "unsafe" 13 | 14 | func CgoTests() { 15 | var c chan bool 16 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer" 17 | C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer" 18 | 19 | var m map[string]string 20 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer" 21 | C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer" 22 | 23 | var f func() 24 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer" 25 | C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer" 26 | 27 | var s []int 28 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer" 29 | C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer" 30 | 31 | var a [1][]int 32 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer" 33 | C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer" 34 | 35 | var st struct{ f []int } 36 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer" 37 | C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer" 38 | 39 | // The following cases are OK. 40 | var i int 41 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i))) 42 | C.f(unsafe.Pointer(&i)) 43 | 44 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0]))) 45 | C.f(unsafe.Pointer(&s[0])) 46 | 47 | var a2 [1]int 48 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2))) 49 | C.f(unsafe.Pointer(&a2)) 50 | 51 | var st2 struct{ i int } 52 | C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2))) 53 | C.f(unsafe.Pointer(&st2)) 54 | 55 | type cgoStruct struct{ p *cgoStruct } 56 | C.f(unsafe.Pointer(&cgoStruct{})) 57 | 58 | C.CBytes([]byte("hello")) 59 | } 60 | -------------------------------------------------------------------------------- /testdata/httpresponse.go: -------------------------------------------------------------------------------- 1 | package testdata 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | ) 7 | 8 | func goodHTTPGet() { 9 | res, err := http.Get("http://foo.com") 10 | if err != nil { 11 | log.Fatal(err) 12 | } 13 | defer res.Body.Close() 14 | } 15 | 16 | func badHTTPGet() { 17 | res, err := http.Get("http://foo.com") 18 | defer res.Body.Close() // ERROR "using res before checking for errors" 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | } 23 | 24 | func badHTTPHead() { 25 | res, err := http.Head("http://foo.com") 26 | defer res.Body.Close() // ERROR "using res before checking for errors" 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | } 31 | 32 | func goodClientGet() { 33 | client := http.DefaultClient 34 | res, err := client.Get("http://foo.com") 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | defer res.Body.Close() 39 | } 40 | 41 | func badClientPtrGet() { 42 | client := http.DefaultClient 43 | resp, err := client.Get("http://foo.com") 44 | defer resp.Body.Close() // ERROR "using resp before checking for errors" 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | } 49 | 50 | func badClientGet() { 51 | client := http.Client{} 52 | resp, err := client.Get("http://foo.com") 53 | defer resp.Body.Close() // ERROR "using resp before checking for errors" 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | 59 | func badClientPtrDo() { 60 | client := http.DefaultClient 61 | req, err := http.NewRequest("GET", "http://foo.com", nil) 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | 66 | resp, err := client.Do(req) 67 | defer resp.Body.Close() // ERROR "using resp before checking for errors" 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | } 72 | 73 | func badClientDo() { 74 | var client http.Client 75 | req, err := http.NewRequest("GET", "http://foo.com", nil) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | 80 | resp, err := client.Do(req) 81 | defer resp.Body.Close() // ERROR "using resp before checking for errors" 82 | if err != nil { 83 | log.Fatal(err) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /atomic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package govet 6 | 7 | import ( 8 | "go/ast" 9 | "go/token" 10 | "go/types" 11 | ) 12 | 13 | func init() { 14 | register("atomic", 15 | "check for common mistaken usages of the sync/atomic package", 16 | checkAtomicAssignment, 17 | assignStmt) 18 | } 19 | 20 | // checkAtomicAssignment walks the assignment statement checking for common 21 | // mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1) 22 | func checkAtomicAssignment(f *File, node ast.Node) { 23 | n := node.(*ast.AssignStmt) 24 | if len(n.Lhs) != len(n.Rhs) { 25 | return 26 | } 27 | if len(n.Lhs) == 1 && n.Tok == token.DEFINE { 28 | return 29 | } 30 | 31 | for i, right := range n.Rhs { 32 | call, ok := right.(*ast.CallExpr) 33 | if !ok { 34 | continue 35 | } 36 | sel, ok := call.Fun.(*ast.SelectorExpr) 37 | if !ok { 38 | continue 39 | } 40 | pkgIdent, _ := sel.X.(*ast.Ident) 41 | pkgName, ok := f.pkg.uses[pkgIdent].(*types.PkgName) 42 | if !ok || pkgName.Imported().Path() != "sync/atomic" { 43 | continue 44 | } 45 | 46 | switch sel.Sel.Name { 47 | case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr": 48 | f.checkAtomicAddAssignment(n.Lhs[i], call) 49 | } 50 | } 51 | } 52 | 53 | // checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value 54 | // to the same variable being used in the operation 55 | func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) { 56 | if len(call.Args) != 2 { 57 | return 58 | } 59 | arg := call.Args[0] 60 | broken := false 61 | 62 | if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND { 63 | broken = f.gofmt(left) == f.gofmt(uarg.X) 64 | } else if star, ok := left.(*ast.StarExpr); ok { 65 | broken = f.gofmt(star.X) == f.gofmt(arg) 66 | } 67 | 68 | if broken { 69 | f.Bad(left.Pos(), "direct assignment to atomic value") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /testdata/unsafeptr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package testdata 6 | 7 | import ( 8 | "reflect" 9 | "unsafe" 10 | ) 11 | 12 | func f() { 13 | var x unsafe.Pointer 14 | var y uintptr 15 | x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer" 16 | y = uintptr(x) 17 | 18 | // only allowed pointer arithmetic is ptr +/-/&^ num. 19 | // num+ptr is technically okay but still flagged: write ptr+num instead. 20 | x = unsafe.Pointer(uintptr(x) + 1) 21 | x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" 22 | x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" 23 | x = unsafe.Pointer(uintptr(x) - 1) 24 | x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" 25 | x = unsafe.Pointer(uintptr(x) &^ 3) 26 | x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" 27 | 28 | // certain uses of reflect are okay 29 | var v reflect.Value 30 | x = unsafe.Pointer(v.Pointer()) 31 | x = unsafe.Pointer(v.UnsafeAddr()) 32 | var s1 *reflect.StringHeader 33 | x = unsafe.Pointer(s1.Data) 34 | var s2 *reflect.SliceHeader 35 | x = unsafe.Pointer(s2.Data) 36 | var s3 reflect.StringHeader 37 | x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer" 38 | var s4 reflect.SliceHeader 39 | x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer" 40 | 41 | // but only in reflect 42 | var vv V 43 | x = unsafe.Pointer(vv.Pointer()) // ERROR "possible misuse of unsafe.Pointer" 44 | x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer" 45 | var ss1 *StringHeader 46 | x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer" 47 | var ss2 *SliceHeader 48 | x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer" 49 | 50 | } 51 | 52 | type V interface { 53 | Pointer() uintptr 54 | UnsafeAddr() uintptr 55 | } 56 | 57 | type StringHeader struct { 58 | Data uintptr 59 | } 60 | 61 | type SliceHeader struct { 62 | Data uintptr 63 | } 64 | -------------------------------------------------------------------------------- /testdata/atomic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the atomic checker. 6 | 7 | package testdata 8 | 9 | import ( 10 | "sync/atomic" 11 | ) 12 | 13 | type Counter uint64 14 | 15 | func AtomicTests() { 16 | x := uint64(1) 17 | x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value" 18 | _, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value" 19 | x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" 20 | 21 | y := &x 22 | *y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value" 23 | 24 | var su struct{ Counter uint64 } 25 | su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value" 26 | z1 := atomic.AddUint64(&su.Counter, 1) 27 | _ = z1 // Avoid err "z declared and not used" 28 | 29 | var sp struct{ Counter *uint64 } 30 | *sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value" 31 | z2 := atomic.AddUint64(sp.Counter, 1) 32 | _ = z2 // Avoid err "z declared and not used" 33 | 34 | au := []uint64{10, 20} 35 | au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value" 36 | au[1] = atomic.AddUint64(&au[0], 1) 37 | 38 | ap := []*uint64{&au[0], &au[1]} 39 | *ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value" 40 | *ap[1] = atomic.AddUint64(ap[0], 1) 41 | 42 | x = atomic.AddUint64() // Used to make vet crash; now silently ignored. 43 | 44 | { 45 | // A variable declaration creates a new variable in the current scope. 46 | x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16" 47 | 48 | // Re-declaration assigns a new value. 49 | x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" 50 | _ = w 51 | } 52 | } 53 | 54 | type T struct{} 55 | 56 | func (T) AddUint64(addr *uint64, delta uint64) uint64 { return 0 } 57 | 58 | func NonAtomic() { 59 | x := uint64(1) 60 | var atomic T 61 | x = atomic.AddUint64(&x, 1) // ok; not the imported pkg 62 | } 63 | -------------------------------------------------------------------------------- /testdata/rangeloop.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the rangeloop checker. 6 | 7 | package testdata 8 | 9 | func RangeLoopTests() { 10 | var s []int 11 | for i, v := range s { 12 | go func() { 13 | println(i) // ERROR "loop variable i captured by func literal" 14 | println(v) // ERROR "loop variable v captured by func literal" 15 | }() 16 | } 17 | for i, v := range s { 18 | defer func() { 19 | println(i) // ERROR "loop variable i captured by func literal" 20 | println(v) // ERROR "loop variable v captured by func literal" 21 | }() 22 | } 23 | for i := range s { 24 | go func() { 25 | println(i) // ERROR "loop variable i captured by func literal" 26 | }() 27 | } 28 | for _, v := range s { 29 | go func() { 30 | println(v) // ERROR "loop variable v captured by func literal" 31 | }() 32 | } 33 | for i, v := range s { 34 | go func() { 35 | println(i, v) 36 | }() 37 | println("unfortunately, we don't catch the error above because of this statement") 38 | } 39 | for i, v := range s { 40 | go func(i, v int) { 41 | println(i, v) 42 | }(i, v) 43 | } 44 | for i, v := range s { 45 | i, v := i, v 46 | go func() { 47 | println(i, v) 48 | }() 49 | } 50 | // If the key of the range statement is not an identifier 51 | // the code should not panic (it used to). 52 | var x [2]int 53 | var f int 54 | for x[0], f = range s { 55 | go func() { 56 | _ = f // ERROR "loop variable f captured by func literal" 57 | }() 58 | } 59 | type T struct { 60 | v int 61 | } 62 | for _, v := range s { 63 | go func() { 64 | _ = T{v: 1} 65 | _ = []int{v: 1} // ERROR "loop variable v captured by func literal" 66 | }() 67 | } 68 | 69 | // ordinary for-loops 70 | for i := 0; i < 10; i++ { 71 | go func() { 72 | print(i) // ERROR "loop variable i captured by func literal" 73 | }() 74 | } 75 | for i, j := 0, 1; i < 100; i, j = j, i+j { 76 | go func() { 77 | print(j) // ERROR "loop variable j captured by func literal" 78 | }() 79 | } 80 | type cons struct { 81 | car int 82 | cdr *cons 83 | } 84 | var head *cons 85 | for p := head; p != nil; p = p.next { 86 | go func() { 87 | print(p.car) // ERROR "loop variable p captured by func literal" 88 | }() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /shift.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | This file contains the code to check for suspicious shifts. 7 | */ 8 | 9 | package govet 10 | 11 | import ( 12 | "go/ast" 13 | "go/constant" 14 | "go/token" 15 | "go/types" 16 | ) 17 | 18 | func init() { 19 | register("shift", 20 | "check for useless shifts", 21 | checkShift, 22 | binaryExpr, assignStmt) 23 | } 24 | 25 | func checkShift(f *File, node ast.Node) { 26 | if f.dead[node] { 27 | // Skip shift checks on unreachable nodes. 28 | return 29 | } 30 | 31 | switch node := node.(type) { 32 | case *ast.BinaryExpr: 33 | if node.Op == token.SHL || node.Op == token.SHR { 34 | checkLongShift(f, node, node.X, node.Y) 35 | } 36 | case *ast.AssignStmt: 37 | if len(node.Lhs) != 1 || len(node.Rhs) != 1 { 38 | return 39 | } 40 | if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN { 41 | checkLongShift(f, node, node.Lhs[0], node.Rhs[0]) 42 | } 43 | } 44 | } 45 | 46 | // checkLongShift checks if shift or shift-assign operations shift by more than 47 | // the length of the underlying variable. 48 | func checkLongShift(f *File, node ast.Node, x, y ast.Expr) { 49 | if f.pkg.types[x].Value != nil { 50 | // Ignore shifts of constants. 51 | // These are frequently used for bit-twiddling tricks 52 | // like ^uint(0) >> 63 for 32/64 bit detection and compatibility. 53 | return 54 | } 55 | 56 | v := f.pkg.types[y].Value 57 | if v == nil { 58 | return 59 | } 60 | amt, ok := constant.Int64Val(v) 61 | if !ok { 62 | return 63 | } 64 | t := f.pkg.types[x].Type 65 | if t == nil { 66 | return 67 | } 68 | b, ok := t.Underlying().(*types.Basic) 69 | if !ok { 70 | return 71 | } 72 | var size int64 73 | switch b.Kind() { 74 | case types.Uint8, types.Int8: 75 | size = 8 76 | case types.Uint16, types.Int16: 77 | size = 16 78 | case types.Uint32, types.Int32: 79 | size = 32 80 | case types.Uint64, types.Int64: 81 | size = 64 82 | case types.Int, types.Uint: 83 | size = uintBitSize 84 | case types.Uintptr: 85 | size = uintptrBitSize 86 | default: 87 | return 88 | } 89 | if amt >= size { 90 | ident := f.gofmt(x) 91 | f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt) 92 | } 93 | } 94 | 95 | var ( 96 | uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint]) 97 | uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr]) 98 | ) 99 | -------------------------------------------------------------------------------- /composite.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the test for unkeyed struct literals. 6 | 7 | package govet 8 | 9 | import ( 10 | "flag" 11 | "go/ast" 12 | "go/types" 13 | "strings" 14 | 15 | "github.com/golangci/govet/lib/whitelist" 16 | ) 17 | 18 | var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only") 19 | 20 | func init() { 21 | register("composites", 22 | "check that composite literals used field-keyed elements", 23 | checkUnkeyedLiteral, 24 | compositeLit) 25 | } 26 | 27 | // checkUnkeyedLiteral checks if a composite literal is a struct literal with 28 | // unkeyed fields. 29 | func checkUnkeyedLiteral(f *File, node ast.Node) { 30 | if strings.HasSuffix(f.name, "_test.go") { 31 | return 32 | } 33 | 34 | cl := node.(*ast.CompositeLit) 35 | 36 | typ := f.pkg.types[cl].Type 37 | if typ == nil { 38 | // cannot determine composite literals' type, skip it 39 | return 40 | } 41 | typeName := typ.String() 42 | if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] { 43 | // skip whitelisted types 44 | return 45 | } 46 | under := typ.Underlying() 47 | for { 48 | ptr, ok := under.(*types.Pointer) 49 | if !ok { 50 | break 51 | } 52 | under = ptr.Elem().Underlying() 53 | } 54 | if _, ok := under.(*types.Struct); !ok { 55 | // skip non-struct composite literals 56 | return 57 | } 58 | if isLocalType(f, typ) { 59 | // allow unkeyed locally defined composite literal 60 | return 61 | } 62 | 63 | // check if the CompositeLit contains an unkeyed field 64 | allKeyValue := true 65 | for _, e := range cl.Elts { 66 | if _, ok := e.(*ast.KeyValueExpr); !ok { 67 | allKeyValue = false 68 | break 69 | } 70 | } 71 | if allKeyValue { 72 | // all the composite literal fields are keyed 73 | return 74 | } 75 | 76 | f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", 77 | types.TypeString(typ, func(pkg *types.Package) string { 78 | return pkg.Name() 79 | })) 80 | } 81 | 82 | func isLocalType(f *File, typ types.Type) bool { 83 | switch x := typ.(type) { 84 | case *types.Struct: 85 | // struct literals are local types 86 | return true 87 | case *types.Pointer: 88 | return isLocalType(f, x.Elem()) 89 | case *types.Named: 90 | // names in package foo are local to foo_test too 91 | return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.typesPkg.Path(), "_test") 92 | } 93 | return false 94 | } 95 | -------------------------------------------------------------------------------- /testdata/testingpkg/tests_test.go: -------------------------------------------------------------------------------- 1 | package testdata 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // Buf is a ... 8 | type Buf []byte 9 | 10 | // Append ... 11 | func (*Buf) Append([]byte) {} 12 | 13 | func (Buf) Reset() {} 14 | 15 | func (Buf) Len() int { return 0 } 16 | 17 | // DefaultBuf is a ... 18 | var DefaultBuf Buf 19 | 20 | func Example() {} // OK because is package-level. 21 | 22 | func Example_goodSuffix() // OK because refers to suffix annotation. 23 | 24 | func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" 25 | 26 | func ExampleBuf() // OK because refers to known top-level type. 27 | 28 | func ExampleBuf_Append() {} // OK because refers to known method. 29 | 30 | func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear" 31 | 32 | func ExampleBuf_suffix() {} // OK because refers to suffix annotation. 33 | 34 | func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad" 35 | 36 | func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. 37 | 38 | func ExampleDefaultBuf() {} // OK because refers to top-level identifier. 39 | 40 | func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" 41 | 42 | func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" 43 | 44 | // "Puffer" is German for "Buffer". 45 | 46 | func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer" 47 | 48 | func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" 49 | 50 | func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" 51 | 52 | func nonTest() {} // OK because it doesn't start with "Test". 53 | 54 | func (Buf) TesthasReceiver() {} // OK because it has a receiver. 55 | 56 | func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase. 57 | 58 | func TestÜnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase. 59 | 60 | func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase" 61 | 62 | func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase" 63 | 64 | func Test(*testing.T) {} // OK "Test" on its own is considered a test. 65 | 66 | func Testify() {} // OK because it takes no parameters. 67 | 68 | func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters. 69 | 70 | func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names. 71 | 72 | func TestnoTParam(string) {} // OK because it doesn't take a *testing.T 73 | 74 | func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase" 75 | -------------------------------------------------------------------------------- /unused.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file defines the check for unused results of calls to certain 6 | // pure functions. 7 | 8 | package govet 9 | 10 | import ( 11 | "flag" 12 | "go/ast" 13 | "go/token" 14 | "go/types" 15 | "strings" 16 | ) 17 | 18 | var unusedFuncsFlag = flag.String("unusedfuncs", 19 | "errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse", 20 | "comma-separated list of functions whose results must be used") 21 | 22 | var unusedStringMethodsFlag = flag.String("unusedstringmethods", 23 | "Error,String", 24 | "comma-separated list of names of methods of type func() string whose results must be used") 25 | 26 | func init() { 27 | register("unusedresult", 28 | "check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list", 29 | checkUnusedResult, 30 | exprStmt) 31 | } 32 | 33 | // func() string 34 | var sigNoArgsStringResult = types.NewSignature(nil, nil, 35 | types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])), 36 | false) 37 | 38 | var unusedFuncs = make(map[string]bool) 39 | var unusedStringMethods = make(map[string]bool) 40 | 41 | func initUnusedFlags() { 42 | commaSplit := func(s string, m map[string]bool) { 43 | if s != "" { 44 | for _, name := range strings.Split(s, ",") { 45 | if len(name) == 0 { 46 | flag.Usage() 47 | } 48 | m[name] = true 49 | } 50 | } 51 | } 52 | commaSplit(*unusedFuncsFlag, unusedFuncs) 53 | commaSplit(*unusedStringMethodsFlag, unusedStringMethods) 54 | } 55 | 56 | func checkUnusedResult(f *File, n ast.Node) { 57 | call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) 58 | if !ok { 59 | return // not a call statement 60 | } 61 | fun := unparen(call.Fun) 62 | 63 | if f.pkg.types[fun].IsType() { 64 | return // a conversion, not a call 65 | } 66 | 67 | selector, ok := fun.(*ast.SelectorExpr) 68 | if !ok { 69 | return // neither a method call nor a qualified ident 70 | } 71 | 72 | sel, ok := f.pkg.selectors[selector] 73 | if ok && sel.Kind() == types.MethodVal { 74 | // method (e.g. foo.String()) 75 | obj := sel.Obj().(*types.Func) 76 | sig := sel.Type().(*types.Signature) 77 | if types.Identical(sig, sigNoArgsStringResult) { 78 | if unusedStringMethods[obj.Name()] { 79 | f.Badf(call.Lparen, "result of (%s).%s call not used", 80 | sig.Recv().Type(), obj.Name()) 81 | } 82 | } 83 | } else if !ok { 84 | // package-qualified function (e.g. fmt.Errorf) 85 | obj := f.pkg.uses[selector.Sel] 86 | if obj, ok := obj.(*types.Func); ok { 87 | qname := obj.Pkg().Path() + "." + obj.Name() 88 | if unusedFuncs[qname] { 89 | f.Badf(call.Lparen, "result of %v call not used", qname) 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /dead.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // 5 | // Simplified dead code detector. Used for skipping certain checks 6 | // on unreachable code (for instance, shift checks on arch-specific code). 7 | 8 | package govet 9 | 10 | import ( 11 | "go/ast" 12 | "go/constant" 13 | ) 14 | 15 | // updateDead puts unreachable "if" and "case" nodes into f.dead. 16 | func (f *File) updateDead(node ast.Node) { 17 | if f.dead[node] { 18 | // The node is already marked as dead. 19 | return 20 | } 21 | 22 | switch stmt := node.(type) { 23 | case *ast.IfStmt: 24 | // "if" branch is dead if its condition evaluates 25 | // to constant false. 26 | v := f.pkg.types[stmt.Cond].Value 27 | if v == nil { 28 | return 29 | } 30 | if !constant.BoolVal(v) { 31 | f.setDead(stmt.Body) 32 | return 33 | } 34 | f.setDead(stmt.Else) 35 | case *ast.SwitchStmt: 36 | // Case clause with empty switch tag is dead if it evaluates 37 | // to constant false. 38 | if stmt.Tag == nil { 39 | BodyLoopBool: 40 | for _, stmt := range stmt.Body.List { 41 | cc := stmt.(*ast.CaseClause) 42 | if cc.List == nil { 43 | // Skip default case. 44 | continue 45 | } 46 | for _, expr := range cc.List { 47 | v := f.pkg.types[expr].Value 48 | if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) { 49 | continue BodyLoopBool 50 | } 51 | } 52 | f.setDead(cc) 53 | } 54 | return 55 | } 56 | 57 | // Case clause is dead if its constant value doesn't match 58 | // the constant value from the switch tag. 59 | // TODO: This handles integer comparisons only. 60 | v := f.pkg.types[stmt.Tag].Value 61 | if v == nil || v.Kind() != constant.Int { 62 | return 63 | } 64 | tagN, ok := constant.Uint64Val(v) 65 | if !ok { 66 | return 67 | } 68 | BodyLoopInt: 69 | for _, x := range stmt.Body.List { 70 | cc := x.(*ast.CaseClause) 71 | if cc.List == nil { 72 | // Skip default case. 73 | continue 74 | } 75 | for _, expr := range cc.List { 76 | v := f.pkg.types[expr].Value 77 | if v == nil { 78 | continue BodyLoopInt 79 | } 80 | n, ok := constant.Uint64Val(v) 81 | if !ok || tagN == n { 82 | continue BodyLoopInt 83 | } 84 | } 85 | f.setDead(cc) 86 | } 87 | } 88 | } 89 | 90 | // setDead marks the node and all the children as dead. 91 | func (f *File) setDead(node ast.Node) { 92 | dv := deadVisitor{ 93 | f: f, 94 | } 95 | ast.Walk(dv, node) 96 | } 97 | 98 | type deadVisitor struct { 99 | f *File 100 | } 101 | 102 | func (dv deadVisitor) Visit(node ast.Node) ast.Visitor { 103 | if node == nil { 104 | return nil 105 | } 106 | dv.f.dead[node] = true 107 | return dv 108 | } 109 | -------------------------------------------------------------------------------- /rangeloop.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | This file contains the code to check range loop variables bound inside function 7 | literals that are deferred or launched in new goroutines. We only check 8 | instances where the defer or go statement is the last statement in the loop 9 | body, as otherwise we would need whole program analysis. 10 | 11 | For example: 12 | 13 | for i, v := range s { 14 | go func() { 15 | println(i, v) // not what you might expect 16 | }() 17 | } 18 | 19 | See: https://golang.org/doc/go_faq.html#closures_and_goroutines 20 | */ 21 | 22 | package govet 23 | 24 | import "go/ast" 25 | 26 | func init() { 27 | register("rangeloops", 28 | "check that loop variables are used correctly", 29 | checkLoop, 30 | rangeStmt, forStmt) 31 | } 32 | 33 | // checkLoop walks the body of the provided loop statement, checking whether 34 | // its index or value variables are used unsafely inside goroutines or deferred 35 | // function literals. 36 | func checkLoop(f *File, node ast.Node) { 37 | // Find the variables updated by the loop statement. 38 | var vars []*ast.Ident 39 | addVar := func(expr ast.Expr) { 40 | if id, ok := expr.(*ast.Ident); ok { 41 | vars = append(vars, id) 42 | } 43 | } 44 | var body *ast.BlockStmt 45 | switch n := node.(type) { 46 | case *ast.RangeStmt: 47 | body = n.Body 48 | addVar(n.Key) 49 | addVar(n.Value) 50 | case *ast.ForStmt: 51 | body = n.Body 52 | switch post := n.Post.(type) { 53 | case *ast.AssignStmt: 54 | // e.g. for p = head; p != nil; p = p.next 55 | for _, lhs := range post.Lhs { 56 | addVar(lhs) 57 | } 58 | case *ast.IncDecStmt: 59 | // e.g. for i := 0; i < n; i++ 60 | addVar(post.X) 61 | } 62 | } 63 | if vars == nil { 64 | return 65 | } 66 | 67 | // Inspect a go or defer statement 68 | // if it's the last one in the loop body. 69 | // (We give up if there are following statements, 70 | // because it's hard to prove go isn't followed by wait, 71 | // or defer by return.) 72 | if len(body.List) == 0 { 73 | return 74 | } 75 | var last *ast.CallExpr 76 | switch s := body.List[len(body.List)-1].(type) { 77 | case *ast.GoStmt: 78 | last = s.Call 79 | case *ast.DeferStmt: 80 | last = s.Call 81 | default: 82 | return 83 | } 84 | lit, ok := last.Fun.(*ast.FuncLit) 85 | if !ok { 86 | return 87 | } 88 | ast.Inspect(lit.Body, func(n ast.Node) bool { 89 | id, ok := n.(*ast.Ident) 90 | if !ok || id.Obj == nil { 91 | return true 92 | } 93 | if f.pkg.types[id].Type == nil { 94 | // Not referring to a variable (e.g. struct field name) 95 | return true 96 | } 97 | for _, v := range vars { 98 | if v.Obj == id.Obj { 99 | f.Badf(id.Pos(), "loop variable %s captured by func literal", 100 | id.Name) 101 | } 102 | } 103 | return true 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /testdata/composite.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the test for untagged struct literals. 6 | 7 | package testdata 8 | 9 | import ( 10 | "flag" 11 | "go/scanner" 12 | "image" 13 | "unicode" 14 | 15 | "path/to/unknownpkg" 16 | ) 17 | 18 | var Okay1 = []string{ 19 | "Name", 20 | "Usage", 21 | "DefValue", 22 | } 23 | 24 | var Okay2 = map[string]bool{ 25 | "Name": true, 26 | "Usage": true, 27 | "DefValue": true, 28 | } 29 | 30 | var Okay3 = struct { 31 | X string 32 | Y string 33 | Z string 34 | }{ 35 | "Name", 36 | "Usage", 37 | "DefValue", 38 | } 39 | 40 | var Okay4 = []struct { 41 | A int 42 | B int 43 | }{ 44 | {1, 2}, 45 | {3, 4}, 46 | } 47 | 48 | type MyStruct struct { 49 | X string 50 | Y string 51 | Z string 52 | } 53 | 54 | var Okay5 = &MyStruct{ 55 | "Name", 56 | "Usage", 57 | "DefValue", 58 | } 59 | 60 | var Okay6 = []MyStruct{ 61 | {"foo", "bar", "baz"}, 62 | {"aa", "bb", "cc"}, 63 | } 64 | 65 | var Okay7 = []*MyStruct{ 66 | {"foo", "bar", "baz"}, 67 | {"aa", "bb", "cc"}, 68 | } 69 | 70 | // Testing is awkward because we need to reference things from a separate package 71 | // to trigger the warnings. 72 | 73 | var goodStructLiteral = flag.Flag{ 74 | Name: "Name", 75 | Usage: "Usage", 76 | } 77 | var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields" 78 | "Name", 79 | "Usage", 80 | nil, // Value 81 | "DefValue", 82 | } 83 | 84 | // SpecialCase is a named slice of CaseRange to test issue 9171. 85 | var goodNamedSliceLiteral = unicode.SpecialCase{ 86 | {Lo: 1, Hi: 2}, 87 | unicode.CaseRange{Lo: 1, Hi: 2}, 88 | } 89 | var badNamedSliceLiteral = unicode.SpecialCase{ 90 | {1, 2}, // ERROR "unkeyed fields" 91 | unicode.CaseRange{1, 2}, // ERROR "unkeyed fields" 92 | } 93 | 94 | // ErrorList is a named slice, so no warnings should be emitted. 95 | var goodScannerErrorList = scanner.ErrorList{ 96 | &scanner.Error{Msg: "foobar"}, 97 | } 98 | var badScannerErrorList = scanner.ErrorList{ 99 | &scanner.Error{"foobar"}, // ERROR "unkeyed fields" 100 | } 101 | 102 | // Check whitelisted structs: if vet is run with --compositewhitelist=false, 103 | // this line triggers an error. 104 | var whitelistedPoint = image.Point{1, 2} 105 | 106 | // Do not check type from unknown package. 107 | // See issue 15408. 108 | var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"} 109 | 110 | // A named pointer slice of CaseRange to test issue 23539. In 111 | // particular, we're interested in how some slice elements omit their 112 | // type. 113 | var goodNamedPointerSliceLiteral = []*unicode.CaseRange{ 114 | {Lo: 1, Hi: 2}, 115 | &unicode.CaseRange{Lo: 1, Hi: 2}, 116 | } 117 | var badNamedPointerSliceLiteral = []*unicode.CaseRange{ 118 | {1, 2}, // ERROR "unkeyed fields" 119 | &unicode.CaseRange{1, 2}, // ERROR "unkeyed fields" 120 | } 121 | -------------------------------------------------------------------------------- /unsafeptr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Check for invalid uintptr -> unsafe.Pointer conversions. 6 | 7 | package govet 8 | 9 | import ( 10 | "go/ast" 11 | "go/token" 12 | "go/types" 13 | ) 14 | 15 | func init() { 16 | register("unsafeptr", 17 | "check for misuse of unsafe.Pointer", 18 | checkUnsafePointer, 19 | callExpr) 20 | } 21 | 22 | func checkUnsafePointer(f *File, node ast.Node) { 23 | x := node.(*ast.CallExpr) 24 | if len(x.Args) != 1 { 25 | return 26 | } 27 | if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) { 28 | f.Badf(x.Pos(), "possible misuse of unsafe.Pointer") 29 | } 30 | } 31 | 32 | // isSafeUintptr reports whether x - already known to be a uintptr - 33 | // is safe to convert to unsafe.Pointer. It is safe if x is itself derived 34 | // directly from an unsafe.Pointer via conversion and pointer arithmetic 35 | // or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr 36 | // or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader. 37 | func (f *File) isSafeUintptr(x ast.Expr) bool { 38 | switch x := x.(type) { 39 | case *ast.ParenExpr: 40 | return f.isSafeUintptr(x.X) 41 | 42 | case *ast.SelectorExpr: 43 | switch x.Sel.Name { 44 | case "Data": 45 | // reflect.SliceHeader and reflect.StringHeader are okay, 46 | // but only if they are pointing at a real slice or string. 47 | // It's not okay to do: 48 | // var x SliceHeader 49 | // x.Data = uintptr(unsafe.Pointer(...)) 50 | // ... use x ... 51 | // p := unsafe.Pointer(x.Data) 52 | // because in the middle the garbage collector doesn't 53 | // see x.Data as a pointer and so x.Data may be dangling 54 | // by the time we get to the conversion at the end. 55 | // For now approximate by saying that *Header is okay 56 | // but Header is not. 57 | pt, ok := f.pkg.types[x.X].Type.(*types.Pointer) 58 | if ok { 59 | t, ok := pt.Elem().(*types.Named) 60 | if ok && t.Obj().Pkg().Path() == "reflect" { 61 | switch t.Obj().Name() { 62 | case "StringHeader", "SliceHeader": 63 | return true 64 | } 65 | } 66 | } 67 | } 68 | 69 | case *ast.CallExpr: 70 | switch len(x.Args) { 71 | case 0: 72 | // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr. 73 | sel, ok := x.Fun.(*ast.SelectorExpr) 74 | if !ok { 75 | break 76 | } 77 | switch sel.Sel.Name { 78 | case "Pointer", "UnsafeAddr": 79 | t, ok := f.pkg.types[sel.X].Type.(*types.Named) 80 | if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" { 81 | return true 82 | } 83 | } 84 | 85 | case 1: 86 | // maybe conversion of uintptr to unsafe.Pointer 87 | return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer) 88 | } 89 | 90 | case *ast.BinaryExpr: 91 | switch x.Op { 92 | case token.ADD, token.SUB, token.AND_NOT: 93 | return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y) 94 | } 95 | } 96 | return false 97 | } 98 | -------------------------------------------------------------------------------- /lib/cfg/cfg_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cfg 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "go/ast" 11 | "go/parser" 12 | "go/token" 13 | "testing" 14 | ) 15 | 16 | const src = `package main 17 | 18 | import "log" 19 | 20 | func f1() { 21 | live() 22 | return 23 | dead() 24 | } 25 | 26 | func f2() { 27 | for { 28 | live() 29 | } 30 | dead() 31 | } 32 | 33 | func f3() { 34 | if true { // even known values are ignored 35 | return 36 | } 37 | for true { // even known values are ignored 38 | live() 39 | } 40 | for { 41 | live() 42 | } 43 | dead() 44 | } 45 | 46 | func f4(x int) { 47 | switch x { 48 | case 1: 49 | live() 50 | fallthrough 51 | case 2: 52 | live() 53 | log.Fatal() 54 | default: 55 | panic("oops") 56 | } 57 | dead() 58 | } 59 | 60 | func f4(ch chan int) { 61 | select { 62 | case <-ch: 63 | live() 64 | return 65 | default: 66 | live() 67 | panic("oops") 68 | } 69 | dead() 70 | } 71 | 72 | func f5(unknown bool) { 73 | for { 74 | if unknown { 75 | break 76 | } 77 | continue 78 | dead() 79 | } 80 | live() 81 | } 82 | 83 | func f6(unknown bool) { 84 | outer: 85 | for { 86 | for { 87 | break outer 88 | dead() 89 | } 90 | dead() 91 | } 92 | live() 93 | } 94 | 95 | func f7() { 96 | for { 97 | break nosuchlabel 98 | dead() 99 | } 100 | dead() 101 | } 102 | 103 | func f8() { 104 | select{} 105 | dead() 106 | } 107 | 108 | func f9(ch chan int) { 109 | select { 110 | case <-ch: 111 | return 112 | } 113 | dead() 114 | } 115 | 116 | func f10(ch chan int) { 117 | select { 118 | case <-ch: 119 | return 120 | dead() 121 | default: 122 | } 123 | live() 124 | } 125 | 126 | func f11() { 127 | goto; // mustn't crash 128 | dead() 129 | } 130 | 131 | ` 132 | 133 | func TestDeadCode(t *testing.T) { 134 | // We'll use dead code detection to verify the CFG. 135 | 136 | fset := token.NewFileSet() 137 | f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0)) 138 | if err != nil { 139 | t.Fatal(err) 140 | } 141 | for _, decl := range f.Decls { 142 | if decl, ok := decl.(*ast.FuncDecl); ok { 143 | g := New(decl.Body, mayReturn) 144 | 145 | // Mark blocks reachable from entry. 146 | live := make(map[*Block]bool) 147 | var visit func(*Block) 148 | visit = func(b *Block) { 149 | if !live[b] { 150 | live[b] = true 151 | for _, succ := range b.Succs { 152 | visit(succ) 153 | } 154 | } 155 | } 156 | visit(g.Blocks[0]) 157 | 158 | // Print statements in unreachable blocks 159 | // (in order determined by builder). 160 | var buf bytes.Buffer 161 | for _, b := range g.Blocks { 162 | if !live[b] { 163 | for _, n := range b.Nodes { 164 | fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n)) 165 | } 166 | } 167 | } 168 | 169 | // Check that the result contains "dead" at least once but not "live". 170 | if !bytes.Contains(buf.Bytes(), []byte("dead")) || 171 | bytes.Contains(buf.Bytes(), []byte("live")) { 172 | t.Errorf("unexpected dead statements in function %s:\n%s", 173 | decl.Name.Name, 174 | &buf) 175 | t.Logf("control flow graph:\n%s", g.Format(fset)) 176 | } 177 | } 178 | } 179 | } 180 | 181 | // A trivial mayReturn predicate that looks only at syntax, not types. 182 | func mayReturn(call *ast.CallExpr) bool { 183 | switch fun := call.Fun.(type) { 184 | case *ast.Ident: 185 | return fun.Name != "panic" 186 | case *ast.SelectorExpr: 187 | return fun.Sel.Name != "Fatal" 188 | } 189 | return true 190 | } 191 | -------------------------------------------------------------------------------- /cgo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Check for invalid cgo pointer passing. 6 | // This looks for code that uses cgo to call C code passing values 7 | // whose types are almost always invalid according to the cgo pointer 8 | // sharing rules. 9 | // Specifically, it warns about attempts to pass a Go chan, map, func, 10 | // or slice to C, either directly, or via a pointer, array, or struct. 11 | 12 | package govet 13 | 14 | import ( 15 | "go/ast" 16 | "go/token" 17 | "go/types" 18 | ) 19 | 20 | func init() { 21 | register("cgocall", 22 | "check for types that may not be passed to cgo calls", 23 | checkCgoCall, 24 | callExpr) 25 | } 26 | 27 | func checkCgoCall(f *File, node ast.Node) { 28 | x := node.(*ast.CallExpr) 29 | 30 | // We are only looking for calls to functions imported from 31 | // the "C" package. 32 | sel, ok := x.Fun.(*ast.SelectorExpr) 33 | if !ok { 34 | return 35 | } 36 | id, ok := sel.X.(*ast.Ident) 37 | if !ok { 38 | return 39 | } 40 | 41 | pkgname, ok := f.pkg.uses[id].(*types.PkgName) 42 | if !ok || pkgname.Imported().Path() != "C" { 43 | return 44 | } 45 | 46 | // A call to C.CBytes passes a pointer but is always safe. 47 | if sel.Sel.Name == "CBytes" { 48 | return 49 | } 50 | 51 | for _, arg := range x.Args { 52 | if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) { 53 | f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") 54 | } 55 | 56 | // Check for passing the address of a bad type. 57 | if conv, ok := arg.(*ast.CallExpr); ok && len(conv.Args) == 1 && f.hasBasicType(conv.Fun, types.UnsafePointer) { 58 | arg = conv.Args[0] 59 | } 60 | if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND { 61 | if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) { 62 | f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") 63 | } 64 | } 65 | } 66 | } 67 | 68 | // cgoBaseType tries to look through type conversions involving 69 | // unsafe.Pointer to find the real type. It converts: 70 | // unsafe.Pointer(x) => x 71 | // *(*unsafe.Pointer)(unsafe.Pointer(&x)) => x 72 | func cgoBaseType(f *File, arg ast.Expr) types.Type { 73 | switch arg := arg.(type) { 74 | case *ast.CallExpr: 75 | if len(arg.Args) == 1 && f.hasBasicType(arg.Fun, types.UnsafePointer) { 76 | return cgoBaseType(f, arg.Args[0]) 77 | } 78 | case *ast.StarExpr: 79 | call, ok := arg.X.(*ast.CallExpr) 80 | if !ok || len(call.Args) != 1 { 81 | break 82 | } 83 | // Here arg is *f(v). 84 | t := f.pkg.types[call.Fun].Type 85 | if t == nil { 86 | break 87 | } 88 | ptr, ok := t.Underlying().(*types.Pointer) 89 | if !ok { 90 | break 91 | } 92 | // Here arg is *(*p)(v) 93 | elem, ok := ptr.Elem().Underlying().(*types.Basic) 94 | if !ok || elem.Kind() != types.UnsafePointer { 95 | break 96 | } 97 | // Here arg is *(*unsafe.Pointer)(v) 98 | call, ok = call.Args[0].(*ast.CallExpr) 99 | if !ok || len(call.Args) != 1 { 100 | break 101 | } 102 | // Here arg is *(*unsafe.Pointer)(f(v)) 103 | if !f.hasBasicType(call.Fun, types.UnsafePointer) { 104 | break 105 | } 106 | // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(v)) 107 | u, ok := call.Args[0].(*ast.UnaryExpr) 108 | if !ok || u.Op != token.AND { 109 | break 110 | } 111 | // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(&v)) 112 | return cgoBaseType(f, u.X) 113 | } 114 | 115 | return f.pkg.types[arg].Type 116 | } 117 | 118 | // typeOKForCgoCall reports whether the type of arg is OK to pass to a 119 | // C function using cgo. This is not true for Go types with embedded 120 | // pointers. m is used to avoid infinite recursion on recursive types. 121 | func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool { 122 | if t == nil || m[t] { 123 | return true 124 | } 125 | m[t] = true 126 | switch t := t.Underlying().(type) { 127 | case *types.Chan, *types.Map, *types.Signature, *types.Slice: 128 | return false 129 | case *types.Pointer: 130 | return typeOKForCgoCall(t.Elem(), m) 131 | case *types.Array: 132 | return typeOKForCgoCall(t.Elem(), m) 133 | case *types.Struct: 134 | for i := 0; i < t.NumFields(); i++ { 135 | if !typeOKForCgoCall(t.Field(i).Type(), m) { 136 | return false 137 | } 138 | } 139 | } 140 | return true 141 | } 142 | -------------------------------------------------------------------------------- /httpresponse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the check for http.Response values being used before 6 | // checking for errors. 7 | 8 | package govet 9 | 10 | import ( 11 | "go/ast" 12 | "go/types" 13 | ) 14 | 15 | func init() { 16 | register("httpresponse", 17 | "check errors are checked before using an http Response", 18 | checkHTTPResponse, callExpr) 19 | } 20 | 21 | func checkHTTPResponse(f *File, node ast.Node) { 22 | call := node.(*ast.CallExpr) 23 | if !isHTTPFuncOrMethodOnClient(f, call) { 24 | return // the function call is not related to this check. 25 | } 26 | 27 | finder := &blockStmtFinder{node: call} 28 | ast.Walk(finder, f.file) 29 | stmts := finder.stmts() 30 | if len(stmts) < 2 { 31 | return // the call to the http function is the last statement of the block. 32 | } 33 | 34 | asg, ok := stmts[0].(*ast.AssignStmt) 35 | if !ok { 36 | return // the first statement is not assignment. 37 | } 38 | resp := rootIdent(asg.Lhs[0]) 39 | if resp == nil { 40 | return // could not find the http.Response in the assignment. 41 | } 42 | 43 | def, ok := stmts[1].(*ast.DeferStmt) 44 | if !ok { 45 | return // the following statement is not a defer. 46 | } 47 | root := rootIdent(def.Call.Fun) 48 | if root == nil { 49 | return // could not find the receiver of the defer call. 50 | } 51 | 52 | if resp.Obj == root.Obj { 53 | f.Badf(root.Pos(), "using %s before checking for errors", resp.Name) 54 | } 55 | } 56 | 57 | // isHTTPFuncOrMethodOnClient checks whether the given call expression is on 58 | // either a function of the net/http package or a method of http.Client that 59 | // returns (*http.Response, error). 60 | func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool { 61 | fun, _ := expr.Fun.(*ast.SelectorExpr) 62 | sig, _ := f.pkg.types[fun].Type.(*types.Signature) 63 | if sig == nil { 64 | return false // the call is not on of the form x.f() 65 | } 66 | 67 | res := sig.Results() 68 | if res.Len() != 2 { 69 | return false // the function called does not return two values. 70 | } 71 | if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") { 72 | return false // the first return type is not *http.Response. 73 | } 74 | if !types.Identical(res.At(1).Type().Underlying(), errorType) { 75 | return false // the second return type is not error 76 | } 77 | 78 | typ := f.pkg.types[fun.X].Type 79 | if typ == nil { 80 | id, ok := fun.X.(*ast.Ident) 81 | return ok && id.Name == "http" // function in net/http package. 82 | } 83 | 84 | if isNamedType(typ, "net/http", "Client") { 85 | return true // method on http.Client. 86 | } 87 | ptr, ok := typ.(*types.Pointer) 88 | return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. 89 | } 90 | 91 | // blockStmtFinder is an ast.Visitor that given any ast node can find the 92 | // statement containing it and its succeeding statements in the same block. 93 | type blockStmtFinder struct { 94 | node ast.Node // target of search 95 | stmt ast.Stmt // innermost statement enclosing argument to Visit 96 | block *ast.BlockStmt // innermost block enclosing argument to Visit. 97 | } 98 | 99 | // Visit finds f.node performing a search down the ast tree. 100 | // It keeps the last block statement and statement seen for later use. 101 | func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor { 102 | if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() { 103 | return nil // not here 104 | } 105 | switch n := node.(type) { 106 | case *ast.BlockStmt: 107 | f.block = n 108 | case ast.Stmt: 109 | f.stmt = n 110 | } 111 | if f.node.Pos() == node.Pos() && f.node.End() == node.End() { 112 | return nil // found 113 | } 114 | return f // keep looking 115 | } 116 | 117 | // stmts returns the statements of f.block starting from the one including f.node. 118 | func (f *blockStmtFinder) stmts() []ast.Stmt { 119 | for i, v := range f.block.List { 120 | if f.stmt == v { 121 | return f.block.List[i:] 122 | } 123 | } 124 | return nil 125 | } 126 | 127 | // rootIdent finds the root identifier x in a chain of selections x.y.z, or nil if not found. 128 | func rootIdent(n ast.Node) *ast.Ident { 129 | switch n := n.(type) { 130 | case *ast.SelectorExpr: 131 | return rootIdent(n.X) 132 | case *ast.Ident: 133 | return n 134 | default: 135 | return nil 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /testdata/lostcancel.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package testdata 6 | 7 | import ( 8 | "context" 9 | "log" 10 | "os" 11 | "testing" 12 | ) 13 | 14 | // Check the three functions and assignment forms (var, :=, =) we look for. 15 | // (Do these early: line numbers are fragile.) 16 | func _() { 17 | var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)" 18 | } // ERROR "this return statement may be reached without using the cancel var defined on line 17" 19 | 20 | func _() { 21 | ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..." 22 | } // ERROR "may be reached without using the cancel2 var defined on line 21" 23 | 24 | func _() { 25 | var ctx context.Context 26 | var cancel3 func() 27 | ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..." 28 | } // ERROR "this return statement may be reached without using the cancel3 var defined on line 27" 29 | 30 | func _() { 31 | ctx, _ := context.WithCancel() // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak" 32 | ctx, _ = context.WithTimeout() // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak" 33 | ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak" 34 | } 35 | 36 | func _() { 37 | ctx, cancel := context.WithCancel() 38 | defer cancel() // ok 39 | } 40 | 41 | func _() { 42 | ctx, cancel := context.WithCancel() // ERROR "not used on all paths" 43 | if condition { 44 | cancel() 45 | } 46 | return // ERROR "this return statement may be reached without using the cancel var" 47 | } 48 | 49 | func _() { 50 | ctx, cancel := context.WithCancel() 51 | if condition { 52 | cancel() 53 | } else { 54 | // ok: infinite loop 55 | for { 56 | print(0) 57 | } 58 | } 59 | } 60 | 61 | func _() { 62 | ctx, cancel := context.WithCancel() // ERROR "not used on all paths" 63 | if condition { 64 | cancel() 65 | } else { 66 | for i := 0; i < 10; i++ { 67 | print(0) 68 | } 69 | } 70 | } // ERROR "this return statement may be reached without using the cancel var" 71 | 72 | func _() { 73 | ctx, cancel := context.WithCancel() 74 | // ok: used on all paths 75 | switch someInt { 76 | case 0: 77 | new(testing.T).FailNow() 78 | case 1: 79 | log.Fatal() 80 | case 2: 81 | cancel() 82 | case 3: 83 | print("hi") 84 | fallthrough 85 | default: 86 | os.Exit(1) 87 | } 88 | } 89 | 90 | func _() { 91 | ctx, cancel := context.WithCancel() // ERROR "not used on all paths" 92 | switch someInt { 93 | case 0: 94 | new(testing.T).FailNow() 95 | case 1: 96 | log.Fatal() 97 | case 2: 98 | cancel() 99 | case 3: 100 | print("hi") // falls through to implicit return 101 | default: 102 | os.Exit(1) 103 | } 104 | } // ERROR "this return statement may be reached without using the cancel var" 105 | 106 | func _(ch chan int) int { 107 | ctx, cancel := context.WithCancel() // ERROR "not used on all paths" 108 | select { 109 | case <-ch: 110 | new(testing.T).FailNow() 111 | case y <- ch: 112 | print("hi") // falls through to implicit return 113 | case ch <- 1: 114 | cancel() 115 | default: 116 | os.Exit(1) 117 | } 118 | } // ERROR "this return statement may be reached without using the cancel var" 119 | 120 | func _(ch chan int) int { 121 | ctx, cancel := context.WithCancel() 122 | // A blocking select must execute one of its cases. 123 | select { 124 | case <-ch: 125 | panic() 126 | } 127 | } 128 | 129 | func _() { 130 | go func() { 131 | ctx, cancel := context.WithCancel() // ERROR "not used on all paths" 132 | print(ctx) 133 | }() // ERROR "may be reached without using the cancel var" 134 | } 135 | 136 | var condition bool 137 | var someInt int 138 | 139 | // Regression test for Go issue 16143. 140 | func _() { 141 | var x struct{ f func() } 142 | x.f() 143 | } 144 | 145 | // Regression test for Go issue 16230. 146 | func _() (ctx context.Context, cancel func()) { 147 | ctx, cancel = context.WithCancel() 148 | return // a naked return counts as a load of the named result values 149 | } 150 | 151 | // Same as above, but for literal function. 152 | var _ = func() (ctx context.Context, cancel func()) { 153 | ctx, cancel = context.WithCancel() 154 | return 155 | } 156 | -------------------------------------------------------------------------------- /testdata/copylock_func.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the copylock checker's 6 | // function declaration analysis. 7 | 8 | package testdata 9 | 10 | import "sync" 11 | 12 | func OkFunc(*sync.Mutex) {} 13 | func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex" 14 | func BadFunc2(sync.Map) {} // ERROR "BadFunc2 passes lock by value: sync.Map contains sync.Mutex" 15 | func OkRet() *sync.Mutex {} 16 | func BadRet() sync.Mutex {} // Don't warn about results 17 | 18 | var ( 19 | OkClosure = func(*sync.Mutex) {} 20 | BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex" 21 | BadClosure2 = func(sync.Map) {} // ERROR "func passes lock by value: sync.Map contains sync.Mutex" 22 | ) 23 | 24 | type EmbeddedRWMutex struct { 25 | sync.RWMutex 26 | } 27 | 28 | func (*EmbeddedRWMutex) OkMeth() {} 29 | func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex" 30 | func OkFunc(e *EmbeddedRWMutex) {} 31 | func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex" 32 | func OkRet() *EmbeddedRWMutex {} 33 | func BadRet() EmbeddedRWMutex {} // Don't warn about results 34 | 35 | type FieldMutex struct { 36 | s sync.Mutex 37 | } 38 | 39 | func (*FieldMutex) OkMeth() {} 40 | func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex" 41 | func OkFunc(*FieldMutex) {} 42 | func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex" 43 | 44 | type L0 struct { 45 | L1 46 | } 47 | 48 | type L1 struct { 49 | l L2 50 | } 51 | 52 | type L2 struct { 53 | sync.Mutex 54 | } 55 | 56 | func (*L0) Ok() {} 57 | func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2" 58 | 59 | type EmbeddedMutexPointer struct { 60 | s *sync.Mutex // safe to copy this pointer 61 | } 62 | 63 | func (*EmbeddedMutexPointer) Ok() {} 64 | func (EmbeddedMutexPointer) AlsoOk() {} 65 | func StillOk(EmbeddedMutexPointer) {} 66 | func LookinGood() EmbeddedMutexPointer {} 67 | 68 | type EmbeddedLocker struct { 69 | sync.Locker // safe to copy interface values 70 | } 71 | 72 | func (*EmbeddedLocker) Ok() {} 73 | func (EmbeddedLocker) AlsoOk() {} 74 | 75 | type CustomLock struct{} 76 | 77 | func (*CustomLock) Lock() {} 78 | func (*CustomLock) Unlock() {} 79 | 80 | func Ok(*CustomLock) {} 81 | func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock" 82 | 83 | // Passing lock values into interface function arguments 84 | func FuncCallInterfaceArg(f func(a int, b interface{})) { 85 | var m sync.Mutex 86 | var t struct{ lock sync.Mutex } 87 | 88 | f(1, "foo") 89 | f(2, &t) 90 | f(3, &sync.Mutex{}) 91 | f(4, m) // ERROR "call of f copies lock value: sync.Mutex" 92 | f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex" 93 | var fntab []func(t) 94 | fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex" 95 | } 96 | 97 | // Returning lock via interface value 98 | func ReturnViaInterface(x int) (int, interface{}) { 99 | var m sync.Mutex 100 | var t struct{ lock sync.Mutex } 101 | 102 | switch x % 4 { 103 | case 0: 104 | return 0, "qwe" 105 | case 1: 106 | return 1, &sync.Mutex{} 107 | case 2: 108 | return 2, m // ERROR "return copies lock value: sync.Mutex" 109 | default: 110 | return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex" 111 | } 112 | } 113 | 114 | // Some cases that we don't warn about. 115 | 116 | func AcceptedCases() { 117 | x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227) 118 | x = BadRet() // function call on RHS is OK (#16227) 119 | x = *OKRet() // indirection of function call on RHS is OK (#16227) 120 | } 121 | 122 | // TODO: Unfortunate cases 123 | 124 | // Non-ideal error message: 125 | // Since we're looking for Lock methods, sync.Once's underlying 126 | // sync.Mutex gets called out, but without any reference to the sync.Once. 127 | type LocalOnce sync.Once 128 | 129 | func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex" 130 | 131 | // False negative: 132 | // LocalMutex doesn't have a Lock method. 133 | // Nevertheless, it is probably a bad idea to pass it by value. 134 | type LocalMutex sync.Mutex 135 | 136 | func (LocalMutex) Bad() {} // WANTED: An error here :( 137 | -------------------------------------------------------------------------------- /lib/cfg/cfg.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This package constructs a simple control-flow graph (CFG) of the 6 | // statements and expressions within a single function. 7 | // 8 | // Use cfg.New to construct the CFG for a function body. 9 | // 10 | // The blocks of the CFG contain all the function's non-control 11 | // statements. The CFG does not contain control statements such as If, 12 | // Switch, Select, and Branch, but does contain their subexpressions. 13 | // For example, this source code: 14 | // 15 | // if x := f(); x != nil { 16 | // T() 17 | // } else { 18 | // F() 19 | // } 20 | // 21 | // produces this CFG: 22 | // 23 | // 1: x := f() 24 | // x != nil 25 | // succs: 2, 3 26 | // 2: T() 27 | // succs: 4 28 | // 3: F() 29 | // succs: 4 30 | // 4: 31 | // 32 | // The CFG does contain Return statements; even implicit returns are 33 | // materialized (at the position of the function's closing brace). 34 | // 35 | // The CFG does not record conditions associated with conditional branch 36 | // edges, nor the short-circuit semantics of the && and || operators, 37 | // nor abnormal control flow caused by panic. If you need this 38 | // information, use golang.org/x/tools/go/ssa instead. 39 | // 40 | package cfg 41 | 42 | // Although the vet tool has type information, it is often extremely 43 | // fragmentary, so for simplicity this package does not depend on 44 | // go/types. Consequently control-flow conditions are ignored even 45 | // when constant, and "mayReturn" information must be provided by the 46 | // client. 47 | import ( 48 | "bytes" 49 | "fmt" 50 | "go/ast" 51 | "go/format" 52 | "go/token" 53 | ) 54 | 55 | // A CFG represents the control-flow graph of a single function. 56 | // 57 | // The entry point is Blocks[0]; there may be multiple return blocks. 58 | type CFG struct { 59 | Blocks []*Block // block[0] is entry; order otherwise undefined 60 | } 61 | 62 | // A Block represents a basic block: a list of statements and 63 | // expressions that are always evaluated sequentially. 64 | // 65 | // A block may have 0-2 successors: zero for a return block or a block 66 | // that calls a function such as panic that never returns; one for a 67 | // normal (jump) block; and two for a conditional (if) block. 68 | type Block struct { 69 | Nodes []ast.Node // statements, expressions, and ValueSpecs 70 | Succs []*Block // successor nodes in the graph 71 | 72 | comment string // for debugging 73 | index int32 // index within CFG.Blocks 74 | unreachable bool // is block of stmts following return/panic/for{} 75 | succs2 [2]*Block // underlying array for Succs 76 | } 77 | 78 | // New returns a new control-flow graph for the specified function body, 79 | // which must be non-nil. 80 | // 81 | // The CFG builder calls mayReturn to determine whether a given function 82 | // call may return. For example, calls to panic, os.Exit, and log.Fatal 83 | // do not return, so the builder can remove infeasible graph edges 84 | // following such calls. The builder calls mayReturn only for a 85 | // CallExpr beneath an ExprStmt. 86 | func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG { 87 | b := builder{ 88 | mayReturn: mayReturn, 89 | cfg: new(CFG), 90 | } 91 | b.current = b.newBlock("entry") 92 | b.stmt(body) 93 | 94 | // Does control fall off the end of the function's body? 95 | // Make implicit return explicit. 96 | if b.current != nil && !b.current.unreachable { 97 | b.add(&ast.ReturnStmt{ 98 | Return: body.End() - 1, 99 | }) 100 | } 101 | 102 | return b.cfg 103 | } 104 | 105 | func (b *Block) String() string { 106 | return fmt.Sprintf("block %d (%s)", b.index, b.comment) 107 | } 108 | 109 | // Return returns the return statement at the end of this block if present, nil otherwise. 110 | func (b *Block) Return() (ret *ast.ReturnStmt) { 111 | if len(b.Nodes) > 0 { 112 | ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt) 113 | } 114 | return 115 | } 116 | 117 | // Format formats the control-flow graph for ease of debugging. 118 | func (g *CFG) Format(fset *token.FileSet) string { 119 | var buf bytes.Buffer 120 | for _, b := range g.Blocks { 121 | fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment) 122 | for _, n := range b.Nodes { 123 | fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n)) 124 | } 125 | if len(b.Succs) > 0 { 126 | fmt.Fprintf(&buf, "\tsuccs:") 127 | for _, succ := range b.Succs { 128 | fmt.Fprintf(&buf, " %d", succ.index) 129 | } 130 | buf.WriteByte('\n') 131 | } 132 | buf.WriteByte('\n') 133 | } 134 | return buf.String() 135 | } 136 | 137 | func formatNode(fset *token.FileSet, n ast.Node) string { 138 | var buf bytes.Buffer 139 | format.Node(&buf, fset, n) 140 | // Indent secondary lines by a tab. 141 | return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1)) 142 | } 143 | -------------------------------------------------------------------------------- /testdata/shift.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the suspicious shift checker. 6 | 7 | package testdata 8 | 9 | import ( 10 | "fmt" 11 | "unsafe" 12 | ) 13 | 14 | func ShiftTest() { 15 | var i8 int8 16 | _ = i8 << 7 17 | _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8" 18 | _ = i8 << (7 + 1) // ERROR "i8 .8 bits. too small for shift of 8" 19 | _ = i8 >> 8 // ERROR "i8 .8 bits. too small for shift of 8" 20 | i8 <<= 8 // ERROR "i8 .8 bits. too small for shift of 8" 21 | i8 >>= 8 // ERROR "i8 .8 bits. too small for shift of 8" 22 | var i16 int16 23 | _ = i16 << 15 24 | _ = i16 << 16 // ERROR "i16 .16 bits. too small for shift of 16" 25 | _ = i16 >> 16 // ERROR "i16 .16 bits. too small for shift of 16" 26 | i16 <<= 16 // ERROR "i16 .16 bits. too small for shift of 16" 27 | i16 >>= 16 // ERROR "i16 .16 bits. too small for shift of 16" 28 | var i32 int32 29 | _ = i32 << 31 30 | _ = i32 << 32 // ERROR "i32 .32 bits. too small for shift of 32" 31 | _ = i32 >> 32 // ERROR "i32 .32 bits. too small for shift of 32" 32 | i32 <<= 32 // ERROR "i32 .32 bits. too small for shift of 32" 33 | i32 >>= 32 // ERROR "i32 .32 bits. too small for shift of 32" 34 | var i64 int64 35 | _ = i64 << 63 36 | _ = i64 << 64 // ERROR "i64 .64 bits. too small for shift of 64" 37 | _ = i64 >> 64 // ERROR "i64 .64 bits. too small for shift of 64" 38 | i64 <<= 64 // ERROR "i64 .64 bits. too small for shift of 64" 39 | i64 >>= 64 // ERROR "i64 .64 bits. too small for shift of 64" 40 | var u8 uint8 41 | _ = u8 << 7 42 | _ = u8 << 8 // ERROR "u8 .8 bits. too small for shift of 8" 43 | _ = u8 >> 8 // ERROR "u8 .8 bits. too small for shift of 8" 44 | u8 <<= 8 // ERROR "u8 .8 bits. too small for shift of 8" 45 | u8 >>= 8 // ERROR "u8 .8 bits. too small for shift of 8" 46 | var u16 uint16 47 | _ = u16 << 15 48 | _ = u16 << 16 // ERROR "u16 .16 bits. too small for shift of 16" 49 | _ = u16 >> 16 // ERROR "u16 .16 bits. too small for shift of 16" 50 | u16 <<= 16 // ERROR "u16 .16 bits. too small for shift of 16" 51 | u16 >>= 16 // ERROR "u16 .16 bits. too small for shift of 16" 52 | var u32 uint32 53 | _ = u32 << 31 54 | _ = u32 << 32 // ERROR "u32 .32 bits. too small for shift of 32" 55 | _ = u32 >> 32 // ERROR "u32 .32 bits. too small for shift of 32" 56 | u32 <<= 32 // ERROR "u32 .32 bits. too small for shift of 32" 57 | u32 >>= 32 // ERROR "u32 .32 bits. too small for shift of 32" 58 | var u64 uint64 59 | _ = u64 << 63 60 | _ = u64 << 64 // ERROR "u64 .64 bits. too small for shift of 64" 61 | _ = u64 >> 64 // ERROR "u64 .64 bits. too small for shift of 64" 62 | u64 <<= 64 // ERROR "u64 .64 bits. too small for shift of 64" 63 | u64 >>= 64 // ERROR "u64 .64 bits. too small for shift of 64" 64 | _ = u64 << u64 // Non-constant shifts should succeed. 65 | 66 | var i int 67 | _ = i << 31 68 | const in = 8 * unsafe.Sizeof(i) 69 | _ = i << in // ERROR "too small for shift" 70 | _ = i >> in // ERROR "too small for shift" 71 | i <<= in // ERROR "too small for shift" 72 | i >>= in // ERROR "too small for shift" 73 | const ix = 8*unsafe.Sizeof(i) - 1 74 | _ = i << ix 75 | _ = i >> ix 76 | i <<= ix 77 | i >>= ix 78 | 79 | var u uint 80 | _ = u << 31 81 | const un = 8 * unsafe.Sizeof(u) 82 | _ = u << un // ERROR "too small for shift" 83 | _ = u >> un // ERROR "too small for shift" 84 | u <<= un // ERROR "too small for shift" 85 | u >>= un // ERROR "too small for shift" 86 | const ux = 8*unsafe.Sizeof(u) - 1 87 | _ = u << ux 88 | _ = u >> ux 89 | u <<= ux 90 | u >>= ux 91 | 92 | var p uintptr 93 | _ = p << 31 94 | const pn = 8 * unsafe.Sizeof(p) 95 | _ = p << pn // ERROR "too small for shift" 96 | _ = p >> pn // ERROR "too small for shift" 97 | p <<= pn // ERROR "too small for shift" 98 | p >>= pn // ERROR "too small for shift" 99 | const px = 8*unsafe.Sizeof(p) - 1 100 | _ = p << px 101 | _ = p >> px 102 | p <<= px 103 | p >>= px 104 | 105 | const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks 106 | 107 | var h uintptr 108 | h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) 109 | h <<= 8 * unsafe.Sizeof(h) // ERROR "too small for shift" 110 | h >>= 7 * unsafe.Alignof(h) 111 | h >>= 8 * unsafe.Alignof(h) // ERROR "too small for shift" 112 | } 113 | 114 | func ShiftDeadCode() { 115 | var i int 116 | const iBits = 8 * unsafe.Sizeof(i) 117 | 118 | if iBits <= 32 { 119 | if iBits == 16 { 120 | _ = i >> 8 121 | } else { 122 | _ = i >> 16 123 | } 124 | } else { 125 | _ = i >> 32 126 | } 127 | 128 | if iBits >= 64 { 129 | _ = i << 32 130 | if iBits == 128 { 131 | _ = i << 64 132 | } 133 | } else { 134 | _ = i << 16 135 | } 136 | 137 | if iBits == 64 { 138 | _ = i << 32 139 | } 140 | 141 | switch iBits { 142 | case 128, 64: 143 | _ = i << 32 144 | default: 145 | _ = i << 16 146 | } 147 | 148 | switch { 149 | case iBits < 32: 150 | _ = i << 16 151 | case iBits > 64: 152 | _ = i << 64 153 | default: 154 | _ = i << 64 // ERROR "too small for shift" 155 | } 156 | 157 | // Make sure other vet checks work in dead code. 158 | if iBits == 1024 { 159 | _ = i << 512 // OK 160 | fmt.Printf("foo %s bar", 123) // ERROR "Printf" 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /testdata/bool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for the bool checker. 6 | 7 | package testdata 8 | 9 | import "io" 10 | 11 | type T int 12 | 13 | type FT func() int 14 | 15 | func RatherStupidConditions() { 16 | var f, g func() int 17 | if f() == 0 || f() == 0 { // OK f might have side effects 18 | } 19 | if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w" 20 | } 21 | _ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil" 22 | 23 | _ = i == byte(1) || i == byte(1) // ERROR "redundant or: i == byte(1) || i == byte(1)" 24 | _ = i == T(2) || i == T(2) // ERROR "redundant or: i == T(2) || i == T(2)" 25 | _ = FT(f) == nil || FT(f) == nil // ERROR "redundant or: FT(f) == nil || FT(f) == nil" 26 | 27 | // TODO: distinguish from an actual func call 28 | _ = (func() int)(f) == nil || (func() int)(f) == nil 29 | 30 | var namedFuncVar FT 31 | _ = namedFuncVar() == namedFuncVar() // OK; still func calls 32 | 33 | var c chan int 34 | _ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values 35 | for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j" 36 | } 37 | 38 | var i, j, k int 39 | _ = i+1 == 1 || i+1 == 1 // ERROR "redundant or: i\+1 == 1 || i\+1 == 1" 40 | _ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1" 41 | 42 | _ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" 43 | _ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect 44 | _ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" 45 | 46 | // Test partition edge cases 47 | _ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1" 48 | _ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" 49 | _ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" 50 | _ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" 51 | _ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" 52 | _ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" 53 | _ = i == 1 || f() == 1 || f() == 1 || i == 1 54 | 55 | _ = i == 1 || (i == 1 || i == 2) // ERROR "redundant or: i == 1 || i == 1" 56 | _ = i == 1 || (f() == 1 || i == 1) // OK f may alter i as a side effect 57 | _ = i == 1 || (i == 1 || f() == 1) // ERROR "redundant or: i == 1 || i == 1" 58 | _ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1" 59 | 60 | var a, b bool 61 | _ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1" 62 | 63 | // Check that all redundant ors are flagged 64 | _ = j == 0 || 65 | i == 1 || 66 | f() == 1 || 67 | j == 0 || // ERROR "redundant or: j == 0 || j == 0" 68 | i == 1 || // ERROR "redundant or: i == 1 || i == 1" 69 | i == 1 || // ERROR "redundant or: i == 1 || i == 1" 70 | i == 1 || 71 | j == 0 || 72 | k == 0 73 | 74 | _ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3" 75 | 76 | // These test that redundant, suspect expressions do not trigger multiple errors. 77 | _ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0" 78 | _ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0" 79 | 80 | // and is dual to or; check the basics and 81 | // let the or tests pull the rest of the weight. 82 | _ = 0 != <-c && 0 != <-c // OK subsequent receives may yield different values 83 | _ = f() != 0 && f() != 0 // OK f might have side effects 84 | _ = f != nil && f != nil // ERROR "redundant and: f != nil && f != nil" 85 | _ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1" 86 | _ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect 87 | _ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1" 88 | } 89 | 90 | func RoyallySuspectConditions() { 91 | var i, j int 92 | 93 | _ = i == 0 || i == 1 // OK 94 | _ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1" 95 | _ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i" 96 | _ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i" 97 | _ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1" 98 | 99 | _ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1" 100 | 101 | _ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9" 102 | 103 | _ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1" 104 | 105 | _ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4" 106 | 107 | _ = i != 0 || j != 0 108 | _ = 0 != i || 0 != j 109 | 110 | var s string 111 | _ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other." 112 | 113 | _ = "et" != "alii" || "et" != "cetera" // ERROR "suspect or: .et. != .alii. || .et. != .cetera." 114 | _ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code 115 | 116 | var err error 117 | _ = err != nil || err != io.EOF // TODO catch this case? 118 | 119 | // Sanity check and. 120 | _ = i != 0 && i != 1 // OK 121 | _ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1" 122 | _ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i" 123 | _ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i" 124 | _ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1" 125 | } 126 | -------------------------------------------------------------------------------- /testdata/structtag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the test for canonical struct tags. 6 | 7 | package testdata 8 | 9 | import "encoding/xml" 10 | 11 | type StructTagTest struct { 12 | A int "hello" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" 13 | B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key" 14 | C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get" 15 | D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" 16 | E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" 17 | F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key" 18 | G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" 19 | H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" 20 | I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces" 21 | J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces" 22 | OK0 int `x:"y" u:"v" w:""` 23 | OK1 int `x:"y:z" u:"v" w:""` // note multiple colons. 24 | OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\"" 25 | OK3 int `under_scores:"and" CAPS:"ARE_OK"` 26 | } 27 | 28 | type UnexportedEncodingTagTest struct { 29 | x int `json:"xx"` // ERROR "struct field x has json tag but is not exported" 30 | y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported" 31 | z int 32 | A int `json:"aa" xml:"bb"` 33 | } 34 | 35 | type unexp struct{} 36 | 37 | type JSONEmbeddedField struct { 38 | UnexportedEncodingTagTest `is:"embedded"` 39 | unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363 40 | } 41 | 42 | type AnonymousJSON struct{} 43 | type AnonymousXML struct{} 44 | 45 | type DuplicateJSONFields struct { 46 | JSON int `json:"a"` 47 | DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46" 48 | IgnoredJSON int `json:"-"` 49 | OtherIgnoredJSON int `json:"-"` 50 | OmitJSON int `json:",omitempty"` 51 | OtherOmitJSON int `json:",omitempty"` 52 | DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46" 53 | NonJSON int `foo:"a"` 54 | DuplicateNonJSON int `foo:"a"` 55 | Embedded struct { 56 | DuplicateJSON int `json:"a"` // OK because its not in the same struct type 57 | } 58 | AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46" 59 | 60 | XML int `xml:"a"` 61 | DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60" 62 | IgnoredXML int `xml:"-"` 63 | OtherIgnoredXML int `xml:"-"` 64 | OmitXML int `xml:",omitempty"` 65 | OtherOmitXML int `xml:",omitempty"` 66 | DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60" 67 | NonXML int `foo:"a"` 68 | DuplicateNonXML int `foo:"a"` 69 | Embedded struct { 70 | DuplicateXML int `xml:"a"` // OK because its not in the same struct type 71 | } 72 | AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60" 73 | Attribute struct { 74 | XMLName xml.Name `xml:"b"` 75 | NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct. 76 | Attr int `xml:"b,attr"` // OK because 0 is valid. 77 | DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" 78 | DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" 79 | 80 | AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76" 81 | } 82 | } 83 | 84 | type UnexpectedSpacetest struct { 85 | A int `json:"a,omitempty"` 86 | B int `json:"b, omitempty"` // ERROR "suspicious space in struct tag value" 87 | C int `json:"c ,omitempty"` 88 | D int `json:"d,omitempty, string"` // ERROR "suspicious space in struct tag value" 89 | E int `xml:"e local"` 90 | F int `xml:"f "` // ERROR "suspicious space in struct tag value" 91 | G int `xml:" g"` // ERROR "suspicious space in struct tag value" 92 | H int `xml:"h ,omitempty"` // ERROR "suspicious space in struct tag value" 93 | I int `xml:"i, omitempty"` // ERROR "suspicious space in struct tag value" 94 | J int `xml:"j local ,omitempty"` // ERROR "suspicious space in struct tag value" 95 | K int `xml:"k local, omitempty"` // ERROR "suspicious space in struct tag value" 96 | L int `xml:" l local,omitempty"` // ERROR "suspicious space in struct tag value" 97 | M int `xml:"m local,omitempty"` // ERROR "suspicious space in struct tag value" 98 | N int `xml:" "` // ERROR "suspicious space in struct tag value" 99 | O int `xml:""` 100 | P int `xml:","` 101 | Q int `foo:" doesn't care "` 102 | } 103 | -------------------------------------------------------------------------------- /bool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains boolean condition tests. 6 | 7 | package govet 8 | 9 | import ( 10 | "go/ast" 11 | "go/token" 12 | "go/types" 13 | ) 14 | 15 | func init() { 16 | register("bool", 17 | "check for mistakes involving boolean operators", 18 | checkBool, 19 | binaryExpr) 20 | } 21 | 22 | func checkBool(f *File, n ast.Node) { 23 | e := n.(*ast.BinaryExpr) 24 | 25 | var op boolOp 26 | switch e.Op { 27 | case token.LOR: 28 | op = or 29 | case token.LAND: 30 | op = and 31 | default: 32 | return 33 | } 34 | 35 | comm := op.commutativeSets(f, e) 36 | for _, exprs := range comm { 37 | op.checkRedundant(f, exprs) 38 | op.checkSuspect(f, exprs) 39 | } 40 | } 41 | 42 | type boolOp struct { 43 | name string 44 | tok token.Token // token corresponding to this operator 45 | badEq token.Token // token corresponding to the equality test that should not be used with this operator 46 | } 47 | 48 | var ( 49 | or = boolOp{"or", token.LOR, token.NEQ} 50 | and = boolOp{"and", token.LAND, token.EQL} 51 | ) 52 | 53 | // commutativeSets returns all side effect free sets of 54 | // expressions in e that are connected by op. 55 | // For example, given 'a || b || f() || c || d' with the or op, 56 | // commutativeSets returns {{b, a}, {d, c}}. 57 | func (op boolOp) commutativeSets(f *File, e *ast.BinaryExpr) [][]ast.Expr { 58 | exprs := op.split(e) 59 | 60 | // Partition the slice of expressions into commutative sets. 61 | i := 0 62 | var sets [][]ast.Expr 63 | for j := 0; j <= len(exprs); j++ { 64 | if j == len(exprs) || hasSideEffects(f, exprs[j]) { 65 | if i < j { 66 | sets = append(sets, exprs[i:j]) 67 | } 68 | i = j + 1 69 | } 70 | } 71 | 72 | return sets 73 | } 74 | 75 | // checkRedundant checks for expressions of the form 76 | // e && e 77 | // e || e 78 | // Exprs must contain only side effect free expressions. 79 | func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) { 80 | seen := make(map[string]bool) 81 | for _, e := range exprs { 82 | efmt := f.gofmt(e) 83 | if seen[efmt] { 84 | f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt) 85 | } else { 86 | seen[efmt] = true 87 | } 88 | } 89 | } 90 | 91 | // checkSuspect checks for expressions of the form 92 | // x != c1 || x != c2 93 | // x == c1 && x == c2 94 | // where c1 and c2 are constant expressions. 95 | // If c1 and c2 are the same then it's redundant; 96 | // if c1 and c2 are different then it's always true or always false. 97 | // Exprs must contain only side effect free expressions. 98 | func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) { 99 | // seen maps from expressions 'x' to equality expressions 'x != c'. 100 | seen := make(map[string]string) 101 | 102 | for _, e := range exprs { 103 | bin, ok := e.(*ast.BinaryExpr) 104 | if !ok || bin.Op != op.badEq { 105 | continue 106 | } 107 | 108 | // In order to avoid false positives, restrict to cases 109 | // in which one of the operands is constant. We're then 110 | // interested in the other operand. 111 | // In the rare case in which both operands are constant 112 | // (e.g. runtime.GOOS and "windows"), we'll only catch 113 | // mistakes if the LHS is repeated, which is how most 114 | // code is written. 115 | var x ast.Expr 116 | switch { 117 | case f.pkg.types[bin.Y].Value != nil: 118 | x = bin.X 119 | case f.pkg.types[bin.X].Value != nil: 120 | x = bin.Y 121 | default: 122 | continue 123 | } 124 | 125 | // e is of the form 'x != c' or 'x == c'. 126 | xfmt := f.gofmt(x) 127 | efmt := f.gofmt(e) 128 | if prev, found := seen[xfmt]; found { 129 | // checkRedundant handles the case in which efmt == prev. 130 | if efmt != prev { 131 | f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev) 132 | } 133 | } else { 134 | seen[xfmt] = efmt 135 | } 136 | } 137 | } 138 | 139 | // hasSideEffects reports whether evaluation of e has side effects. 140 | func hasSideEffects(f *File, e ast.Expr) bool { 141 | safe := true 142 | ast.Inspect(e, func(node ast.Node) bool { 143 | switch n := node.(type) { 144 | case *ast.CallExpr: 145 | // Don't call Type.Underlying(), since its lack 146 | // lets us see the NamedFuncType(x) type 147 | // conversion as a *types.Named. 148 | _, ok := f.pkg.types[n.Fun].Type.(*types.Signature) 149 | if ok { 150 | // Conservatively assume that all function and 151 | // method calls have side effects for 152 | // now. This will include func type 153 | // conversions, but it's ok given that 154 | // this is the conservative side. 155 | safe = false 156 | return false 157 | } 158 | // It's a type conversion, which cannot 159 | // have side effects. 160 | case *ast.UnaryExpr: 161 | if n.Op == token.ARROW { 162 | safe = false 163 | return false 164 | } 165 | } 166 | return true 167 | }) 168 | return !safe 169 | } 170 | 171 | // split returns a slice of all subexpressions in e that are connected by op. 172 | // For example, given 'a || (b || c) || d' with the or op, 173 | // split returns []{d, c, b, a}. 174 | func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) { 175 | for { 176 | e = unparen(e) 177 | if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok { 178 | exprs = append(exprs, op.split(b.Y)...) 179 | e = b.X 180 | } else { 181 | exprs = append(exprs, e) 182 | break 183 | } 184 | } 185 | return 186 | } 187 | 188 | // unparen returns e with any enclosing parentheses stripped. 189 | func unparen(e ast.Expr) ast.Expr { 190 | for { 191 | p, ok := e.(*ast.ParenExpr) 192 | if !ok { 193 | return e 194 | } 195 | e = p.X 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /tests.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package govet 6 | 7 | import ( 8 | "go/ast" 9 | "go/types" 10 | "strings" 11 | "unicode" 12 | "unicode/utf8" 13 | ) 14 | 15 | func init() { 16 | register("tests", 17 | "check for common mistaken usages of tests/documentation examples", 18 | checkTestFunctions, 19 | funcDecl) 20 | } 21 | 22 | func isExampleSuffix(s string) bool { 23 | r, size := utf8.DecodeRuneInString(s) 24 | return size > 0 && unicode.IsLower(r) 25 | } 26 | 27 | func isTestSuffix(name string) bool { 28 | if len(name) == 0 { 29 | // "Test" is ok. 30 | return true 31 | } 32 | r, _ := utf8.DecodeRuneInString(name) 33 | return !unicode.IsLower(r) 34 | } 35 | 36 | func isTestParam(typ ast.Expr, wantType string) bool { 37 | ptr, ok := typ.(*ast.StarExpr) 38 | if !ok { 39 | // Not a pointer. 40 | return false 41 | } 42 | // No easy way of making sure it's a *testing.T or *testing.B: 43 | // ensure the name of the type matches. 44 | if name, ok := ptr.X.(*ast.Ident); ok { 45 | return name.Name == wantType 46 | } 47 | if sel, ok := ptr.X.(*ast.SelectorExpr); ok { 48 | return sel.Sel.Name == wantType 49 | } 50 | return false 51 | } 52 | 53 | func lookup(name string, scopes []*types.Scope) types.Object { 54 | for _, scope := range scopes { 55 | if o := scope.Lookup(name); o != nil { 56 | return o 57 | } 58 | } 59 | return nil 60 | } 61 | 62 | func extendedScope(f *File) []*types.Scope { 63 | scopes := []*types.Scope{f.pkg.typesPkg.Scope()} 64 | if f.basePkg != nil { 65 | scopes = append(scopes, f.basePkg.typesPkg.Scope()) 66 | } else { 67 | // If basePkg is not specified (e.g. when checking a single file) try to 68 | // find it among imports. 69 | pkgName := f.pkg.typesPkg.Name() 70 | if strings.HasSuffix(pkgName, "_test") { 71 | basePkgName := strings.TrimSuffix(pkgName, "_test") 72 | for _, p := range f.pkg.typesPkg.Imports() { 73 | if p.Name() == basePkgName { 74 | scopes = append(scopes, p.Scope()) 75 | break 76 | } 77 | } 78 | } 79 | } 80 | return scopes 81 | } 82 | 83 | func checkExample(fn *ast.FuncDecl, f *File, report reporter) { 84 | fnName := fn.Name.Name 85 | if params := fn.Type.Params; len(params.List) != 0 { 86 | report("%s should be niladic", fnName) 87 | } 88 | if results := fn.Type.Results; results != nil && len(results.List) != 0 { 89 | report("%s should return nothing", fnName) 90 | } 91 | 92 | if filesRun && !includesNonTest { 93 | // The coherence checks between a test and the package it tests 94 | // will report false positives if no non-test files have 95 | // been provided. 96 | return 97 | } 98 | 99 | if fnName == "Example" { 100 | // Nothing more to do. 101 | return 102 | } 103 | 104 | var ( 105 | exName = strings.TrimPrefix(fnName, "Example") 106 | elems = strings.SplitN(exName, "_", 3) 107 | ident = elems[0] 108 | obj = lookup(ident, extendedScope(f)) 109 | ) 110 | if ident != "" && obj == nil { 111 | // Check ExampleFoo and ExampleBadFoo. 112 | report("%s refers to unknown identifier: %s", fnName, ident) 113 | // Abort since obj is absent and no subsequent checks can be performed. 114 | return 115 | } 116 | if len(elems) < 2 { 117 | // Nothing more to do. 118 | return 119 | } 120 | 121 | if ident == "" { 122 | // Check Example_suffix and Example_BadSuffix. 123 | if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) { 124 | report("%s has malformed example suffix: %s", fnName, residual) 125 | } 126 | return 127 | } 128 | 129 | mmbr := elems[1] 130 | if !isExampleSuffix(mmbr) { 131 | // Check ExampleFoo_Method and ExampleFoo_BadMethod. 132 | if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil { 133 | report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr) 134 | } 135 | } 136 | if len(elems) == 3 && !isExampleSuffix(elems[2]) { 137 | // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix. 138 | report("%s has malformed example suffix: %s", fnName, elems[2]) 139 | } 140 | } 141 | 142 | func checkTest(fn *ast.FuncDecl, prefix string, report reporter) { 143 | // Want functions with 0 results and 1 parameter. 144 | if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || 145 | fn.Type.Params == nil || 146 | len(fn.Type.Params.List) != 1 || 147 | len(fn.Type.Params.List[0].Names) > 1 { 148 | return 149 | } 150 | 151 | // The param must look like a *testing.T or *testing.B. 152 | if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) { 153 | return 154 | } 155 | 156 | if !isTestSuffix(fn.Name.Name[len(prefix):]) { 157 | report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix) 158 | } 159 | } 160 | 161 | type reporter func(format string, args ...interface{}) 162 | 163 | // checkTestFunctions walks Test, Benchmark and Example functions checking 164 | // malformed names, wrong signatures and examples documenting nonexistent 165 | // identifiers. 166 | func checkTestFunctions(f *File, node ast.Node) { 167 | if !strings.HasSuffix(f.name, "_test.go") { 168 | return 169 | } 170 | 171 | fn, ok := node.(*ast.FuncDecl) 172 | if !ok || fn.Recv != nil { 173 | // Ignore non-functions or functions with receivers. 174 | return 175 | } 176 | 177 | report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) } 178 | 179 | switch { 180 | case strings.HasPrefix(fn.Name.Name, "Example"): 181 | checkExample(fn, f, report) 182 | case strings.HasPrefix(fn.Name.Name, "Test"): 183 | checkTest(fn, "Test", report) 184 | case strings.HasPrefix(fn.Name.Name, "Benchmark"): 185 | checkTest(fn, "Benchmark", report) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /testdata/copylock.go: -------------------------------------------------------------------------------- 1 | package testdata 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "unsafe" 7 | . "unsafe" 8 | unsafe1 "unsafe" 9 | ) 10 | 11 | func OkFunc() { 12 | var x *sync.Mutex 13 | p := x 14 | var y sync.Mutex 15 | p = &y 16 | 17 | var z = sync.Mutex{} 18 | w := sync.Mutex{} 19 | 20 | w = sync.Mutex{} 21 | q := struct{ L sync.Mutex }{ 22 | L: sync.Mutex{}, 23 | } 24 | 25 | yy := []Tlock{ 26 | Tlock{}, 27 | Tlock{ 28 | once: sync.Once{}, 29 | }, 30 | } 31 | 32 | nl := new(sync.Mutex) 33 | mx := make([]sync.Mutex, 10) 34 | xx := struct{ L *sync.Mutex }{ 35 | L: new(sync.Mutex), 36 | } 37 | } 38 | 39 | type Tlock struct { 40 | once sync.Once 41 | } 42 | 43 | func BadFunc() { 44 | var x *sync.Mutex 45 | p := x 46 | var y sync.Mutex 47 | p = &y 48 | *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex" 49 | 50 | var t Tlock 51 | var tp *Tlock 52 | tp = &t 53 | *tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" 54 | t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex" 55 | 56 | y := *x // ERROR "assignment copies lock value to y: sync.Mutex" 57 | var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex" 58 | 59 | w := struct{ L sync.Mutex }{ 60 | L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex" 61 | } 62 | var q = map[int]Tlock{ 63 | 1: t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex" 64 | 2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" 65 | } 66 | yy := []Tlock{ 67 | t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex" 68 | *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" 69 | } 70 | 71 | // override 'new' keyword 72 | new := func(interface{}) {} 73 | new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex" 74 | 75 | // copy of array of locks 76 | var muA [5]sync.Mutex 77 | muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex" 78 | muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex" 79 | muSlice := muA[:] // OK 80 | 81 | // multidimensional array 82 | var mmuA [5][5]sync.Mutex 83 | mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex" 84 | mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex" 85 | mmuSlice := mmuA[:] // OK 86 | 87 | // slice copy is ok 88 | var fmuA [5][][5]sync.Mutex 89 | fmuB := fmuA // OK 90 | fmuA = fmuB // OK 91 | fmuSlice := fmuA[:] // OK 92 | } 93 | 94 | func LenAndCapOnLockArrays() { 95 | var a [5]sync.Mutex 96 | aLen := len(a) // OK 97 | aCap := cap(a) // OK 98 | 99 | // override 'len' and 'cap' keywords 100 | 101 | len := func(interface{}) {} 102 | len(a) // ERROR "call of len copies lock value: sync.Mutex" 103 | 104 | cap := func(interface{}) {} 105 | cap(a) // ERROR "call of cap copies lock value: sync.Mutex" 106 | } 107 | 108 | func SizeofMutex() { 109 | var mu sync.Mutex 110 | unsafe.Sizeof(mu) // OK 111 | unsafe1.Sizeof(mu) // OK 112 | Sizeof(mu) // OK 113 | unsafe := struct{ Sizeof func(interface{}) }{} 114 | unsafe.Sizeof(mu) // ERROR "call of unsafe.Sizeof copies lock value: sync.Mutex" 115 | Sizeof := func(interface{}) {} 116 | Sizeof(mu) // ERROR "call of Sizeof copies lock value: sync.Mutex" 117 | } 118 | 119 | // SyncTypesCheck checks copying of sync.* types except sync.Mutex 120 | func SyncTypesCheck() { 121 | // sync.RWMutex copying 122 | var rwmuX sync.RWMutex 123 | var rwmuXX = sync.RWMutex{} 124 | rwmuX1 := new(sync.RWMutex) 125 | rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" 126 | rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" 127 | var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex" 128 | rwmuP := &rwmuX 129 | rwmuZ := &sync.RWMutex{} 130 | 131 | // sync.Cond copying 132 | var condX sync.Cond 133 | var condXX = sync.Cond{} 134 | condX1 := new(sync.Cond) 135 | condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" 136 | condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" 137 | var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy" 138 | condP := &condX 139 | condZ := &sync.Cond{ 140 | L: &sync.Mutex{}, 141 | } 142 | condZ = sync.NewCond(&sync.Mutex{}) 143 | 144 | // sync.WaitGroup copying 145 | var wgX sync.WaitGroup 146 | var wgXX = sync.WaitGroup{} 147 | wgX1 := new(sync.WaitGroup) 148 | wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" 149 | wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" 150 | var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy" 151 | wgP := &wgX 152 | wgZ := &sync.WaitGroup{} 153 | 154 | // sync.Pool copying 155 | var poolX sync.Pool 156 | var poolXX = sync.Pool{} 157 | poolX1 := new(sync.Pool) 158 | poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" 159 | poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" 160 | var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy" 161 | poolP := &poolX 162 | poolZ := &sync.Pool{} 163 | 164 | // sync.Once copying 165 | var onceX sync.Once 166 | var onceXX = sync.Once{} 167 | onceX1 := new(sync.Once) 168 | onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" 169 | onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" 170 | var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex" 171 | onceP := &onceX 172 | onceZ := &sync.Once{} 173 | } 174 | 175 | // AtomicTypesCheck checks copying of sync/atomic types 176 | func AtomicTypesCheck() { 177 | // atomic.Value copying 178 | var vX atomic.Value 179 | var vXX = atomic.Value{} 180 | vX1 := new(atomic.Value) 181 | // These are OK because the value has not been used yet. 182 | // (And vet can't tell whether it has been used, so they're always OK.) 183 | vY := vX 184 | vY = vX 185 | var vYY = vX 186 | vP := &vX 187 | vZ := &atomic.Value{} 188 | } 189 | -------------------------------------------------------------------------------- /method.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the code to check canonical methods. 6 | 7 | package govet 8 | 9 | import ( 10 | "fmt" 11 | "go/ast" 12 | "go/printer" 13 | "strings" 14 | ) 15 | 16 | func init() { 17 | register("methods", 18 | "check that canonically named methods are canonically defined", 19 | checkCanonicalMethod, 20 | funcDecl, interfaceType) 21 | } 22 | 23 | type MethodSig struct { 24 | args []string 25 | results []string 26 | } 27 | 28 | // canonicalMethods lists the input and output types for Go methods 29 | // that are checked using dynamic interface checks. Because the 30 | // checks are dynamic, such methods would not cause a compile error 31 | // if they have the wrong signature: instead the dynamic check would 32 | // fail, sometimes mysteriously. If a method is found with a name listed 33 | // here but not the input/output types listed here, vet complains. 34 | // 35 | // A few of the canonical methods have very common names. 36 | // For example, a type might implement a Scan method that 37 | // has nothing to do with fmt.Scanner, but we still want to check 38 | // the methods that are intended to implement fmt.Scanner. 39 | // To do that, the arguments that have a = prefix are treated as 40 | // signals that the canonical meaning is intended: if a Scan 41 | // method doesn't have a fmt.ScanState as its first argument, 42 | // we let it go. But if it does have a fmt.ScanState, then the 43 | // rest has to match. 44 | var canonicalMethods = map[string]MethodSig{ 45 | // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict 46 | "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter 47 | "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder 48 | "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder 49 | "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler 50 | "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler 51 | "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader 52 | "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom 53 | "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader 54 | "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner 55 | "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker 56 | "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler 57 | "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler 58 | "UnreadByte": {[]string{}, []string{"error"}}, 59 | "UnreadRune": {[]string{}, []string{"error"}}, 60 | "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer) 61 | "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo 62 | } 63 | 64 | func checkCanonicalMethod(f *File, node ast.Node) { 65 | switch n := node.(type) { 66 | case *ast.FuncDecl: 67 | if n.Recv != nil { 68 | canonicalMethod(f, n.Name, n.Type) 69 | } 70 | case *ast.InterfaceType: 71 | for _, field := range n.Methods.List { 72 | for _, id := range field.Names { 73 | canonicalMethod(f, id, field.Type.(*ast.FuncType)) 74 | } 75 | } 76 | } 77 | } 78 | 79 | func canonicalMethod(f *File, id *ast.Ident, t *ast.FuncType) { 80 | // Expected input/output. 81 | expect, ok := canonicalMethods[id.Name] 82 | if !ok { 83 | return 84 | } 85 | 86 | // Actual input/output 87 | args := typeFlatten(t.Params.List) 88 | var results []ast.Expr 89 | if t.Results != nil { 90 | results = typeFlatten(t.Results.List) 91 | } 92 | 93 | // Do the =s (if any) all match? 94 | if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") { 95 | return 96 | } 97 | 98 | // Everything must match. 99 | if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") { 100 | expectFmt := id.Name + "(" + argjoin(expect.args) + ")" 101 | if len(expect.results) == 1 { 102 | expectFmt += " " + argjoin(expect.results) 103 | } else if len(expect.results) > 1 { 104 | expectFmt += " (" + argjoin(expect.results) + ")" 105 | } 106 | 107 | f.b.Reset() 108 | if err := printer.Fprint(&f.b, f.fset, t); err != nil { 109 | fmt.Fprintf(&f.b, "<%s>", err) 110 | } 111 | actual := f.b.String() 112 | actual = strings.TrimPrefix(actual, "func") 113 | actual = id.Name + actual 114 | 115 | f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt) 116 | } 117 | } 118 | 119 | func argjoin(x []string) string { 120 | y := make([]string, len(x)) 121 | for i, s := range x { 122 | if s[0] == '=' { 123 | s = s[1:] 124 | } 125 | y[i] = s 126 | } 127 | return strings.Join(y, ", ") 128 | } 129 | 130 | // Turn parameter list into slice of types 131 | // (in the ast, types are Exprs). 132 | // Have to handle f(int, bool) and f(x, y, z int) 133 | // so not a simple 1-to-1 conversion. 134 | func typeFlatten(l []*ast.Field) []ast.Expr { 135 | var t []ast.Expr 136 | for _, f := range l { 137 | if len(f.Names) == 0 { 138 | t = append(t, f.Type) 139 | continue 140 | } 141 | for range f.Names { 142 | t = append(t, f.Type) 143 | } 144 | } 145 | return t 146 | } 147 | 148 | // Does each type in expect with the given prefix match the corresponding type in actual? 149 | func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool { 150 | for i, x := range expect { 151 | if !strings.HasPrefix(x, prefix) { 152 | continue 153 | } 154 | if i >= len(actual) { 155 | return false 156 | } 157 | if !f.matchParamType(x, actual[i]) { 158 | return false 159 | } 160 | } 161 | if prefix == "" && len(actual) > len(expect) { 162 | return false 163 | } 164 | return true 165 | } 166 | 167 | // Does this one type match? 168 | func (f *File) matchParamType(expect string, actual ast.Expr) bool { 169 | expect = strings.TrimPrefix(expect, "=") 170 | // Strip package name if we're in that package. 171 | if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' { 172 | expect = expect[n+1:] 173 | } 174 | 175 | // Overkill but easy. 176 | f.b.Reset() 177 | printer.Fprint(&f.b, f.fset, actual) 178 | return f.b.String() == expect 179 | } 180 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | 7 | Vet examines Go source code and reports suspicious constructs, such as Printf 8 | calls whose arguments do not align with the format string. Vet uses heuristics 9 | that do not guarantee all reports are genuine problems, but it can find errors 10 | not caught by the compilers. 11 | 12 | Vet is normally invoked using the go command by running "go vet": 13 | 14 | go vet 15 | vets the package in the current directory. 16 | 17 | go vet package/path/name 18 | vets the package whose path is provided. 19 | 20 | Use "go help packages" to see other ways of specifying which packages to vet. 21 | 22 | Vet's exit code is 2 for erroneous invocation of the tool, 1 if a 23 | problem was reported, and 0 otherwise. Note that the tool does not 24 | check every possible problem and depends on unreliable heuristics 25 | so it should be used as guidance only, not as a firm indicator of 26 | program correctness. 27 | 28 | By default the -all flag is set so all checks are performed. 29 | If any flags are explicitly set to true, only those tests are run. Conversely, if 30 | any flag is explicitly set to false, only those tests are disabled. Thus -printf=true 31 | runs the printf check, -printf=false runs all checks except the printf check. 32 | 33 | By default vet uses the object files generated by 'go install some/pkg' to typecheck the code. 34 | If the -source flag is provided, vet uses only source code. 35 | 36 | Available checks: 37 | 38 | Assembly declarations 39 | 40 | Flag: -asmdecl 41 | 42 | Mismatches between assembly files and Go function declarations. 43 | 44 | Useless assignments 45 | 46 | Flag: -assign 47 | 48 | Check for useless assignments. 49 | 50 | Atomic mistakes 51 | 52 | Flag: -atomic 53 | 54 | Common mistaken usages of the sync/atomic package. 55 | 56 | Boolean conditions 57 | 58 | Flag: -bool 59 | 60 | Mistakes involving boolean operators. 61 | 62 | Build tags 63 | 64 | Flag: -buildtags 65 | 66 | Badly formed or misplaced +build tags. 67 | 68 | Invalid uses of cgo 69 | 70 | Flag: -cgocall 71 | 72 | Detect some violations of the cgo pointer passing rules. 73 | 74 | Unkeyed composite literals 75 | 76 | Flag: -composites 77 | 78 | Composite struct literals that do not use the field-keyed syntax. 79 | 80 | Copying locks 81 | 82 | Flag: -copylocks 83 | 84 | Locks that are erroneously passed by value. 85 | 86 | HTTP responses used incorrectly 87 | 88 | Flag: -httpresponse 89 | 90 | Mistakes deferring a function call on an HTTP response before 91 | checking whether the error returned with the response was nil. 92 | 93 | Failure to call the cancelation function returned by WithCancel 94 | 95 | Flag: -lostcancel 96 | 97 | The cancelation function returned by context.WithCancel, WithTimeout, 98 | and WithDeadline must be called or the new context will remain live 99 | until its parent context is cancelled. 100 | (The background context is never cancelled.) 101 | 102 | Methods 103 | 104 | Flag: -methods 105 | 106 | Non-standard signatures for methods with familiar names, including: 107 | Format GobEncode GobDecode MarshalJSON MarshalXML 108 | Peek ReadByte ReadFrom ReadRune Scan Seek 109 | UnmarshalJSON UnreadByte UnreadRune WriteByte 110 | WriteTo 111 | 112 | Nil function comparison 113 | 114 | Flag: -nilfunc 115 | 116 | Comparisons between functions and nil. 117 | 118 | Printf family 119 | 120 | Flag: -printf 121 | 122 | Suspicious calls to functions in the Printf family, including any functions 123 | with these names, disregarding case: 124 | Print Printf Println 125 | Fprint Fprintf Fprintln 126 | Sprint Sprintf Sprintln 127 | Error Errorf 128 | Fatal Fatalf 129 | Log Logf 130 | Panic Panicf Panicln 131 | The -printfuncs flag can be used to redefine this list. 132 | If the function name ends with an 'f', the function is assumed to take 133 | a format descriptor string in the manner of fmt.Printf. If not, vet 134 | complains about arguments that look like format descriptor strings. 135 | 136 | It also checks for errors such as using a Writer as the first argument of 137 | Printf. 138 | 139 | Range loop variables 140 | 141 | Flag: -rangeloops 142 | 143 | Incorrect uses of range loop variables in closures. 144 | 145 | Shadowed variables 146 | 147 | Flag: -shadow=false (experimental; must be set explicitly) 148 | 149 | Variables that may have been unintentionally shadowed. 150 | 151 | Shifts 152 | 153 | Flag: -shift 154 | 155 | Shifts equal to or longer than the variable's length. 156 | 157 | Struct tags 158 | 159 | Flag: -structtags 160 | 161 | Struct tags that do not follow the format understood by reflect.StructTag.Get. 162 | Well-known encoding struct tags (json, xml) used with unexported fields. 163 | 164 | Tests and documentation examples 165 | 166 | Flag: -tests 167 | 168 | Mistakes involving tests including functions with incorrect names or signatures 169 | and example tests that document identifiers not in the package. 170 | 171 | Unreachable code 172 | 173 | Flag: -unreachable 174 | 175 | Unreachable code. 176 | 177 | Misuse of unsafe Pointers 178 | 179 | Flag: -unsafeptr 180 | 181 | Likely incorrect uses of unsafe.Pointer to convert integers to pointers. 182 | A conversion from uintptr to unsafe.Pointer is invalid if it implies that 183 | there is a uintptr-typed word in memory that holds a pointer value, 184 | because that word will be invisible to stack copying and to the garbage 185 | collector. 186 | 187 | Unused result of certain function calls 188 | 189 | Flag: -unusedresult 190 | 191 | Calls to well-known functions and methods that return a value that is 192 | discarded. By default, this includes functions like fmt.Errorf and 193 | fmt.Sprintf and methods like String and Error. The flags -unusedfuncs 194 | and -unusedstringmethods control the set. 195 | 196 | Other flags 197 | 198 | These flags configure the behavior of vet: 199 | 200 | -all (default true) 201 | Enable all non-experimental checks. 202 | -v 203 | Verbose mode 204 | -printfuncs 205 | A comma-separated list of print-like function names 206 | to supplement the standard list. 207 | For more information, see the discussion of the -printf flag. 208 | -shadowstrict 209 | Whether to be strict about shadowing; can be noisy. 210 | 211 | Using vet directly 212 | 213 | For testing and debugging vet can be run directly by invoking 214 | "go tool vet" or just running the binary. Run this way, vet might not 215 | have up to date information for imported packages. 216 | 217 | go tool vet source/directory/*.go 218 | vets the files named, all of which must be in the same package. 219 | 220 | go tool vet source/directory 221 | recursively descends the directory, vetting each package it finds. 222 | 223 | */ 224 | package govet 225 | -------------------------------------------------------------------------------- /structtag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the test for canonical struct tags. 6 | 7 | package govet 8 | 9 | import ( 10 | "errors" 11 | "go/ast" 12 | "go/token" 13 | "reflect" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | func init() { 19 | register("structtags", 20 | "check that struct field tags have canonical format and apply to exported fields as needed", 21 | checkStructFieldTags, 22 | structType) 23 | } 24 | 25 | // checkStructFieldTags checks all the field tags of a struct, including checking for duplicates. 26 | func checkStructFieldTags(f *File, node ast.Node) { 27 | var seen map[[2]string]token.Pos 28 | for _, field := range node.(*ast.StructType).Fields.List { 29 | checkCanonicalFieldTag(f, field, &seen) 30 | } 31 | } 32 | 33 | var checkTagDups = []string{"json", "xml"} 34 | var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} 35 | 36 | // checkCanonicalFieldTag checks a single struct field tag. 37 | func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token.Pos) { 38 | if field.Tag == nil { 39 | return 40 | } 41 | 42 | tag, err := strconv.Unquote(field.Tag.Value) 43 | if err != nil { 44 | f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value) 45 | return 46 | } 47 | 48 | if err := validateStructTag(tag); err != nil { 49 | raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string 50 | f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err) 51 | } 52 | 53 | for _, key := range checkTagDups { 54 | val := reflect.StructTag(tag).Get(key) 55 | if val == "" || val == "-" || val[0] == ',' { 56 | continue 57 | } 58 | if key == "xml" && len(field.Names) > 0 && field.Names[0].Name == "XMLName" { 59 | // XMLName defines the XML element name of the struct being 60 | // checked. That name cannot collide with element or attribute 61 | // names defined on other fields of the struct. Vet does not have a 62 | // check for untagged fields of type struct defining their own name 63 | // by containing a field named XMLName; see issue 18256. 64 | continue 65 | } 66 | if i := strings.Index(val, ","); i >= 0 { 67 | if key == "xml" { 68 | // Use a separate namespace for XML attributes. 69 | for _, opt := range strings.Split(val[i:], ",") { 70 | if opt == "attr" { 71 | key += " attribute" // Key is part of the error message. 72 | break 73 | } 74 | } 75 | } 76 | val = val[:i] 77 | } 78 | if *seen == nil { 79 | *seen = map[[2]string]token.Pos{} 80 | } 81 | if pos, ok := (*seen)[[2]string{key, val}]; ok { 82 | var name string 83 | if len(field.Names) > 0 { 84 | name = field.Names[0].Name 85 | } else { 86 | name = field.Type.(*ast.Ident).Name 87 | } 88 | f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", name, key, val, f.loc(pos)) 89 | } else { 90 | (*seen)[[2]string{key, val}] = field.Pos() 91 | } 92 | } 93 | 94 | // Check for use of json or xml tags with unexported fields. 95 | 96 | // Embedded struct. Nothing to do for now, but that 97 | // may change, depending on what happens with issue 7363. 98 | if len(field.Names) == 0 { 99 | return 100 | } 101 | 102 | if field.Names[0].IsExported() { 103 | return 104 | } 105 | 106 | for _, enc := range [...]string{"json", "xml"} { 107 | if reflect.StructTag(tag).Get(enc) != "" { 108 | f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc) 109 | return 110 | } 111 | } 112 | } 113 | 114 | var ( 115 | errTagSyntax = errors.New("bad syntax for struct tag pair") 116 | errTagKeySyntax = errors.New("bad syntax for struct tag key") 117 | errTagValueSyntax = errors.New("bad syntax for struct tag value") 118 | errTagValueSpace = errors.New("suspicious space in struct tag value") 119 | errTagSpace = errors.New("key:\"value\" pairs not separated by spaces") 120 | ) 121 | 122 | // validateStructTag parses the struct tag and returns an error if it is not 123 | // in the canonical format, which is a space-separated list of key:"value" 124 | // settings. The value may contain spaces. 125 | func validateStructTag(tag string) error { 126 | // This code is based on the StructTag.Get code in package reflect. 127 | 128 | n := 0 129 | for ; tag != ""; n++ { 130 | if n > 0 && tag != "" && tag[0] != ' ' { 131 | // More restrictive than reflect, but catches likely mistakes 132 | // like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y". 133 | return errTagSpace 134 | } 135 | // Skip leading space. 136 | i := 0 137 | for i < len(tag) && tag[i] == ' ' { 138 | i++ 139 | } 140 | tag = tag[i:] 141 | if tag == "" { 142 | break 143 | } 144 | 145 | // Scan to colon. A space, a quote or a control character is a syntax error. 146 | // Strictly speaking, control chars include the range [0x7f, 0x9f], not just 147 | // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters 148 | // as it is simpler to inspect the tag's bytes than the tag's runes. 149 | i = 0 150 | for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { 151 | i++ 152 | } 153 | if i == 0 { 154 | return errTagKeySyntax 155 | } 156 | if i+1 >= len(tag) || tag[i] != ':' { 157 | return errTagSyntax 158 | } 159 | if tag[i+1] != '"' { 160 | return errTagValueSyntax 161 | } 162 | key := tag[:i] 163 | tag = tag[i+1:] 164 | 165 | // Scan quoted string to find value. 166 | i = 1 167 | for i < len(tag) && tag[i] != '"' { 168 | if tag[i] == '\\' { 169 | i++ 170 | } 171 | i++ 172 | } 173 | if i >= len(tag) { 174 | return errTagValueSyntax 175 | } 176 | qvalue := tag[:i+1] 177 | tag = tag[i+1:] 178 | 179 | value, err := strconv.Unquote(qvalue) 180 | if err != nil { 181 | return errTagValueSyntax 182 | } 183 | 184 | if !checkTagSpaces[key] { 185 | continue 186 | } 187 | 188 | switch key { 189 | case "xml": 190 | // If the first or last character in the XML tag is a space, it is 191 | // suspicious. 192 | if strings.Trim(value, " ") != value { 193 | return errTagValueSpace 194 | } 195 | 196 | // If there are multiple spaces, they are suspicious. 197 | if strings.Count(value, " ") > 1 { 198 | return errTagValueSpace 199 | } 200 | 201 | // If there is no comma, skip the rest of the checks. 202 | comma := strings.IndexRune(value, ',') 203 | if comma < 0 { 204 | continue 205 | } 206 | 207 | // If the character before a comma is a space, this is suspicious. 208 | if comma > 0 && value[comma-1] == ' ' { 209 | return errTagValueSpace 210 | } 211 | value = value[comma+1:] 212 | case "json": 213 | // JSON allows using spaces in the name, so skip it. 214 | comma := strings.IndexRune(value, ',') 215 | if comma < 0 { 216 | continue 217 | } 218 | value = value[comma+1:] 219 | } 220 | 221 | if strings.IndexByte(value, ' ') >= 0 { 222 | return errTagValueSpace 223 | } 224 | } 225 | return nil 226 | } 227 | -------------------------------------------------------------------------------- /copylock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains the code to check that locks are not passed by value. 6 | 7 | package govet 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "go/ast" 13 | "go/token" 14 | "go/types" 15 | ) 16 | 17 | func init() { 18 | register("copylocks", 19 | "check that locks are not passed by value", 20 | checkCopyLocks, 21 | funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt) 22 | } 23 | 24 | // checkCopyLocks checks whether node might 25 | // inadvertently copy a lock. 26 | func checkCopyLocks(f *File, node ast.Node) { 27 | switch node := node.(type) { 28 | case *ast.RangeStmt: 29 | checkCopyLocksRange(f, node) 30 | case *ast.FuncDecl: 31 | checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type) 32 | case *ast.FuncLit: 33 | checkCopyLocksFunc(f, "func", nil, node.Type) 34 | case *ast.CallExpr: 35 | checkCopyLocksCallExpr(f, node) 36 | case *ast.AssignStmt: 37 | checkCopyLocksAssign(f, node) 38 | case *ast.GenDecl: 39 | checkCopyLocksGenDecl(f, node) 40 | case *ast.CompositeLit: 41 | checkCopyLocksCompositeLit(f, node) 42 | case *ast.ReturnStmt: 43 | checkCopyLocksReturnStmt(f, node) 44 | } 45 | } 46 | 47 | // checkCopyLocksAssign checks whether an assignment 48 | // copies a lock. 49 | func checkCopyLocksAssign(f *File, as *ast.AssignStmt) { 50 | for i, x := range as.Rhs { 51 | if path := lockPathRhs(f, x); path != nil { 52 | f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path) 53 | } 54 | } 55 | } 56 | 57 | // checkCopyLocksGenDecl checks whether lock is copied 58 | // in variable declaration. 59 | func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) { 60 | if gd.Tok != token.VAR { 61 | return 62 | } 63 | for _, spec := range gd.Specs { 64 | valueSpec := spec.(*ast.ValueSpec) 65 | for i, x := range valueSpec.Values { 66 | if path := lockPathRhs(f, x); path != nil { 67 | f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path) 68 | } 69 | } 70 | } 71 | } 72 | 73 | // checkCopyLocksCompositeLit detects lock copy inside a composite literal 74 | func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) { 75 | for _, x := range cl.Elts { 76 | if node, ok := x.(*ast.KeyValueExpr); ok { 77 | x = node.Value 78 | } 79 | if path := lockPathRhs(f, x); path != nil { 80 | f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path) 81 | } 82 | } 83 | } 84 | 85 | // checkCopyLocksReturnStmt detects lock copy in return statement 86 | func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) { 87 | for _, x := range rs.Results { 88 | if path := lockPathRhs(f, x); path != nil { 89 | f.Badf(x.Pos(), "return copies lock value: %v", path) 90 | } 91 | } 92 | } 93 | 94 | // checkCopyLocksCallExpr detects lock copy in the arguments to a function call 95 | func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) { 96 | var id *ast.Ident 97 | switch fun := ce.Fun.(type) { 98 | case *ast.Ident: 99 | id = fun 100 | case *ast.SelectorExpr: 101 | id = fun.Sel 102 | } 103 | if fun, ok := f.pkg.uses[id].(*types.Builtin); ok { 104 | switch fun.Name() { 105 | case "new", "len", "cap", "Sizeof": 106 | return 107 | } 108 | } 109 | for _, x := range ce.Args { 110 | if path := lockPathRhs(f, x); path != nil { 111 | f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path) 112 | } 113 | } 114 | } 115 | 116 | // checkCopyLocksFunc checks whether a function might 117 | // inadvertently copy a lock, by checking whether 118 | // its receiver, parameters, or return values 119 | // are locks. 120 | func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) { 121 | if recv != nil && len(recv.List) > 0 { 122 | expr := recv.List[0].Type 123 | if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil { 124 | f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path) 125 | } 126 | } 127 | 128 | if typ.Params != nil { 129 | for _, field := range typ.Params.List { 130 | expr := field.Type 131 | if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil { 132 | f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path) 133 | } 134 | } 135 | } 136 | 137 | // Don't check typ.Results. If T has a Lock field it's OK to write 138 | // return T{} 139 | // because that is returning the zero value. Leave result checking 140 | // to the return statement. 141 | } 142 | 143 | // checkCopyLocksRange checks whether a range statement 144 | // might inadvertently copy a lock by checking whether 145 | // any of the range variables are locks. 146 | func checkCopyLocksRange(f *File, r *ast.RangeStmt) { 147 | checkCopyLocksRangeVar(f, r.Tok, r.Key) 148 | checkCopyLocksRangeVar(f, r.Tok, r.Value) 149 | } 150 | 151 | func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) { 152 | if e == nil { 153 | return 154 | } 155 | id, isId := e.(*ast.Ident) 156 | if isId && id.Name == "_" { 157 | return 158 | } 159 | 160 | var typ types.Type 161 | if rtok == token.DEFINE { 162 | if !isId { 163 | return 164 | } 165 | obj := f.pkg.defs[id] 166 | if obj == nil { 167 | return 168 | } 169 | typ = obj.Type() 170 | } else { 171 | typ = f.pkg.types[e].Type 172 | } 173 | 174 | if typ == nil { 175 | return 176 | } 177 | if path := lockPath(f.pkg.typesPkg, typ); path != nil { 178 | f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path) 179 | } 180 | } 181 | 182 | type typePath []types.Type 183 | 184 | // String pretty-prints a typePath. 185 | func (path typePath) String() string { 186 | n := len(path) 187 | var buf bytes.Buffer 188 | for i := range path { 189 | if i > 0 { 190 | fmt.Fprint(&buf, " contains ") 191 | } 192 | // The human-readable path is in reverse order, outermost to innermost. 193 | fmt.Fprint(&buf, path[n-i-1].String()) 194 | } 195 | return buf.String() 196 | } 197 | 198 | func lockPathRhs(f *File, x ast.Expr) typePath { 199 | if _, ok := x.(*ast.CompositeLit); ok { 200 | return nil 201 | } 202 | if _, ok := x.(*ast.CallExpr); ok { 203 | // A call may return a zero value. 204 | return nil 205 | } 206 | if star, ok := x.(*ast.StarExpr); ok { 207 | if _, ok := star.X.(*ast.CallExpr); ok { 208 | // A call may return a pointer to a zero value. 209 | return nil 210 | } 211 | } 212 | return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type) 213 | } 214 | 215 | // lockPath returns a typePath describing the location of a lock value 216 | // contained in typ. If there is no contained lock, it returns nil. 217 | func lockPath(tpkg *types.Package, typ types.Type) typePath { 218 | if typ == nil { 219 | return nil 220 | } 221 | 222 | for { 223 | atyp, ok := typ.Underlying().(*types.Array) 224 | if !ok { 225 | break 226 | } 227 | typ = atyp.Elem() 228 | } 229 | 230 | // We're only interested in the case in which the underlying 231 | // type is a struct. (Interfaces and pointers are safe to copy.) 232 | styp, ok := typ.Underlying().(*types.Struct) 233 | if !ok { 234 | return nil 235 | } 236 | 237 | // We're looking for cases in which a reference to this type 238 | // can be locked, but a value cannot. This differentiates 239 | // embedded interfaces from embedded values. 240 | if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil { 241 | if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil { 242 | return []types.Type{typ} 243 | } 244 | } 245 | 246 | nfields := styp.NumFields() 247 | for i := 0; i < nfields; i++ { 248 | ftyp := styp.Field(i).Type() 249 | subpath := lockPath(tpkg, ftyp) 250 | if subpath != nil { 251 | return append(subpath, typ) 252 | } 253 | } 254 | 255 | return nil 256 | } 257 | -------------------------------------------------------------------------------- /shadow.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | This file contains the code to check for shadowed variables. 7 | A shadowed variable is a variable declared in an inner scope 8 | with the same name and type as a variable in an outer scope, 9 | and where the outer variable is mentioned after the inner one 10 | is declared. 11 | 12 | (This definition can be refined; the module generates too many 13 | false positives and is not yet enabled by default.) 14 | 15 | For example: 16 | 17 | func BadRead(f *os.File, buf []byte) error { 18 | var err error 19 | for { 20 | n, err := f.Read(buf) // shadows the function variable 'err' 21 | if err != nil { 22 | break // causes return of wrong value 23 | } 24 | foo(buf) 25 | } 26 | return err 27 | } 28 | 29 | */ 30 | 31 | package govet 32 | 33 | import ( 34 | "flag" 35 | "go/ast" 36 | "go/token" 37 | "go/types" 38 | ) 39 | 40 | var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy") 41 | 42 | func init() { 43 | register("shadow", 44 | "check for shadowed variables (experimental; must be set explicitly)", 45 | checkShadow, 46 | assignStmt, genDecl) 47 | experimental["shadow"] = true 48 | } 49 | 50 | func checkShadow(f *File, node ast.Node) { 51 | switch n := node.(type) { 52 | case *ast.AssignStmt: 53 | checkShadowAssignment(f, n) 54 | case *ast.GenDecl: 55 | checkShadowDecl(f, n) 56 | } 57 | } 58 | 59 | // Span stores the minimum range of byte positions in the file in which a 60 | // given variable (types.Object) is mentioned. It is lexically defined: it spans 61 | // from the beginning of its first mention to the end of its last mention. 62 | // A variable is considered shadowed (if *strictShadowing is off) only if the 63 | // shadowing variable is declared within the span of the shadowed variable. 64 | // In other words, if a variable is shadowed but not used after the shadowed 65 | // variable is declared, it is inconsequential and not worth complaining about. 66 | // This simple check dramatically reduces the nuisance rate for the shadowing 67 | // check, at least until something cleverer comes along. 68 | // 69 | // One wrinkle: A "naked return" is a silent use of a variable that the Span 70 | // will not capture, but the compilers catch naked returns of shadowed 71 | // variables so we don't need to. 72 | // 73 | // Cases this gets wrong (TODO): 74 | // - If a for loop's continuation statement mentions a variable redeclared in 75 | // the block, we should complain about it but don't. 76 | // - A variable declared inside a function literal can falsely be identified 77 | // as shadowing a variable in the outer function. 78 | // 79 | type Span struct { 80 | min token.Pos 81 | max token.Pos 82 | } 83 | 84 | // contains reports whether the position is inside the span. 85 | func (s Span) contains(pos token.Pos) bool { 86 | return s.min <= pos && pos < s.max 87 | } 88 | 89 | // growSpan expands the span for the object to contain the instance represented 90 | // by the identifier. 91 | func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) { 92 | if *strictShadowing { 93 | return // No need 94 | } 95 | pos := ident.Pos() 96 | end := ident.End() 97 | span, ok := pkg.spans[obj] 98 | if ok { 99 | if span.min > pos { 100 | span.min = pos 101 | } 102 | if span.max < end { 103 | span.max = end 104 | } 105 | } else { 106 | span = Span{pos, end} 107 | } 108 | pkg.spans[obj] = span 109 | } 110 | 111 | // checkShadowAssignment checks for shadowing in a short variable declaration. 112 | func checkShadowAssignment(f *File, a *ast.AssignStmt) { 113 | if a.Tok != token.DEFINE { 114 | return 115 | } 116 | if f.idiomaticShortRedecl(a) { 117 | return 118 | } 119 | for _, expr := range a.Lhs { 120 | ident, ok := expr.(*ast.Ident) 121 | if !ok { 122 | f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier") 123 | return 124 | } 125 | checkShadowing(f, ident) 126 | } 127 | } 128 | 129 | // idiomaticShortRedecl reports whether this short declaration can be ignored for 130 | // the purposes of shadowing, that is, that any redeclarations it contains are deliberate. 131 | func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool { 132 | // Don't complain about deliberate redeclarations of the form 133 | // i := i 134 | // Such constructs are idiomatic in range loops to create a new variable 135 | // for each iteration. Another example is 136 | // switch n := n.(type) 137 | if len(a.Rhs) != len(a.Lhs) { 138 | return false 139 | } 140 | // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.) 141 | for i, expr := range a.Lhs { 142 | lhs, ok := expr.(*ast.Ident) 143 | if !ok { 144 | f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier") 145 | return true // Don't do any more processing. 146 | } 147 | switch rhs := a.Rhs[i].(type) { 148 | case *ast.Ident: 149 | if lhs.Name != rhs.Name { 150 | return false 151 | } 152 | case *ast.TypeAssertExpr: 153 | if id, ok := rhs.X.(*ast.Ident); ok { 154 | if lhs.Name != id.Name { 155 | return false 156 | } 157 | } 158 | default: 159 | return false 160 | } 161 | } 162 | return true 163 | } 164 | 165 | // idiomaticRedecl reports whether this declaration spec can be ignored for 166 | // the purposes of shadowing, that is, that any redeclarations it contains are deliberate. 167 | func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool { 168 | // Don't complain about deliberate redeclarations of the form 169 | // var i, j = i, j 170 | if len(d.Names) != len(d.Values) { 171 | return false 172 | } 173 | for i, lhs := range d.Names { 174 | if rhs, ok := d.Values[i].(*ast.Ident); ok { 175 | if lhs.Name != rhs.Name { 176 | return false 177 | } 178 | } 179 | } 180 | return true 181 | } 182 | 183 | // checkShadowDecl checks for shadowing in a general variable declaration. 184 | func checkShadowDecl(f *File, d *ast.GenDecl) { 185 | if d.Tok != token.VAR { 186 | return 187 | } 188 | for _, spec := range d.Specs { 189 | valueSpec, ok := spec.(*ast.ValueSpec) 190 | if !ok { 191 | f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec") 192 | return 193 | } 194 | // Don't complain about deliberate redeclarations of the form 195 | // var i = i 196 | if f.idiomaticRedecl(valueSpec) { 197 | return 198 | } 199 | for _, ident := range valueSpec.Names { 200 | checkShadowing(f, ident) 201 | } 202 | } 203 | } 204 | 205 | // checkShadowing checks whether the identifier shadows an identifier in an outer scope. 206 | func checkShadowing(f *File, ident *ast.Ident) { 207 | if ident.Name == "_" { 208 | // Can't shadow the blank identifier. 209 | return 210 | } 211 | obj := f.pkg.defs[ident] 212 | if obj == nil { 213 | return 214 | } 215 | // obj.Parent.Parent is the surrounding scope. If we can find another declaration 216 | // starting from there, we have a shadowed identifier. 217 | _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos()) 218 | if shadowed == nil { 219 | return 220 | } 221 | // Don't complain if it's shadowing a universe-declared identifier; that's fine. 222 | if shadowed.Parent() == types.Universe { 223 | return 224 | } 225 | if *strictShadowing { 226 | // The shadowed identifier must appear before this one to be an instance of shadowing. 227 | if shadowed.Pos() > ident.Pos() { 228 | return 229 | } 230 | } else { 231 | // Don't complain if the span of validity of the shadowed identifier doesn't include 232 | // the shadowing identifier. 233 | span, ok := f.pkg.spans[shadowed] 234 | if !ok { 235 | f.Badf(ident.Pos(), "internal error: no range for %q", ident.Name) 236 | return 237 | } 238 | if !span.contains(ident.Pos()) { 239 | return 240 | } 241 | } 242 | // Don't complain if the types differ: that implies the programmer really wants two different things. 243 | if types.Identical(obj.Type(), shadowed.Type()) { 244 | f.Badf(ident.Pos(), "declaration of %q shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos())) 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /deadcode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Check for syntactically unreachable code. 6 | 7 | package govet 8 | 9 | import ( 10 | "go/ast" 11 | "go/token" 12 | ) 13 | 14 | func init() { 15 | register("unreachable", 16 | "check for unreachable code", 17 | checkUnreachable, 18 | funcDecl, funcLit) 19 | } 20 | 21 | type deadState struct { 22 | f *File 23 | hasBreak map[ast.Stmt]bool 24 | hasGoto map[string]bool 25 | labels map[string]ast.Stmt 26 | breakTarget ast.Stmt 27 | 28 | reachable bool 29 | } 30 | 31 | // checkUnreachable checks a function body for dead code. 32 | // 33 | // TODO(adonovan): use the new cfg package, which is more precise. 34 | func checkUnreachable(f *File, node ast.Node) { 35 | var body *ast.BlockStmt 36 | switch n := node.(type) { 37 | case *ast.FuncDecl: 38 | body = n.Body 39 | case *ast.FuncLit: 40 | body = n.Body 41 | } 42 | if body == nil { 43 | return 44 | } 45 | 46 | d := &deadState{ 47 | f: f, 48 | hasBreak: make(map[ast.Stmt]bool), 49 | hasGoto: make(map[string]bool), 50 | labels: make(map[string]ast.Stmt), 51 | } 52 | 53 | d.findLabels(body) 54 | 55 | d.reachable = true 56 | d.findDead(body) 57 | } 58 | 59 | // findLabels gathers information about the labels defined and used by stmt 60 | // and about which statements break, whether a label is involved or not. 61 | func (d *deadState) findLabels(stmt ast.Stmt) { 62 | switch x := stmt.(type) { 63 | default: 64 | d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x) 65 | 66 | case *ast.AssignStmt, 67 | *ast.BadStmt, 68 | *ast.DeclStmt, 69 | *ast.DeferStmt, 70 | *ast.EmptyStmt, 71 | *ast.ExprStmt, 72 | *ast.GoStmt, 73 | *ast.IncDecStmt, 74 | *ast.ReturnStmt, 75 | *ast.SendStmt: 76 | // no statements inside 77 | 78 | case *ast.BlockStmt: 79 | for _, stmt := range x.List { 80 | d.findLabels(stmt) 81 | } 82 | 83 | case *ast.BranchStmt: 84 | switch x.Tok { 85 | case token.GOTO: 86 | if x.Label != nil { 87 | d.hasGoto[x.Label.Name] = true 88 | } 89 | 90 | case token.BREAK: 91 | stmt := d.breakTarget 92 | if x.Label != nil { 93 | stmt = d.labels[x.Label.Name] 94 | } 95 | if stmt != nil { 96 | d.hasBreak[stmt] = true 97 | } 98 | } 99 | 100 | case *ast.IfStmt: 101 | d.findLabels(x.Body) 102 | if x.Else != nil { 103 | d.findLabels(x.Else) 104 | } 105 | 106 | case *ast.LabeledStmt: 107 | d.labels[x.Label.Name] = x.Stmt 108 | d.findLabels(x.Stmt) 109 | 110 | // These cases are all the same, but the x.Body only works 111 | // when the specific type of x is known, so the cases cannot 112 | // be merged. 113 | case *ast.ForStmt: 114 | outer := d.breakTarget 115 | d.breakTarget = x 116 | d.findLabels(x.Body) 117 | d.breakTarget = outer 118 | 119 | case *ast.RangeStmt: 120 | outer := d.breakTarget 121 | d.breakTarget = x 122 | d.findLabels(x.Body) 123 | d.breakTarget = outer 124 | 125 | case *ast.SelectStmt: 126 | outer := d.breakTarget 127 | d.breakTarget = x 128 | d.findLabels(x.Body) 129 | d.breakTarget = outer 130 | 131 | case *ast.SwitchStmt: 132 | outer := d.breakTarget 133 | d.breakTarget = x 134 | d.findLabels(x.Body) 135 | d.breakTarget = outer 136 | 137 | case *ast.TypeSwitchStmt: 138 | outer := d.breakTarget 139 | d.breakTarget = x 140 | d.findLabels(x.Body) 141 | d.breakTarget = outer 142 | 143 | case *ast.CommClause: 144 | for _, stmt := range x.Body { 145 | d.findLabels(stmt) 146 | } 147 | 148 | case *ast.CaseClause: 149 | for _, stmt := range x.Body { 150 | d.findLabels(stmt) 151 | } 152 | } 153 | } 154 | 155 | // findDead walks the statement looking for dead code. 156 | // If d.reachable is false on entry, stmt itself is dead. 157 | // When findDead returns, d.reachable tells whether the 158 | // statement following stmt is reachable. 159 | func (d *deadState) findDead(stmt ast.Stmt) { 160 | // Is this a labeled goto target? 161 | // If so, assume it is reachable due to the goto. 162 | // This is slightly conservative, in that we don't 163 | // check that the goto is reachable, so 164 | // L: goto L 165 | // will not provoke a warning. 166 | // But it's good enough. 167 | if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] { 168 | d.reachable = true 169 | } 170 | 171 | if !d.reachable { 172 | switch stmt.(type) { 173 | case *ast.EmptyStmt: 174 | // do not warn about unreachable empty statements 175 | default: 176 | d.f.Bad(stmt.Pos(), "unreachable code") 177 | d.reachable = true // silence error about next statement 178 | } 179 | } 180 | 181 | switch x := stmt.(type) { 182 | default: 183 | d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x) 184 | 185 | case *ast.AssignStmt, 186 | *ast.BadStmt, 187 | *ast.DeclStmt, 188 | *ast.DeferStmt, 189 | *ast.EmptyStmt, 190 | *ast.GoStmt, 191 | *ast.IncDecStmt, 192 | *ast.SendStmt: 193 | // no control flow 194 | 195 | case *ast.BlockStmt: 196 | for _, stmt := range x.List { 197 | d.findDead(stmt) 198 | } 199 | 200 | case *ast.BranchStmt: 201 | switch x.Tok { 202 | case token.BREAK, token.GOTO, token.FALLTHROUGH: 203 | d.reachable = false 204 | case token.CONTINUE: 205 | // NOTE: We accept "continue" statements as terminating. 206 | // They are not necessary in the spec definition of terminating, 207 | // because a continue statement cannot be the final statement 208 | // before a return. But for the more general problem of syntactically 209 | // identifying dead code, continue redirects control flow just 210 | // like the other terminating statements. 211 | d.reachable = false 212 | } 213 | 214 | case *ast.ExprStmt: 215 | // Call to panic? 216 | call, ok := x.X.(*ast.CallExpr) 217 | if ok { 218 | name, ok := call.Fun.(*ast.Ident) 219 | if ok && name.Name == "panic" && name.Obj == nil { 220 | d.reachable = false 221 | } 222 | } 223 | 224 | case *ast.ForStmt: 225 | d.findDead(x.Body) 226 | d.reachable = x.Cond != nil || d.hasBreak[x] 227 | 228 | case *ast.IfStmt: 229 | d.findDead(x.Body) 230 | if x.Else != nil { 231 | r := d.reachable 232 | d.reachable = true 233 | d.findDead(x.Else) 234 | d.reachable = d.reachable || r 235 | } else { 236 | // might not have executed if statement 237 | d.reachable = true 238 | } 239 | 240 | case *ast.LabeledStmt: 241 | d.findDead(x.Stmt) 242 | 243 | case *ast.RangeStmt: 244 | d.findDead(x.Body) 245 | d.reachable = true 246 | 247 | case *ast.ReturnStmt: 248 | d.reachable = false 249 | 250 | case *ast.SelectStmt: 251 | // NOTE: Unlike switch and type switch below, we don't care 252 | // whether a select has a default, because a select without a 253 | // default blocks until one of the cases can run. That's different 254 | // from a switch without a default, which behaves like it has 255 | // a default with an empty body. 256 | anyReachable := false 257 | for _, comm := range x.Body.List { 258 | d.reachable = true 259 | for _, stmt := range comm.(*ast.CommClause).Body { 260 | d.findDead(stmt) 261 | } 262 | anyReachable = anyReachable || d.reachable 263 | } 264 | d.reachable = anyReachable || d.hasBreak[x] 265 | 266 | case *ast.SwitchStmt: 267 | anyReachable := false 268 | hasDefault := false 269 | for _, cas := range x.Body.List { 270 | cc := cas.(*ast.CaseClause) 271 | if cc.List == nil { 272 | hasDefault = true 273 | } 274 | d.reachable = true 275 | for _, stmt := range cc.Body { 276 | d.findDead(stmt) 277 | } 278 | anyReachable = anyReachable || d.reachable 279 | } 280 | d.reachable = anyReachable || d.hasBreak[x] || !hasDefault 281 | 282 | case *ast.TypeSwitchStmt: 283 | anyReachable := false 284 | hasDefault := false 285 | for _, cas := range x.Body.List { 286 | cc := cas.(*ast.CaseClause) 287 | if cc.List == nil { 288 | hasDefault = true 289 | } 290 | d.reachable = true 291 | for _, stmt := range cc.Body { 292 | d.findDead(stmt) 293 | } 294 | anyReachable = anyReachable || d.reachable 295 | } 296 | d.reachable = anyReachable || d.hasBreak[x] || !hasDefault 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /all/whitelist/all.txt: -------------------------------------------------------------------------------- 1 | // Non-platform-specific vet whitelist. See readme.txt for details. 2 | 3 | // Real problems that we can't fix. 4 | 5 | // This is a bad WriteTo signature. Errors are being ignored! 6 | // However, we can't change it due to the Go 1 compatibility promise. 7 | go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have signature WriteTo(io.Writer) (int64, error) 8 | 9 | 10 | // False positives. 11 | 12 | // Nothing much to do about cross-package assembly. Unfortunate. 13 | runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: call is in package reflect 14 | internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Equal is in package bytes 15 | internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal is in package runtime 16 | internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal_varlen is in package runtime 17 | internal/bytealg/indexbyte_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package bytes 18 | internal/bytealg/indexbyte_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package strings 19 | 20 | // The write barrier is called directly by the compiler, so no Go def 21 | runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing Go declaration 22 | 23 | // Legitimate vet complaints in which we are testing for correct runtime behavior 24 | // in bad situations that vet can also detect statically. 25 | encoding/json/decode_test.go: struct field m has json tag but is not exported 26 | encoding/json/decode_test.go: struct field m2 has json tag but is not exported 27 | encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key 28 | runtime/testdata/testprog/deadlock.go: unreachable code 29 | runtime/testdata/testprog/deadlock.go: unreachable code 30 | 31 | // Non-standard method signatures. 32 | // These cases are basically ok. 33 | // Errors are handled reasonably and there's no clear need for interface satisfaction. 34 | // Except for the runtime/pprof case, the API is not exported. 35 | cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error) 36 | cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error) 37 | fmt/print.go: method WriteByte(c byte) should have signature WriteByte(byte) error 38 | runtime/pprof/pprof.go: method WriteTo(w io.Writer, debug int) error should have signature WriteTo(io.Writer) (int64, error) 39 | 40 | // These encoding/xml methods have the correct signature. 41 | // vet doesn't know it because they are *in* the encoding/xml package. 42 | // It's not worth teaching vet about the distinction, so whitelist them. 43 | encoding/gob/encode.go: method WriteByte(c byte) should have signature WriteByte(byte) error 44 | encoding/xml/marshal.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error 45 | encoding/xml/marshal_test.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error 46 | encoding/xml/read.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error 47 | encoding/xml/read_test.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error 48 | encoding/xml/xml_test.go: method UnmarshalXML(*Decoder, StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error 49 | 50 | // Long struct tags used to test reflect internals 51 | cmd/link/link_test.go: struct field tag "\n\tLondon. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning, one might imagine, for the death of the sun. Dogs, undistinguishable in mire. Horses, scarcely better; splashed to their very blinkers. Foot passengers, jostling one another’s umbrellas in a general infection of ill temper, and losing their foot-hold at street-corners, where tens of thousands of other foot passengers have been slipping and sliding since the day broke (if this day ever broke), adding new deposits to the crust upon crust of mud, sticking at those points tenaciously to the pavement, and accumulating at compound interest.\n\n\tFog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pensioners, wheezing by the firesides of their wards; fog in the stem and bowl of the afternoon pipe of the wrathful skipper, down in his close cabin; fog cruelly pinching the toes and fingers of his shivering little ‘prentice boy on deck. Chance people on the bridges peeping over the parapets into a nether sky of fog, with fog all round them, as if they were up in a balloon and hanging in the misty clouds.\n\n\tGas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look.\n\n\tThe raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery." not compatible with reflect.StructTag.Get: bad syntax for struct tag key 52 | cmd/link/link_test.go: struct field tag "\n\tIt was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again." not compatible with reflect.StructTag.Get: bad syntax for struct tag key 53 | cmd/link/link_test.go: struct field tag "\n\tJarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless." not compatible with reflect.StructTag.Get: bad syntax for struct tag key 54 | cmd/link/link_test.go: struct field tag "\n\tThe one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble." not compatible with reflect.StructTag.Get: bad syntax for struct tag key 55 | -------------------------------------------------------------------------------- /testdata/asm8.s: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build mipsle 6 | // +build vet_test 7 | 8 | TEXT ·arg1(SB),0,$0-2 9 | MOVB x+0(FP), R1 10 | MOVBU y+1(FP), R2 11 | MOVH x+0(FP), R1 // ERROR "\[mipsle\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" 12 | MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value" 13 | MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" 14 | MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value" 15 | MOVW y+1(FP), R1 // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value" 16 | MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" 17 | MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" 18 | MOVB 8(R29), R1 // ERROR "8\(R29\) should be x\+0\(FP\)" 19 | MOVB 9(R29), R1 // ERROR "9\(R29\) should be y\+1\(FP\)" 20 | MOVB 10(R29), R1 // ERROR "use of 10\(R29\) points beyond argument frame" 21 | RET 22 | 23 | TEXT ·arg2(SB),0,$0-4 24 | MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value" 25 | MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" 26 | MOVHU x+0(FP), R1 27 | MOVH y+2(FP), R2 28 | MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value" 29 | MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" 30 | MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" 31 | MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" 32 | RET 33 | 34 | TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" 35 | MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" 36 | MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" 37 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" 38 | MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" 39 | MOVW x+0(FP), R1 40 | MOVW y+4(FP), R1 41 | MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" 42 | MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" 43 | RET 44 | 45 | TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" 46 | MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" 47 | MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" 48 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" 49 | MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" 50 | MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)" 51 | MOVW x_lo+0(FP), R1 52 | MOVW x_hi+4(FP), R1 53 | MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)" 54 | MOVW y_lo+8(FP), R1 55 | MOVW y_hi+12(FP), R1 56 | RET 57 | 58 | TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8" 59 | MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value" 60 | MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value" 61 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value" 62 | MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value" 63 | MOVW x+0(FP), R1 64 | MOVW y+4(FP), R1 65 | MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" 66 | MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" 67 | RET 68 | 69 | TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20" 70 | MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value" 71 | MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value" 72 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value" 73 | MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value" 74 | MOVW x+0(FP), R1 75 | MOVW y+4(FP), R1 76 | MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" 77 | MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" 78 | MOVH c+8(FP), R1 // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value" 79 | MOVH m+12(FP), R1 // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value" 80 | MOVH f+16(FP), R1 // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value" 81 | RET 82 | 83 | TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16" 84 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value" 85 | MOVW x+0(FP), R1 86 | MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value" 87 | MOVW x_base+0(FP), R1 88 | MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" 89 | MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" 90 | MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value" 91 | MOVW x_len+4(FP), R1 92 | MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)" 93 | MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)" 94 | RET 95 | 96 | TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24" 97 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value" 98 | MOVW x+0(FP), R1 99 | MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value" 100 | MOVW x_base+0(FP), R1 101 | MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" 102 | MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" 103 | MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value" 104 | MOVW x_len+4(FP), R1 105 | MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" 106 | MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" 107 | MOVH x_cap+8(FP), R1 // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value" 108 | MOVW x_cap+8(FP), R1 109 | MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)" 110 | MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)" 111 | MOVW y_cap+8(FP), R1 // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)" 112 | RET 113 | 114 | TEXT ·argiface(SB),0,$0-16 115 | MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value" 116 | MOVW x+0(FP), R1 117 | MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value" 118 | MOVW x_type+0(FP), R1 119 | MOVQ x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" 120 | MOVQ x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" 121 | MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" 122 | MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" 123 | MOVQ x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" 124 | MOVH x_data+4(FP), R1 // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value" 125 | MOVW x_data+4(FP), R1 126 | MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value" 127 | MOVW y+8(FP), R1 128 | MOVH y_itable+8(FP), R1 // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value" 129 | MOVW y_itable+8(FP), R1 130 | MOVW y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)" 131 | MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" 132 | MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" 133 | MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value" 134 | MOVW y_data+12(FP), AX 135 | RET 136 | 137 | TEXT ·returnbyte(SB),0,$0-5 138 | MOVW x+0(FP), R1 139 | MOVB R1, ret+4(FP) 140 | MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value" 141 | MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" 142 | MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" 143 | RET 144 | 145 | TEXT ·returnbyte(SB),0,$0-5 146 | MOVW x+0(FP), R1 147 | MOVB R1, ret+4(FP) 148 | MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value" 149 | MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" 150 | MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" 151 | RET 152 | 153 | TEXT ·returnnamed(SB),0,$0-21 154 | MOVB x+0(FP), AX 155 | MOVW R1, r1+4(FP) 156 | MOVH R1, r2+8(FP) 157 | MOVW R1, r3+12(FP) 158 | MOVW R1, r3_base+12(FP) 159 | MOVW R1, r3_len+16(FP) 160 | MOVB R1, r4+20(FP) 161 | MOVB R1, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value" 162 | RET 163 | 164 | TEXT ·returnintmissing(SB),0,$0-4 165 | RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)" 166 | --------------------------------------------------------------------------------