MCPcopy
hub / github.com/uber-go/nilaway / handleErrorReturns

Function handleErrorReturns

assertion/function/assertiontree/backprop_util.go:276–319  ·  view source on GitHub ↗

handleErrorReturns handles the special case for error returning functions (n-th result of type `error` which guards at least one of the first n-1 non-error results). It generates consumers by applying the error contract: (1) if error return value = nil, create consumers for the non-error returns (2)

(rootNode *RootAssertionNode, retStmt *ast.ReturnStmt, results []ast.Expr, isNamedReturn bool)

Source from the content-addressed store, hash-verified

274//
275// Note that `results` should be explicitly passed since `retStmt` of a named return will contain no results
276func handleErrorReturns(rootNode *RootAssertionNode, retStmt *ast.ReturnStmt, results []ast.Expr, isNamedReturn bool) bool {
277 if !typeshelper.FuncIsErrReturning(rootNode.FuncObj().Signature()) {
278 return false
279 }
280
281 errRetIndex := len(results) - 1
282 errRetExpr := results[errRetIndex] // n-th expression
283 nonErrRetExpr := results[:errRetIndex] // n-1 expressions
284
285 // default tracking to support potential "always safe" cases
286 createReturnConsumersForAlwaysSafe(rootNode, nonErrRetExpr, retStmt, isNamedReturn)
287
288 // check if the error return is at all guarding any nilable returns, such as pointers, maps, and slices
289 if isErrorReturnNil(rootNode, errRetExpr) {
290 // if error is the only return expression in the statement, then create a consumer for it, else create consumers for the non-error return expressions
291 if len(nonErrRetExpr) == 0 {
292 createConsumerForErrorReturn(rootNode, errRetExpr, errRetIndex, retStmt, isNamedReturn)
293 } else {
294 // create general return consume triggers for all n-1 (non-error) return expressions
295 createGeneralReturnConsumers(rootNode, nonErrRetExpr, retStmt, isNamedReturn)
296 }
297
298 // TODO: handle struct init in the context of error return in a better way in a follow up diff
299 if rootNode.functionContext.functionConfig.EnableStructInitCheck {
300 for i := range results {
301 rootNode.addConsumptionsForFieldsOfReturns(results[i], i)
302 }
303 }
304 } else if isErrorReturnNonnil(rootNode, errRetExpr) {
305 // create consume trigger for only the error return
306 createConsumerForErrorReturn(rootNode, errRetExpr, errRetIndex, retStmt, isNamedReturn)
307 } else {
308 // the nilability of error return is unknown, hence create special consume triggers for all returns
309 createSpecialConsumersForAllReturns(rootNode, nonErrRetExpr, errRetExpr, errRetIndex, retStmt, isNamedReturn)
310
311 // TODO: handle struct init in the context of error return in a better way in a follow up diff
312 if rootNode.functionContext.functionConfig.EnableStructInitCheck {
313 for i := range results {
314 rootNode.addConsumptionsForFieldsOfReturns(results[i], i)
315 }
316 }
317 }
318 return true
319}
320
321// handleBooleanReturns handles the special case for boolean (`ok`) returning functions (n-th result of type `bool`
322// which guards at least one of the first n-1 non-bool results). Similar to the handling of error returning functions,

Callers 1

computeAndConsumeResultsFunction · 0.85

Calls 9

FuncIsErrReturningFunction · 0.92
isErrorReturnNilFunction · 0.85
isErrorReturnNonnilFunction · 0.85
FuncObjMethod · 0.80

Tested by

no test coverage detected