1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:54:57 -07:00

go/analysis/passes/copylock: split out of vet

Change-Id: Ib7c735e714d8b5436d055bf99ca90e840c963c7b
Reviewed-on: https://go-review.googlesource.com/c/140740
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Alan Donovan 2018-10-08 20:53:19 -04:00
parent a2b3f7f249
commit 6d96510a3a
8 changed files with 366 additions and 336 deletions

View File

@ -135,9 +135,11 @@ func loadPackage(dir, pkgpath string) (*packages.Package, error) {
if err != nil {
return nil, err
}
if packages.PrintErrors(pkgs) > 0 {
return nil, fmt.Errorf("loading %s failed", pkgpath)
}
// Print errors but do not stop:
// some Analyzers may be disposed to RunDespiteErrors
packages.PrintErrors(pkgs)
if len(pkgs) != 1 {
return nil, fmt.Errorf("pattern %q expanded to %d packages, want 1",
pkgpath, len(pkgs))

View File

@ -1,12 +1,8 @@
// +build ignore
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains the code to check that locks are not passed by value.
package main
package copylock
import (
"bytes"
@ -14,87 +10,106 @@ import (
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
)
func init() {
register("copylocks",
"check that locks are not passed by value",
checkCopyLocks,
funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt)
var Analyzer = &analysis.Analyzer{
Name: "copylocks",
Doc: "check for locks erroneously passed by value",
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
Run: run,
}
// checkCopyLocks checks whether node might
// inadvertently copy a lock.
func checkCopyLocks(f *File, node ast.Node) {
switch node := node.(type) {
case *ast.RangeStmt:
checkCopyLocksRange(f, node)
case *ast.FuncDecl:
checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type)
case *ast.FuncLit:
checkCopyLocksFunc(f, "func", nil, node.Type)
case *ast.CallExpr:
checkCopyLocksCallExpr(f, node)
case *ast.AssignStmt:
checkCopyLocksAssign(f, node)
case *ast.GenDecl:
checkCopyLocksGenDecl(f, node)
case *ast.CompositeLit:
checkCopyLocksCompositeLit(f, node)
case *ast.ReturnStmt:
checkCopyLocksReturnStmt(f, node)
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.AssignStmt)(nil),
(*ast.CallExpr)(nil),
(*ast.CompositeLit)(nil),
(*ast.FuncDecl)(nil),
(*ast.FuncLit)(nil),
(*ast.GenDecl)(nil),
(*ast.RangeStmt)(nil),
(*ast.ReturnStmt)(nil),
}
inspect.Preorder(nodeFilter, func(node ast.Node) {
switch node := node.(type) {
case *ast.RangeStmt:
checkCopyLocksRange(pass, node)
case *ast.FuncDecl:
checkCopyLocksFunc(pass, node.Name.Name, node.Recv, node.Type)
case *ast.FuncLit:
checkCopyLocksFunc(pass, "func", nil, node.Type)
case *ast.CallExpr:
checkCopyLocksCallExpr(pass, node)
case *ast.AssignStmt:
checkCopyLocksAssign(pass, node)
case *ast.GenDecl:
checkCopyLocksGenDecl(pass, node)
case *ast.CompositeLit:
checkCopyLocksCompositeLit(pass, node)
case *ast.ReturnStmt:
checkCopyLocksReturnStmt(pass, node)
}
})
return nil, nil
}
// checkCopyLocksAssign checks whether an assignment
// copies a lock.
func checkCopyLocksAssign(f *File, as *ast.AssignStmt) {
func checkCopyLocksAssign(pass *analysis.Pass, as *ast.AssignStmt) {
for i, x := range as.Rhs {
if path := lockPathRhs(f, x); path != nil {
f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path)
if path := lockPathRhs(pass, x); path != nil {
pass.Reportf(x.Pos(), "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, as.Lhs[i]), path)
}
}
}
// checkCopyLocksGenDecl checks whether lock is copied
// in variable declaration.
func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) {
func checkCopyLocksGenDecl(pass *analysis.Pass, gd *ast.GenDecl) {
if gd.Tok != token.VAR {
return
}
for _, spec := range gd.Specs {
valueSpec := spec.(*ast.ValueSpec)
for i, x := range valueSpec.Values {
if path := lockPathRhs(f, x); path != nil {
f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
if path := lockPathRhs(pass, x); path != nil {
pass.Reportf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
}
}
}
}
// checkCopyLocksCompositeLit detects lock copy inside a composite literal
func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) {
func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) {
for _, x := range cl.Elts {
if node, ok := x.(*ast.KeyValueExpr); ok {
x = node.Value
}
if path := lockPathRhs(f, x); path != nil {
f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path)
if path := lockPathRhs(pass, x); path != nil {
pass.Reportf(x.Pos(), "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path)
}
}
}
// checkCopyLocksReturnStmt detects lock copy in return statement
func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
func checkCopyLocksReturnStmt(pass *analysis.Pass, rs *ast.ReturnStmt) {
for _, x := range rs.Results {
if path := lockPathRhs(f, x); path != nil {
f.Badf(x.Pos(), "return copies lock value: %v", path)
if path := lockPathRhs(pass, x); path != nil {
pass.Reportf(x.Pos(), "return copies lock value: %v", path)
}
}
}
// checkCopyLocksCallExpr detects lock copy in the arguments to a function call
func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) {
var id *ast.Ident
switch fun := ce.Fun.(type) {
case *ast.Ident:
@ -102,15 +117,15 @@ func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
case *ast.SelectorExpr:
id = fun.Sel
}
if fun, ok := f.pkg.uses[id].(*types.Builtin); ok {
if fun, ok := pass.TypesInfo.Uses[id].(*types.Builtin); ok {
switch fun.Name() {
case "new", "len", "cap", "Sizeof":
return
}
}
for _, x := range ce.Args {
if path := lockPathRhs(f, x); path != nil {
f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path)
if path := lockPathRhs(pass, x); path != nil {
pass.Reportf(x.Pos(), "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path)
}
}
}
@ -119,19 +134,19 @@ func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
// inadvertently copy a lock, by checking whether
// its receiver, parameters, or return values
// are locks.
func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) {
func checkCopyLocksFunc(pass *analysis.Pass, name string, recv *ast.FieldList, typ *ast.FuncType) {
if recv != nil && len(recv.List) > 0 {
expr := recv.List[0].Type
if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil {
pass.Reportf(expr.Pos(), "%s passes lock by value: %v", name, path)
}
}
if typ.Params != nil {
for _, field := range typ.Params.List {
expr := field.Type
if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil {
pass.Reportf(expr.Pos(), "%s passes lock by value: %v", name, path)
}
}
}
@ -145,12 +160,12 @@ func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.Func
// checkCopyLocksRange checks whether a range statement
// might inadvertently copy a lock by checking whether
// any of the range variables are locks.
func checkCopyLocksRange(f *File, r *ast.RangeStmt) {
checkCopyLocksRangeVar(f, r.Tok, r.Key)
checkCopyLocksRangeVar(f, r.Tok, r.Value)
func checkCopyLocksRange(pass *analysis.Pass, r *ast.RangeStmt) {
checkCopyLocksRangeVar(pass, r.Tok, r.Key)
checkCopyLocksRangeVar(pass, r.Tok, r.Value)
}
func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) {
if e == nil {
return
}
@ -164,20 +179,20 @@ func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
if !isId {
return
}
obj := f.pkg.defs[id]
obj := pass.TypesInfo.Defs[id]
if obj == nil {
return
}
typ = obj.Type()
} else {
typ = f.pkg.types[e].Type
typ = pass.TypesInfo.Types[e].Type
}
if typ == nil {
return
}
if path := lockPath(f.pkg.typesPkg, typ); path != nil {
f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path)
if path := lockPath(pass.Pkg, typ); path != nil {
pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisutil.Format(pass.Fset, e), path)
}
}
@ -197,7 +212,7 @@ func (path typePath) String() string {
return buf.String()
}
func lockPathRhs(f *File, x ast.Expr) typePath {
func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
if _, ok := x.(*ast.CompositeLit); ok {
return nil
}
@ -211,7 +226,7 @@ func lockPathRhs(f *File, x ast.Expr) typePath {
return nil
}
}
return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
return lockPath(pass.Pkg, pass.TypesInfo.Types[x].Type)
}
// lockPath returns a typePath describing the location of a lock value

View File

@ -0,0 +1,13 @@
package copylock_test
import (
"testing"
"golang.org/x/tools/go/analysis/analysistest"
"golang.org/x/tools/go/analysis/passes/copylock"
)
func TestFromFileSystem(t *testing.T) {
testdata := analysistest.TestData()
analysistest.Run(t, testdata, copylock.Analyzer, "a")
}

View File

@ -0,0 +1,188 @@
package a
import (
"sync"
"sync/atomic"
"unsafe"
. "unsafe"
unsafe1 "unsafe"
)
func OkFunc() {
var x *sync.Mutex
p := x
var y sync.Mutex
p = &y
var z = sync.Mutex{}
w := sync.Mutex{}
w = sync.Mutex{}
q := struct{ L sync.Mutex }{
L: sync.Mutex{},
}
yy := []Tlock{
Tlock{},
Tlock{
once: sync.Once{},
},
}
nl := new(sync.Mutex)
mx := make([]sync.Mutex, 10)
xx := struct{ L *sync.Mutex }{
L: new(sync.Mutex),
}
}
type Tlock struct {
once sync.Once
}
func BadFunc() {
var x *sync.Mutex
p := x
var y sync.Mutex
p = &y
*p = *x // want `assignment copies lock value to \*p: sync.Mutex`
var t Tlock
var tp *Tlock
tp = &t
*tp = t // want `assignment copies lock value to \*tp: a.Tlock contains sync.Once contains sync.Mutex`
t = *tp // want "assignment copies lock value to t: a.Tlock contains sync.Once contains sync.Mutex"
y := *x // want "assignment copies lock value to y: sync.Mutex"
var z = t // want "variable declaration copies lock value to z: a.Tlock contains sync.Once contains sync.Mutex"
w := struct{ L sync.Mutex }{
L: *x, // want `literal copies lock value from \*x: sync.Mutex`
}
var q = map[int]Tlock{
1: t, // want "literal copies lock value from t: a.Tlock contains sync.Once contains sync.Mutex"
2: *tp, // want `literal copies lock value from \*tp: a.Tlock contains sync.Once contains sync.Mutex`
}
yy := []Tlock{
t, // want "literal copies lock value from t: a.Tlock contains sync.Once contains sync.Mutex"
*tp, // want `literal copies lock value from \*tp: a.Tlock contains sync.Once contains sync.Mutex`
}
// override 'new' keyword
new := func(interface{}) {}
new(t) // want "call of new copies lock value: a.Tlock contains sync.Once contains sync.Mutex"
// copy of array of locks
var muA [5]sync.Mutex
muB := muA // want "assignment copies lock value to muB: sync.Mutex"
muA = muB // want "assignment copies lock value to muA: sync.Mutex"
muSlice := muA[:] // OK
// multidimensional array
var mmuA [5][5]sync.Mutex
mmuB := mmuA // want "assignment copies lock value to mmuB: sync.Mutex"
mmuA = mmuB // want "assignment copies lock value to mmuA: sync.Mutex"
mmuSlice := mmuA[:] // OK
// slice copy is ok
var fmuA [5][][5]sync.Mutex
fmuB := fmuA // OK
fmuA = fmuB // OK
fmuSlice := fmuA[:] // OK
}
func LenAndCapOnLockArrays() {
var a [5]sync.Mutex
aLen := len(a) // OK
aCap := cap(a) // OK
// override 'len' and 'cap' keywords
len := func(interface{}) {}
len(a) // want "call of len copies lock value: sync.Mutex"
cap := func(interface{}) {}
cap(a) // want "call of cap copies lock value: sync.Mutex"
}
func SizeofMutex() {
var mu sync.Mutex
unsafe.Sizeof(mu) // OK
unsafe1.Sizeof(mu) // OK
Sizeof(mu) // OK
unsafe := struct{ Sizeof func(interface{}) }{}
unsafe.Sizeof(mu) // want "call of unsafe.Sizeof copies lock value: sync.Mutex"
Sizeof := func(interface{}) {}
Sizeof(mu) // want "call of Sizeof copies lock value: sync.Mutex"
}
// SyncTypesCheck checks copying of sync.* types except sync.Mutex
func SyncTypesCheck() {
// sync.RWMutex copying
var rwmuX sync.RWMutex
var rwmuXX = sync.RWMutex{}
rwmuX1 := new(sync.RWMutex)
rwmuY := rwmuX // want "assignment copies lock value to rwmuY: sync.RWMutex"
rwmuY = rwmuX // want "assignment copies lock value to rwmuY: sync.RWMutex"
var rwmuYY = rwmuX // want "variable declaration copies lock value to rwmuYY: sync.RWMutex"
rwmuP := &rwmuX
rwmuZ := &sync.RWMutex{}
// sync.Cond copying
var condX sync.Cond
var condXX = sync.Cond{}
condX1 := new(sync.Cond)
condY := condX // want "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
condY = condX // want "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
var condYY = condX // want "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
condP := &condX
condZ := &sync.Cond{
L: &sync.Mutex{},
}
condZ = sync.NewCond(&sync.Mutex{})
// sync.WaitGroup copying
var wgX sync.WaitGroup
var wgXX = sync.WaitGroup{}
wgX1 := new(sync.WaitGroup)
wgY := wgX // want "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
wgY = wgX // want "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
var wgYY = wgX // want "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
wgP := &wgX
wgZ := &sync.WaitGroup{}
// sync.Pool copying
var poolX sync.Pool
var poolXX = sync.Pool{}
poolX1 := new(sync.Pool)
poolY := poolX // want "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
poolY = poolX // want "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
var poolYY = poolX // want "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
poolP := &poolX
poolZ := &sync.Pool{}
// sync.Once copying
var onceX sync.Once
var onceXX = sync.Once{}
onceX1 := new(sync.Once)
onceY := onceX // want "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
onceY = onceX // want "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
var onceYY = onceX // want "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
onceP := &onceX
onceZ := &sync.Once{}
}
// AtomicTypesCheck checks copying of sync/atomic types
func AtomicTypesCheck() {
// atomic.Value copying
var vX atomic.Value
var vXX = atomic.Value{}
vX1 := new(atomic.Value)
// These are OK because the value has not been used yet.
// (And vet can't tell whether it has been used, so they're always OK.)
vY := vX
vY = vX
var vYY = vX
vP := &vX
vZ := &atomic.Value{}
}

View File

@ -5,20 +5,20 @@
// This file contains tests for the copylock checker's
// function declaration analysis.
package testdata
package a
import "sync"
func OkFunc(*sync.Mutex) {}
func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex"
func BadFunc2(sync.Map) {} // ERROR "BadFunc2 passes lock by value: sync.Map contains sync.Mutex"
func BadFunc(sync.Mutex) {} // want "BadFunc passes lock by value: sync.Mutex"
func BadFunc2(sync.Map) {} // want "BadFunc2 passes lock by value: sync.Map contains sync.Mutex"
func OkRet() *sync.Mutex {}
func BadRet() sync.Mutex {} // Don't warn about results
var (
OkClosure = func(*sync.Mutex) {}
BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex"
BadClosure2 = func(sync.Map) {} // ERROR "func passes lock by value: sync.Map contains sync.Mutex"
BadClosure = func(sync.Mutex) {} // want "func passes lock by value: sync.Mutex"
BadClosure2 = func(sync.Map) {} // want "func passes lock by value: sync.Map contains sync.Mutex"
)
type EmbeddedRWMutex struct {
@ -26,9 +26,9 @@ type EmbeddedRWMutex struct {
}
func (*EmbeddedRWMutex) OkMeth() {}
func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex"
func (EmbeddedRWMutex) BadMeth() {} // want "BadMeth passes lock by value: a.EmbeddedRWMutex"
func OkFunc(e *EmbeddedRWMutex) {}
func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex"
func BadFunc(EmbeddedRWMutex) {} // want "BadFunc passes lock by value: a.EmbeddedRWMutex"
func OkRet() *EmbeddedRWMutex {}
func BadRet() EmbeddedRWMutex {} // Don't warn about results
@ -37,9 +37,9 @@ type FieldMutex struct {
}
func (*FieldMutex) OkMeth() {}
func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex"
func (FieldMutex) BadMeth() {} // want "BadMeth passes lock by value: a.FieldMutex contains sync.Mutex"
func OkFunc(*FieldMutex) {}
func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex"
func BadFunc(FieldMutex, int) {} // want "BadFunc passes lock by value: a.FieldMutex contains sync.Mutex"
type L0 struct {
L1
@ -54,7 +54,7 @@ type L2 struct {
}
func (*L0) Ok() {}
func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2"
func (L0) Bad() {} // want "Bad passes lock by value: a.L0 contains a.L1 contains a.L2"
type EmbeddedMutexPointer struct {
s *sync.Mutex // safe to copy this pointer
@ -78,7 +78,7 @@ func (*CustomLock) Lock() {}
func (*CustomLock) Unlock() {}
func Ok(*CustomLock) {}
func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock"
func Bad(CustomLock) {} // want "Bad passes lock by value: a.CustomLock"
// Passing lock values into interface function arguments
func FuncCallInterfaceArg(f func(a int, b interface{})) {
@ -88,10 +88,10 @@ func FuncCallInterfaceArg(f func(a int, b interface{})) {
f(1, "foo")
f(2, &t)
f(3, &sync.Mutex{})
f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
f(4, m) // want "call of f copies lock value: sync.Mutex"
f(5, t) // want "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
var fntab []func(t)
fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
fntab[0](t) // want "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
}
// Returning lock via interface value
@ -105,9 +105,9 @@ func ReturnViaInterface(x int) (int, interface{}) {
case 1:
return 1, &sync.Mutex{}
case 2:
return 2, m // ERROR "return copies lock value: sync.Mutex"
return 2, m // want "return copies lock value: sync.Mutex"
default:
return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
return 3, t // want "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
}
}
@ -126,7 +126,7 @@ func AcceptedCases() {
// sync.Mutex gets called out, but without any reference to the sync.Once.
type LocalOnce sync.Once
func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex"
func (LocalOnce) Bad() {} // want "Bad passes lock by value: a.LocalOnce contains sync.Mutex"
// False negative:
// LocalMutex doesn't have a Lock method.

View File

@ -0,0 +1,67 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains tests for the copylock checker's
// range statement analysis.
package a
import "sync"
func rangeMutex() {
var mu sync.Mutex
var i int
var s []sync.Mutex
for range s {
}
for i = range s {
}
for i := range s {
}
for i, _ = range s {
}
for i, _ := range s {
}
for _, mu = range s { // want "range var mu copies lock: sync.Mutex"
}
for _, m := range s { // want "range var m copies lock: sync.Mutex"
}
for i, mu = range s { // want "range var mu copies lock: sync.Mutex"
}
for i, m := range s { // want "range var m copies lock: sync.Mutex"
}
var a [3]sync.Mutex
for _, m := range a { // want "range var m copies lock: sync.Mutex"
}
var m map[sync.Mutex]sync.Mutex
for k := range m { // want "range var k copies lock: sync.Mutex"
}
for mu, _ = range m { // want "range var mu copies lock: sync.Mutex"
}
for k, _ := range m { // want "range var k copies lock: sync.Mutex"
}
for _, mu = range m { // want "range var mu copies lock: sync.Mutex"
}
for _, v := range m { // want "range var v copies lock: sync.Mutex"
}
var c chan sync.Mutex
for range c {
}
for mu = range c { // want "range var mu copies lock: sync.Mutex"
}
for v := range c { // want "range var v copies lock: sync.Mutex"
}
// Test non-idents in range variables
var t struct {
i int
mu sync.Mutex
}
for t.i, t.mu = range s { // want "range var t.mu copies lock: sync.Mutex"
}
}

View File

@ -1,188 +0,0 @@
package testdata
import (
"sync"
"sync/atomic"
"unsafe"
. "unsafe"
unsafe1 "unsafe"
)
func OkFunc() {
var x *sync.Mutex
p := x
var y sync.Mutex
p = &y
var z = sync.Mutex{}
w := sync.Mutex{}
w = sync.Mutex{}
q := struct{ L sync.Mutex }{
L: sync.Mutex{},
}
yy := []Tlock{
Tlock{},
Tlock{
once: sync.Once{},
},
}
nl := new(sync.Mutex)
mx := make([]sync.Mutex, 10)
xx := struct{ L *sync.Mutex }{
L: new(sync.Mutex),
}
}
type Tlock struct {
once sync.Once
}
func BadFunc() {
var x *sync.Mutex
p := x
var y sync.Mutex
p = &y
*p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex"
var t Tlock
var tp *Tlock
tp = &t
*tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex"
y := *x // ERROR "assignment copies lock value to y: sync.Mutex"
var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex"
w := struct{ L sync.Mutex }{
L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex"
}
var q = map[int]Tlock{
1: t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
}
yy := []Tlock{
t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
*tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
}
// override 'new' keyword
new := func(interface{}) {}
new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
// copy of array of locks
var muA [5]sync.Mutex
muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex"
muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex"
muSlice := muA[:] // OK
// multidimensional array
var mmuA [5][5]sync.Mutex
mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex"
mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex"
mmuSlice := mmuA[:] // OK
// slice copy is ok
var fmuA [5][][5]sync.Mutex
fmuB := fmuA // OK
fmuA = fmuB // OK
fmuSlice := fmuA[:] // OK
}
func LenAndCapOnLockArrays() {
var a [5]sync.Mutex
aLen := len(a) // OK
aCap := cap(a) // OK
// override 'len' and 'cap' keywords
len := func(interface{}) {}
len(a) // ERROR "call of len copies lock value: sync.Mutex"
cap := func(interface{}) {}
cap(a) // ERROR "call of cap copies lock value: sync.Mutex"
}
func SizeofMutex() {
var mu sync.Mutex
unsafe.Sizeof(mu) // OK
unsafe1.Sizeof(mu) // OK
Sizeof(mu) // OK
unsafe := struct{ Sizeof func(interface{}) }{}
unsafe.Sizeof(mu) // ERROR "call of unsafe.Sizeof copies lock value: sync.Mutex"
Sizeof := func(interface{}) {}
Sizeof(mu) // ERROR "call of Sizeof copies lock value: sync.Mutex"
}
// SyncTypesCheck checks copying of sync.* types except sync.Mutex
func SyncTypesCheck() {
// sync.RWMutex copying
var rwmuX sync.RWMutex
var rwmuXX = sync.RWMutex{}
rwmuX1 := new(sync.RWMutex)
rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
rwmuP := &rwmuX
rwmuZ := &sync.RWMutex{}
// sync.Cond copying
var condX sync.Cond
var condXX = sync.Cond{}
condX1 := new(sync.Cond)
condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
condP := &condX
condZ := &sync.Cond{
L: &sync.Mutex{},
}
condZ = sync.NewCond(&sync.Mutex{})
// sync.WaitGroup copying
var wgX sync.WaitGroup
var wgXX = sync.WaitGroup{}
wgX1 := new(sync.WaitGroup)
wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
wgP := &wgX
wgZ := &sync.WaitGroup{}
// sync.Pool copying
var poolX sync.Pool
var poolXX = sync.Pool{}
poolX1 := new(sync.Pool)
poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
poolP := &poolX
poolZ := &sync.Pool{}
// sync.Once copying
var onceX sync.Once
var onceXX = sync.Once{}
onceX1 := new(sync.Once)
onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
onceP := &onceX
onceZ := &sync.Once{}
}
// AtomicTypesCheck checks copying of sync/atomic types
func AtomicTypesCheck() {
// atomic.Value copying
var vX atomic.Value
var vXX = atomic.Value{}
vX1 := new(atomic.Value)
// These are OK because the value has not been used yet.
// (And vet can't tell whether it has been used, so they're always OK.)
vY := vX
vY = vX
var vYY = vX
vP := &vX
vZ := &atomic.Value{}
}

View File

@ -1,67 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains tests for the copylock checker's
// range statement analysis.
package testdata
import "sync"
func rangeMutex() {
var mu sync.Mutex
var i int
var s []sync.Mutex
for range s {
}
for i = range s {
}
for i := range s {
}
for i, _ = range s {
}
for i, _ := range s {
}
for _, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
}
for _, m := range s { // ERROR "range var m copies lock: sync.Mutex"
}
for i, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
}
for i, m := range s { // ERROR "range var m copies lock: sync.Mutex"
}
var a [3]sync.Mutex
for _, m := range a { // ERROR "range var m copies lock: sync.Mutex"
}
var m map[sync.Mutex]sync.Mutex
for k := range m { // ERROR "range var k copies lock: sync.Mutex"
}
for mu, _ = range m { // ERROR "range var mu copies lock: sync.Mutex"
}
for k, _ := range m { // ERROR "range var k copies lock: sync.Mutex"
}
for _, mu = range m { // ERROR "range var mu copies lock: sync.Mutex"
}
for _, v := range m { // ERROR "range var v copies lock: sync.Mutex"
}
var c chan sync.Mutex
for range c {
}
for mu = range c { // ERROR "range var mu copies lock: sync.Mutex"
}
for v := range c { // ERROR "range var v copies lock: sync.Mutex"
}
// Test non-idents in range variables
var t struct {
i int
mu sync.Mutex
}
for t.i, t.mu = range s { // ERROR "range var t.mu copies lock: sync.Mutex"
}
}