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
8package a
9
10import "sync"
11
12func OkFunc(*sync.Mutex) {}
13func BadFunc(sync.Mutex) {} // want "BadFunc passes lock by value: sync.Mutex"
14func BadFunc2(sync.Map)  {} // want "BadFunc2 passes lock by value: sync.Map contains sync.Mutex"
15func OkRet() *sync.Mutex {}
16func BadRet() sync.Mutex {} // Don't warn about results
17
18var (
19	OkClosure   = func(*sync.Mutex) {}
20	BadClosure  = func(sync.Mutex) {} // want "func passes lock by value: sync.Mutex"
21	BadClosure2 = func(sync.Map) {}   // want "func passes lock by value: sync.Map contains sync.Mutex"
22)
23
24type EmbeddedRWMutex struct {
25	sync.RWMutex
26}
27
28func (*EmbeddedRWMutex) OkMeth() {}
29func (EmbeddedRWMutex) BadMeth() {} // want "BadMeth passes lock by value: a.EmbeddedRWMutex"
30func OkFunc(e *EmbeddedRWMutex)  {}
31func BadFunc(EmbeddedRWMutex)    {} // want "BadFunc passes lock by value: a.EmbeddedRWMutex"
32func OkRet() *EmbeddedRWMutex    {}
33func BadRet() EmbeddedRWMutex    {} // Don't warn about results
34
35type FieldMutex struct {
36	s sync.Mutex
37}
38
39func (*FieldMutex) OkMeth()   {}
40func (FieldMutex) BadMeth()   {} // want "BadMeth passes lock by value: a.FieldMutex contains sync.Mutex"
41func OkFunc(*FieldMutex)      {}
42func BadFunc(FieldMutex, int) {} // want "BadFunc passes lock by value: a.FieldMutex contains sync.Mutex"
43
44type L0 struct {
45	L1
46}
47
48type L1 struct {
49	l L2
50}
51
52type L2 struct {
53	sync.Mutex
54}
55
56func (*L0) Ok() {}
57func (L0) Bad() {} // want "Bad passes lock by value: a.L0 contains a.L1 contains a.L2"
58
59type EmbeddedMutexPointer struct {
60	s *sync.Mutex // safe to copy this pointer
61}
62
63func (*EmbeddedMutexPointer) Ok()      {}
64func (EmbeddedMutexPointer) AlsoOk()   {}
65func StillOk(EmbeddedMutexPointer)     {}
66func LookinGood() EmbeddedMutexPointer {}
67
68type EmbeddedLocker struct {
69	sync.Locker // safe to copy interface values
70}
71
72func (*EmbeddedLocker) Ok()    {}
73func (EmbeddedLocker) AlsoOk() {}
74
75type CustomLock struct{}
76
77func (*CustomLock) Lock()   {}
78func (*CustomLock) Unlock() {}
79
80func Ok(*CustomLock) {}
81func Bad(CustomLock) {} // want "Bad passes lock by value: a.CustomLock"
82
83// Passing lock values into interface function arguments
84func 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) // want "call of f copies lock value: sync.Mutex"
92	f(5, t) // want "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
93	var fntab []func(t)
94	fntab[0](t) // want "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
95}
96
97// Returning lock via interface value
98func 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 // want "return copies lock value: sync.Mutex"
109	default:
110		return 3, t // want "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
111	}
112}
113
114// Some cases that we don't warn about.
115
116func 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.
127type LocalOnce sync.Once
128
129func (LocalOnce) Bad() {} // want "Bad passes lock by value: a.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.
134type LocalMutex sync.Mutex
135
136func (LocalMutex) Bad() {} // WANTED: An error here :(
137