From 77ee34ea5cb2c4f19786ca9ce8cba3ddcfeb0d74 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Tue, 28 Feb 2017 12:30:08 +0300 Subject: [PATCH] PY-22769 Fixed: Wrong inspection "Expected type 'bytes', got 'str' instead" for replacement function of os.path.abspath object PY-22512 Fixed: False positive: expected Optional[bytes] got str for os.path.realpath(...).rstrip('_') PY-22475 Fixed: Switch multi-parameters handling to multi-resolved functions API Use PyCallExpression.multiResolveRatedCalleeFunction in PyTypeChecker and drop PyUtil.getOverloadedParametersSet --- .../inspections/PyTypeCheckerInspection.java | 2 +- .../src/com/jetbrains/python/psi/PyUtil.java | 58 ------------------- .../python/psi/types/PyTypeChecker.java | 26 ++++----- ...ledOnUnionOfStrAndBytesWithStrArguments.py | 5 ++ .../Py3TypeCheckerInspectionTest.java | 9 ++- 5 files changed, 23 insertions(+), 77 deletions(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/ReplaceCalledOnUnionOfStrAndBytesWithStrArguments.py diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 132a3f3b4d83..d4f3a6e664d7 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -181,7 +181,7 @@ public class PyTypeCheckerInspection extends PyInspection { } } - private void checkCallSite(@Nullable PyCallSiteExpression callSite) { + private void checkCallSite(@NotNull PyCallSiteExpression callSite) { final List resultsSet = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext); final List>> problemsSet = new ArrayList<>(); diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 7e4c74feea09..3553e1c4f661 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -1522,64 +1522,6 @@ public class PyUtil { return element; } - @NotNull - public static List> getOverloadedParametersSet(@NotNull PyCallable callable, @NotNull TypeEvalContext context) { - final List> parametersSet = getOverloadedParametersSet(context.getType(callable), context); - return parametersSet != null ? parametersSet : Collections.singletonList(Arrays.asList(callable.getParameterList().getParameters())); - } - - @Nullable - private static List getParametersOfCallableType(@NotNull PyCallableType type, @NotNull TypeEvalContext context) { - final List callableTypeParameters = type.getParameters(context); - if (callableTypeParameters != null) { - boolean allParametersDefined = true; - final List parameters = new ArrayList<>(); - for (PyCallableParameter callableParameter : callableTypeParameters) { - final PyParameter parameter = callableParameter.getParameter(); - if (parameter == null) { - allParametersDefined = false; - break; - } - parameters.add(parameter); - } - if (allParametersDefined) { - return parameters; - } - } - return null; - } - - @Nullable - private static List> getOverloadedParametersSet(@Nullable PyType type, @NotNull TypeEvalContext context) { - if (type instanceof PyUnionType) { - type = ((PyUnionType)type).excludeNull(context); - } - - if (type instanceof PyCallableType) { - final List results = getParametersOfCallableType((PyCallableType)type, context); - if (results != null) { - return Collections.singletonList(results); - } - } - else if (type instanceof PyUnionType) { - final List> results = new ArrayList<>(); - final Collection members = ((PyUnionType)type).getMembers(); - for (PyType member : members) { - if (member instanceof PyCallableType) { - final List parameters = getParametersOfCallableType((PyCallableType)member, context); - if (parameters != null) { - results.add(parameters); - } - } - } - if (!results.isEmpty()) { - return results; - } - } - - return null; - } - @NotNull public static List getParameters(@NotNull PyCallable callable, @NotNull TypeEvalContext context) { return Optional diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 0ca884be7b24..ed4c4329f79a 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -615,28 +615,22 @@ public class PyTypeChecker { } @NotNull - public static List analyzeCallSite(@Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { - if (callSite != null) { - final List results = new ArrayList<>(); - for (PyCallable callable : resolveCallee(callSite, context)) { - final PyExpression receiver = getReceiver(callSite, callable); - for (List parameters : PyUtil.getOverloadedParametersSet(callable, context)) { - final Map mapping = PyCallExpressionHelper.mapArguments(callSite, callable, parameters, context); - results.add(new AnalyzeCallResults(callable, receiver, mapping)); - } - } - return results; + public static List analyzeCallSite(@NotNull PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { + final List results = new ArrayList<>(); + for (PyCallable callable : multiResolveCallee(callSite, context)) { + final PyExpression receiver = getReceiver(callSite, callable); + final Map mapping = PyCallExpressionHelper.mapArguments(callSite, callable, context); + results.add(new AnalyzeCallResults(callable, receiver, mapping)); } - return Collections.emptyList(); + return results; } @NotNull - private static List resolveCallee(@NotNull PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { + private static List multiResolveCallee(@NotNull PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); if (callSite instanceof PyCallExpression) { - final PyCallExpression callExpr = (PyCallExpression)callSite; - final PyCallExpression.PyMarkedCallee callee = callExpr.resolveCallee(resolveContext); - return callee != null ? Collections.singletonList(callee.getCallable()) : Collections.emptyList(); + final List ratedCallees = ((PyCallExpression)callSite).multiResolveRatedCalleeFunction(resolveContext); + return ContainerUtil.map(PyUtil.filterTopPriorityResults(ratedCallees), PyCallExpression.PyRatedCallee::getElement); } else if (callSite instanceof PySubscriptionExpression || callSite instanceof PyBinaryExpression) { final List results = new ArrayList<>(); diff --git a/python/testData/inspections/PyTypeCheckerInspection/ReplaceCalledOnUnionOfStrAndBytesWithStrArguments.py b/python/testData/inspections/PyTypeCheckerInspection/ReplaceCalledOnUnionOfStrAndBytesWithStrArguments.py new file mode 100644 index 000000000000..fb32c7adcfe1 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/ReplaceCalledOnUnionOfStrAndBytesWithStrArguments.py @@ -0,0 +1,5 @@ +from typing import Union + + +def foo(path: Union[bytes, str]) -> None: + path.replace("/", "\\") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index 9fbc9fe97bc7..9de54dc04f70 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -198,7 +198,7 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testBuiltinInputPy3() { doTest(); } - + // PY-200057 public void testClassObjectType() { doTest(); @@ -218,4 +218,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testOptionalOfBoundTypeVarInWarnings() { doTest(); } + + // PY-22769 + public void testReplaceCalledOnUnionOfStrAndBytesWithStrArguments() { + doTest(); + } }