@@ -31,7 +31,7 @@ const requireErrorReport = "for error assertions use require"
31
31
//
32
32
// RequireError ignores:
33
33
// - assertion in the `if` condition;
34
- // - the entire `if-else` block, if there is an assertion in the `if` condition;
34
+ // - the entire `if-else[-if] ` block, if there is an assertion in any `if` condition;
35
35
// - the last assertion in the block, if there are no methods/functions calls after it;
36
36
// - assertions in an explicit goroutine;
37
37
// - assertions in an explicit testing cleanup function or suite teardown methods;
@@ -80,6 +80,7 @@ func (checker RequireError) Check(pass *analysis.Pass, inspector *inspector.Insp
80
80
call := & callMeta {
81
81
call : callExpr ,
82
82
testifyCall : testifyCall ,
83
+ rootIf : findRootIf (stack ),
83
84
parentIf : findNearestNode [* ast.IfStmt ](stack ),
84
85
parentBlock : findNearestNode [* ast.BlockStmt ](stack ),
85
86
inIfCond : inIfCond ,
@@ -157,10 +158,10 @@ func needToSkipBasedOnContext(
157
158
return true
158
159
}
159
160
160
- if currCall .parentIf != nil {
161
+ if currCall .rootIf != nil {
161
162
for _ , rootCall := range otherCalls {
162
- if (rootCall .parentIf == currCall .parentIf ) && rootCall .inIfCond {
163
- // Skip assertions in the entire if-else parentBlock , if the "if condition" contains assertion.
163
+ if (rootCall .rootIf == currCall .rootIf ) && rootCall .inIfCond {
164
+ // Skip assertions in the entire if-else[-if] block , if some of "if condition" contains assertion.
164
165
return true
165
166
}
166
167
}
@@ -175,7 +176,7 @@ func needToSkipBasedOnContext(
175
176
_ , blockEndWithReturn := block .List [len (block .List )- 1 ].(* ast.ReturnStmt )
176
177
if ! blockEndWithReturn {
177
178
for i := currCallIndex + 1 ; i < len (otherCalls ); i ++ {
178
- if (otherCalls [i ].parentIf == nil ) || (otherCalls [i ].parentIf != currCall .parentIf ) {
179
+ if (otherCalls [i ].rootIf == nil ) || (otherCalls [i ].rootIf != currCall .rootIf ) {
179
180
noCallsAfter = false
180
181
break
181
182
}
@@ -233,10 +234,28 @@ func findSurroundingFunc(pass *analysis.Pass, stack []ast.Node) *funcID {
233
234
return nil
234
235
}
235
236
237
+ func findRootIf (stack []ast.Node ) * ast.IfStmt {
238
+ nearestIf , i := findNearestNodeWithIdx [* ast.IfStmt ](stack )
239
+ for ; i > 0 ; i -- {
240
+ parent , ok := stack [i - 1 ].(* ast.IfStmt )
241
+ if ok {
242
+ nearestIf = parent
243
+ } else {
244
+ break
245
+ }
246
+ }
247
+ return nearestIf
248
+ }
249
+
236
250
func findNearestNode [T ast.Node ](stack []ast.Node ) (v T ) {
251
+ v , _ = findNearestNodeWithIdx [T ](stack )
252
+ return
253
+ }
254
+
255
+ func findNearestNodeWithIdx [T ast.Node ](stack []ast.Node ) (v T , index int ) {
237
256
for i := len (stack ) - 2 ; i >= 0 ; i -- {
238
257
if n , ok := stack [i ].(T ); ok {
239
- return n
258
+ return n , i
240
259
}
241
260
}
242
261
return
@@ -273,7 +292,8 @@ func markCallsInNoErrorSequence(callsByBlock map[*ast.BlockStmt][]*callMeta) {
273
292
type callMeta struct {
274
293
call * ast.CallExpr
275
294
testifyCall * CallMeta
276
- parentIf * ast.IfStmt
295
+ rootIf * ast.IfStmt // The root `if` in if-else[-if] chain.
296
+ parentIf * ast.IfStmt // The nearest `if`, can be equal with rootIf.
277
297
parentBlock * ast.BlockStmt
278
298
inIfCond bool // True for code like `if assert.ErrorAs(t, err, &target) {`.
279
299
inNoErrorSeq bool // True for sequence of `assert.NoError` assertions.
0 commit comments