@@ -2,6 +2,7 @@ package rule
2
2
3
3
import (
4
4
"go/ast"
5
+ "go/token"
5
6
"strings"
6
7
7
8
"github.com/mgechev/revive/lint"
@@ -60,14 +61,14 @@ func (w lintModifiesValRecRule) Visit(node ast.Node) ast.Visitor {
60
61
return nil // skip, anonymous receiver
61
62
}
62
63
63
- fselect := func (n ast.Node ) bool {
64
+ receiverAssignmentFinder := func (n ast.Node ) bool {
64
65
// look for assignments with the receiver in the right hand
65
- asgmt , ok := n .(* ast.AssignStmt )
66
+ assignment , ok := n .(* ast.AssignStmt )
66
67
if ! ok {
67
68
return false
68
69
}
69
70
70
- for _ , exp := range asgmt .Lhs {
71
+ for _ , exp := range assignment .Lhs {
71
72
switch e := exp .(type ) {
72
73
case * ast.IndexExpr : // receiver...[] = ...
73
74
continue
@@ -92,7 +93,15 @@ func (w lintModifiesValRecRule) Visit(node ast.Node) ast.Visitor {
92
93
return false
93
94
}
94
95
95
- assignmentsToReceiver := pick (n .Body , fselect )
96
+ assignmentsToReceiver := pick (n .Body , receiverAssignmentFinder )
97
+ if len (assignmentsToReceiver ) == 0 {
98
+ return nil // receiver is not modified
99
+ }
100
+
101
+ methodReturnsReceiver := len (w .findReturnReceiverStatements (receiverName , n .Body )) > 0
102
+ if methodReturnsReceiver {
103
+ return nil // modification seems legit (see issue #1066)
104
+ }
96
105
97
106
for _ , assignment := range assignmentsToReceiver {
98
107
w .onFailure (lint.Failure {
@@ -127,3 +136,44 @@ func (lintModifiesValRecRule) getNameFromExpr(ie ast.Expr) string {
127
136
128
137
return ident .Name
129
138
}
139
+
140
+ func (w lintModifiesValRecRule ) findReturnReceiverStatements (receiverName string , target ast.Node ) []ast.Node {
141
+ finder := func (n ast.Node ) bool {
142
+ // look for returns with the receiver as value
143
+ returnStatement , ok := n .(* ast.ReturnStmt )
144
+ if ! ok {
145
+ return false
146
+ }
147
+
148
+ for _ , exp := range returnStatement .Results {
149
+ switch e := exp .(type ) {
150
+ case * ast.SelectorExpr : // receiver.field = ...
151
+ name := w .getNameFromExpr (e .X )
152
+ if name == "" || name != receiverName {
153
+ continue
154
+ }
155
+ case * ast.Ident : // receiver := ...
156
+ if e .Name != receiverName {
157
+ continue
158
+ }
159
+ case * ast.UnaryExpr :
160
+ if e .Op != token .AND {
161
+ continue
162
+ }
163
+ name := w .getNameFromExpr (e .X )
164
+ if name == "" || name != receiverName {
165
+ continue
166
+ }
167
+
168
+ default :
169
+ continue
170
+ }
171
+
172
+ return true
173
+ }
174
+
175
+ return false
176
+ }
177
+
178
+ return pick (target , finder )
179
+ }
0 commit comments