Table of Contents

RDC00206 — Not all code paths return a value

Severity: Warning  ·  Family: RDC (Rubberduck Core analyzers)  ·  Raised by: NotAllPathsReturnValueAnalyzer

A function or a property getter has a code path that ends without assigning its return value.

A function declaration implicitly defines a local variable that shares its name and its declared type with the function, the function result variable (MS-VBAL §5.3.1 Procedure Declarations); what the function returns is what the variable holds when the procedure ends. On a code path that never assigns it, that is the default value of the type: 0, an empty string, Empty for a Variant, Nothing for an object. The caller cannot tell that apart from a result, and a mistake of this kind shows up as a wrong value far from the function that returned it. Unlike the inspection of the legacy Rubberduck, which reported a function that never assigns its return value, this is reported for any code path that does not: the function that assigns it in the If and forgets the Else is the common one.

The code paths are those of the lowered body of the procedure (RD-VBAL §3.5.1 InstructionList): the ControlFlowGraph the environment host builds from it when it loads the code. A code path is a way control can go, so each branch of a condition is one, except where the condition is the literal True or False, and a For loop is skipped unless its bounds are literals that say it runs. The path an On Error GoTo handler is reached by starts at any statement that can raise an error while the handler is in effect, and leaves it before it completes. That the return value is, or is not, assigned on every path is a fact of the procedure (ProcedureSemanticModel.ReturnValue); the analyzer reads it, and is not given the syntax tree to work it out from.

The fact is not stated - and nothing is reported - for a procedure whose code paths could not be told exactly: one with GoSub/Return, where a Return goes back to whichever GoSub sent control there; one with a jump to a label that is not defined; and one that the static pass found something wrong with, or did not analyze entirely. A body that has no statement is not reported either: it is how a member of an interface is written.

How it is raised

Situation Example Resolution
One branch of a condition assigns it and another does not. If ok Then Total = 1 Assign it in every branch: add the Else, or assign a default before the If.
An Exit Function is reached before the assignment. If n < 0 Then Exit Function Assign the return value before exiting, or assign a default first.
A Select Case has no Case Else, and a value matches no case. Select Case n: Case 1: Total = 1: End Select Add a Case Else that assigns it.
An error handler leaves without assigning it. Handler: Debug.Print Err.Description Assign the return value in the handler.
No code path assigns it. Function Total() As Long: Dim x As Long: x = 1: End Function Assign the return value, or make the procedure a Sub.

See also


ACCUEIL • HOME | ℹ️ BIENVENUE • WELCOME | 🧩 BÂTISSONS • BUILD | RD-VBAL | SDK | 🌐 rubberduckvba.ca