PY-20611 Missing warning about functions implicitly returning None when return type is not Optional

Updated PyFunction to account for implicit 'return None' statements when inferring return statement types.

It affected return type inference of PyFunction.

Fixed a failing test related to formatted strings.

Added a quick fix to make all return statements explicit.

Updated the CFG to include PyPassStatements, enabling detection of exit points in empty functions.

Simplified PyMakeFunctionReturnTypeQuickFix to independently infer function types and handle required imports. Currently, it does not support specifying custom suggested types.



Merge-request: IJ-MR-148719
Merged-by: Aleksandr Govenko <aleksandr.govenko@jetbrains.com>

(cherry picked from commit 9f58961f9eb70e4f9dbba7359f5aafdfd392b7e2)

IJ-MR-148719

GitOrigin-RevId: 68ef5c4a1cc0fcaffd750cc0713250a106136643
This commit is contained in:
Aleksandr.Govenko
2024-11-26 17:02:37 +00:00
committed by intellij-monorepo-bot
parent 137b1d2b13
commit 4dd41ee9f5
32 changed files with 430 additions and 301 deletions

View File

@@ -274,6 +274,10 @@ public class PyElementVisitor extends PsiElementVisitor {
visitPyElement(node);
}
public void visitPyPassStatement(@NotNull PyPassStatement node) {
visitPyStatement(node);
}
public void visitPyNoneLiteralExpression(@NotNull PyNoneLiteralExpression node) {
visitPyElement(node);
}

View File

@@ -8,9 +8,11 @@ import com.jetbrains.python.PyNames;
import com.jetbrains.python.ast.*;
import com.jetbrains.python.ast.impl.PyPsiUtilsCore;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.impl.PyTypeProvider;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,9 +30,38 @@ public interface PyFunction extends PyAstFunction, StubBasedPsiElement<PyFunctio
PyFunction[] EMPTY_ARRAY = new PyFunction[0];
ArrayFactory<PyFunction> ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PyFunction[count];
/**
* Infers function's return type by analyzing <b>only return statements</b> (including implicit returns) in its control flow.
* Does not consider yield statements or return type annotations.
*
* @see PyFunction#getInferredReturnType(TypeEvalContext)
*/
@Nullable
PyType getReturnStatementType(@NotNull TypeEvalContext context);
/**
* Infers function's return type by analyzing <b>return statements</b> (including implicit returns) and <b>yield expression</b>.
* In contrast with {@link TypeEvalContext#getReturnType(PyCallable)} does not consider
* return type annotations or any other {@link PyTypeProvider}.
*
* @apiNote Does not cache the result.
*/
@ApiStatus.Internal
@Nullable
PyType getInferredReturnType(@NotNull TypeEvalContext context);
/**
* Returns a list of all function exit points that can return a value.
* This includes explicit 'return' statements and statements that can complete
* normally with an implicit 'return None', excluding statements that raise exceptions.
*
* @see PyFunction#getReturnStatementType(TypeEvalContext)
* @return List of exit point statements, in control flow order
*/
@ApiStatus.Internal
@NotNull
List<PyStatement> getReturnPoints(@NotNull TypeEvalContext context);
/**
* Checks whether the function contains a yield expression in its body.
*/