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