@@ -158,6 +158,40 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
158158 result = getAReturnStmt ( ) .getExpr ( )
159159 }
160160
161+ /**
162+ *
163+ * Functions can sometimes return without returning a value, in which case they
164+ * "return" `undefined`. They can do this in two ways:
165+ *
166+ * 1. An explicit return statement with no expression, i.e. the statement `return;`
167+ *
168+ * 2. An implicit return resulting from an expression executing as the last thing
169+ * in the function. For example, the test in a final `if` statement:
170+ *
171+ * ```
172+ * function foo() {
173+ * ...
174+ * if (test) { return 1; }
175+ * }
176+ * ```
177+ *
178+ * Some things look like they might return undefined but actually don't because
179+ * the containing functioning doesn't return at all. For instance, `throw`
180+ * statements prevent the containing function from returning, so they don't count
181+ * as undefined returns. Similarly, `yield` doesn't actually cause a return,
182+ * since the containing function is a generator and can be re-entered, so we also
183+ * exclude yields entirely.
184+ */
185+
186+ ConcreteControlFlowNode getAnUndefinedReturn ( ) {
187+ not ( this instanceof ArrowFunctionExpr and this .getBody ( ) instanceof Expr ) and
188+ result .getContainer ( ) = this and
189+ result .isAFinalNode ( ) and
190+ not ( result instanceof ReturnStmt and exists ( result .( ReturnStmt ) .getExpr ( ) ) ) and
191+ not result instanceof ThrowStmt and
192+ not result instanceof YieldExpr
193+ }
194+
161195 /**
162196 * Gets the function whose `this` binding a `this` expression in this function refers to,
163197 * which is the nearest enclosing non-arrow function.
0 commit comments