PY-80936 Don't hide Any from callable parameter types in their rendering

GitOrigin-RevId: 5cd4c1e2190b3860dff746034d50fb5fffde9166
This commit is contained in:
Mikhail Golubev
2025-05-14 09:51:56 +00:00
committed by intellij-monorepo-bot
parent a2d43e2f78
commit d55a206af8
5 changed files with 9 additions and 41 deletions
@@ -77,24 +77,11 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
public RichDocumentation(@NotNull TypeEvalContext typeEvalContext, @NotNull PsiElement anchor) {
super(typeEvalContext, anchor);
}
@Override
protected boolean hideWeakUnions() {
return true;
}
}
public static final class Documentation extends PyTypeRenderer {
private final boolean mySimplifyWeakUnions;
public Documentation(@NotNull TypeEvalContext typeEvalContext, boolean simplifyWeakUnions) {
public Documentation(@NotNull TypeEvalContext typeEvalContext) {
super(typeEvalContext);
mySimplifyWeakUnions = simplifyWeakUnions;
}
@Override
protected boolean hideWeakUnions() {
return mySimplifyWeakUnions;
}
}
@@ -204,10 +191,6 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
return origin == null || PythonLanguageLevelPusher.getLanguageLevelForFile(origin).isAtLeast(LanguageLevel.PYTHON39);
}
protected boolean hideWeakUnions() {
return false;
}
protected boolean hideAllAnyTypeArguments() {
return true;
}
@@ -288,12 +271,7 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
if (ContainerUtil.all(unionType.getMembers(), t -> t instanceof PyClassType ct && ct.isDefinition())) {
return wrapInTypingType(render(unionType.map(type -> type != null ? ((PyClassType)type).toInstance() : null)));
}
// TODO Remove special-casing of "weak" unions
// Exclude Any from "weak" types
if (PyTypeChecker.isUnknown(unionType, false, myTypeEvalContext)) {
if (hideWeakUnions()) {
return render(unionType.excludeNull());
}
// Always put Any at the end of the union
return renderUnion(List.of(render(unionType.excludeNull()), visitUnknownType()));
}
@@ -334,7 +334,7 @@ public class PythonDocumentationProvider implements DocumentationProvider {
* @return string representation of the type
*/
public static @NotNull @NlsSafe String getTypeName(@Nullable PyType type, @NotNull TypeEvalContext context) {
return PyTypeVisitor.visit(type, new PyTypeRenderer.Documentation(context, false)).toString();
return PyTypeVisitor.visit(type, new PyTypeRenderer.Documentation(context)).toString();
}
/**
@@ -358,7 +358,7 @@ public class PythonDocumentationProvider implements DocumentationProvider {
/**
* @param type type which description will be calculated.
* Description is the same as {@link PythonDocumentationProvider#getTypeDescription(PyType, TypeEvalContext)} gives but
* Description is the same as {@link PythonDocumentationProvider#getTypeName(PyType, TypeEvalContext)} gives but
* types are converted to links.
* @param typeOwner element that has the given type, can be {@code null} for synthetic parameters
* @param context type evaluation context
@@ -381,16 +381,6 @@ public class PythonDocumentationProvider implements DocumentationProvider {
body.append(PyTypeVisitor.visit(type, new PyTypeRenderer.RichDocumentation(context, anchor)));
}
/**
* @param type type which description will be calculated
* @param context type evaluation context
* @return more user-friendly description than result of {@link PythonDocumentationProvider#getTypeName(PyType, TypeEvalContext)}.
* {@code Any} is excluded from {@code Union[Any, ...]}-like types.
*/
public static @NotNull String getTypeDescription(@Nullable PyType type, @NotNull TypeEvalContext context) {
return PyTypeVisitor.visit(type, new PyTypeRenderer.Documentation(context, true)).toString();
}
static @NotNull HtmlChunk describeDecorators(@NotNull PyDecoratable decoratable,
@NotNull HtmlChunk separator) {
final HtmlBuilder result = new HtmlBuilder();
@@ -1306,8 +1306,8 @@ class PyTypeHintsInspection : PyInspection() {
?: return
if (!PyTypeChecker.match(commentSelfType, actualSelfType, myTypeEvalContext)) {
val actualSelfTypeDescription = PythonDocumentationProvider.getTypeDescription(actualSelfType, myTypeEvalContext)
val commentSelfTypeDescription = PythonDocumentationProvider.getTypeDescription(commentSelfType, myTypeEvalContext)
val actualSelfTypeDescription = PythonDocumentationProvider.getTypeName(actualSelfType, myTypeEvalContext)
val commentSelfTypeDescription = PythonDocumentationProvider.getTypeName(commentSelfType, myTypeEvalContext)
registerProblem(node.typeComment, PyPsiBundle.message("INSP.type.hints.type.self.not.supertype.its.class",
commentSelfTypeDescription, actualSelfTypeDescription))
@@ -178,7 +178,7 @@ public final class PyCallableParameterImpl implements PyCallableParameter {
final PyType argumentType = getArgumentType(context);
if (!typeFilter.test(argumentType)) {
sb.append(": ");
sb.append(PythonDocumentationProvider.getTypeDescription(argumentType, context));
sb.append(PythonDocumentationProvider.getTypeName(argumentType, context));
renderedAsTyped = true;
}
}
@@ -25,8 +25,8 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.io.File;
import java.util.List;
import java.util.*;
import java.util.List;
/**
* Tests parameter info available via ^P at call sites.
@@ -440,7 +440,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
// PY-22005
public void testWithSpecifiedType() {
final int offset = loadTest(1).get("<arg1>").getTextOffset();
final String expectedInfo = "a1: str, a2: str | None = None, a3: str | int | None = None, a4: int, *args: int, **kwargs: int";
final String expectedInfo = "a1: str, a2: str | None = None, a3: str | int | None = None, a4: int | Any, *args: int, **kwargs: int";
feignCtrlP(offset).check(expectedInfo, new String[]{"a1: str, "});
}
@@ -733,7 +733,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
feignCtrlP(marks.get("<arg4>").getTextOffset()).check("x, y, z: list = ...", new String[]{"x, "});
feignCtrlP(marks.get("<arg5>").getTextOffset()).check("x, y: int = ...", new String[]{"x, "});
feignCtrlP(marks.get("<arg6>").getTextOffset()).check("x, y: str = ...", new String[]{"x, "});
feignCtrlP(marks.get("<arg7>").getTextOffset()).check("x: int = ...", new String[]{"x: int = ..."});
feignCtrlP(marks.get("<arg7>").getTextOffset()).check("x: int | Any = ...", new String[]{"x: int | Any = ..."});
feignCtrlP(marks.get("<arg8>").getTextOffset()).check("x, y, z: list = ...", new String[]{"x, "});
}
);