diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 6577bc116282..7e734531e9af 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -119,29 +119,27 @@ public class PyCallExpressionHelper { public static List multiResolveRatedCallee(@NotNull PyCallExpression call, @NotNull PyResolveContext resolveContext, int implicitOffset) { - final LinkedHashMap result = new LinkedHashMap<>(); + final TypeEvalContext context = resolveContext.getTypeEvalContext(); + final List ratedMarkedCallees = new ArrayList<>(); for (QualifiedRatedResolveResult resolveResult : multiResolveCallee(call.getCallee(), resolveContext)) { final ClarifiedResolveResult clarifiedResolveResult = clarifyResolveResult(resolveResult, resolveContext, call); if (clarifiedResolveResult == null) continue; - final PyCallExpression.PyRatedMarkedCallee markedCallee = - markResolveResult(clarifiedResolveResult, resolveContext.getTypeEvalContext(), implicitOffset); + final PyCallExpression.PyRatedMarkedCallee markedCallee = markResolveResult(clarifiedResolveResult, context, implicitOffset); if (markedCallee == null) continue; - // while clarifying resolve results we could get duplicate callables so we have to group them and select result with highest rate - result.put(markedCallee.getElement(), - StreamEx - .of(markedCallee, result.get(markedCallee.getElement())) - .nonNull() - .max(Comparator.comparingInt(PyCallExpression.PyRatedMarkedCallee::getRate)) - .orElse(null)); + ratedMarkedCallees.add(markedCallee); } - return StreamEx - .of(forEveryScopeTakeOverloadsOtherwiseImplementations(result.entrySet(), Map.Entry::getKey, resolveContext.getTypeEvalContext())) - .map(Map.Entry::getValue) - .toList(); + return forEveryScopeTakeOverloadsOtherwiseImplementations(ratedMarkedCallees, PyCallExpression.PyRatedMarkedCallee::getElement, context) + // while clarifying resolve results we could get duplicate callables so we have to group them and select result with highest rate + .collect(Collectors.groupingBy(markedCallee -> markedCallee.getElement(), LinkedHashMap::new, Collectors.toList())) + .entrySet() + .stream() + .map(entry -> entry.getValue().stream().max(Comparator.comparingInt(PyCallExpression.PyRatedMarkedCallee::getRate)).orElse(null)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } @NotNull @@ -405,11 +403,13 @@ public class PyCallExpressionHelper { } // normal cases final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - final List resolveResults = - PyUtil.filterTopPriorityResults(multiResolveCallee(callee, resolveContext)); + + final List resolveResults = multiResolveCallee(callee, resolveContext); + final Stream overloadsOtherwiseImplementations = + forEveryScopeTakeOverloadsOtherwiseImplementations(resolveResults, RatedResolveResult::getElement, context); final List members = StreamEx - .of(forEveryScopeTakeOverloadsOtherwiseImplementations(resolveResults, ResolveResult::getElement, context)) + .of(PyUtil.filterTopPriorityResults(overloadsOtherwiseImplementations.collect(Collectors.toList()))) .map(ResolveResult::getElement) .nonNull() .peek(element -> PyUtil.verboseOnly(() -> PyPsiUtils.assertValid(element))) diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index a24d754891b9..7748cf5f18fa 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -54,14 +54,12 @@ import com.jetbrains.python.psi.stubs.PyFileStub; import com.jetbrains.python.psi.types.PyModuleType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; -import com.jetbrains.python.pyi.PyiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; import java.util.*; -import java.util.function.Function; public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { protected PyType myType; @@ -183,10 +181,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { } } - final Function mapper = RatedResolveResult::getElement; - return PyiUtil.containsOverloads(resultList, mapper, typeEvalContext) - ? PyiUtil.moveOverloadsBack(resultList, mapper, typeEvalContext) - : resultList; + return resultList; } synchronized (myNameDefinerNegativeCache) { diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 0fc8bd762625..cf039de321eb 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -440,6 +440,9 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference else if (elt instanceof PyFile) { rate = RatedResolveResult.RATE_HIGH; } + else if (!PyiUtil.isInsideStub(elt) && PyiUtil.isOverload(elt, context)) { + rate = RatedResolveResult.RATE_LOW; + } else { rate = RatedResolveResult.RATE_NORMAL; } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index e551668a3e7f..8e3d15af41d3 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -44,13 +44,11 @@ import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.PyResolveProcessor; import com.jetbrains.python.psi.resolve.RatedResolveResult; -import com.jetbrains.python.pyi.PyiUtil; import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; import static com.jetbrains.python.psi.PyUtil.as; @@ -561,13 +559,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } else { cls.processClassLevelDeclarations(processor); - final Collection elements = processor.getElements(); - result = PyiUtil.containsOverloads(elements, Function.identity(), context) - ? PyiUtil.moveOverloadsBack(elements, Function.identity(), context) - : elements; + result = processor.getElements(); } - return ContainerUtil.map(result, element -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, element)); + return ContainerUtil.map(result, element -> new RatedResolveResult(PyReferenceImpl.getRate(element, context), element)); } private static Key> CTX_VISITED = Key.create("PyClassType.Visited"); diff --git a/python/src/com/jetbrains/python/pyi/PyiUtil.java b/python/src/com/jetbrains/python/pyi/PyiUtil.java index 9753e884405e..de7221c6f53d 100644 --- a/python/src/com/jetbrains/python/pyi/PyiUtil.java +++ b/python/src/com/jetbrains/python/pyi/PyiUtil.java @@ -28,14 +28,13 @@ import com.jetbrains.python.psi.resolve.*; import com.jetbrains.python.psi.types.PyClassLikeType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; -import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.List; -import java.util.function.Function; /** * @author vlan @@ -126,22 +125,6 @@ public class PyiUtil { PyKnownDecoratorUtil.getKnownDecorators((PyFunction)element, context).contains(overload); } - public static boolean containsOverloads(@NotNull Collection elements, - @NotNull Function mapper, - @NotNull TypeEvalContext context) { - return ContainerUtil.exists(elements, element -> isOverload(mapper.apply(element), context)); - } - - @NotNull - public static List moveOverloadsBack(@NotNull Collection elements, - @NotNull Function mapper, - @NotNull TypeEvalContext context) { - return StreamEx - .of(elements) - .sorted((e1, e2) -> Boolean.compare(isOverload(mapper.apply(e1), context), isOverload(mapper.apply(e2), context))) - .toList(); - } - private static boolean pyButNotPyiFile(@Nullable PsiFile file) { return file instanceof PyFile && !(file instanceof PyiFile); } @@ -190,20 +173,20 @@ public class PyiUtil { final PyClassLikeType instanceType = classType.toInstance(); final List resolveResults = instanceType.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits(), false); - return takeFirstElement(resolveResults); + return takeTopPriorityElement(resolveResults); } } else if (originalOwner instanceof PyFile) { - return takeFirstElement(((PyFile)originalOwner).multiResolveName(name)); + return takeTopPriorityElement(((PyFile)originalOwner).multiResolveName(name)); } } return null; } @Nullable - private static PsiElement takeFirstElement(@Nullable List resolveResults) { + private static PsiElement takeTopPriorityElement(@Nullable List resolveResults) { if (!ContainerUtil.isEmpty(resolveResults)) { - return resolveResults.get(0).getElement(); + return Collections.max(resolveResults, Comparator.comparingInt(RatedResolveResult::getRate)).getElement(); } return null; }