diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index fbba6129fcfd..4253fe4de0b9 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -48,6 +48,7 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.pyi.PyiUtil; import com.jetbrains.python.toolbox.ChainIterable; import one.util.streamex.StreamEx; import org.apache.commons.httpclient.HttpClient; @@ -156,6 +157,9 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i @NotNull Function escapedNameMapper, @NotNull Function escaper, @NotNull TypeEvalContext context) { + final List overloads = PyiUtil.getOverloads(function, context); + if (!overloads.isEmpty()) return describeOverload(function, overloads, escapedNameMapper, escaper, context); + final ChainIterable result = new ChainIterable<>(); final String name = function.getName(); @@ -172,6 +176,33 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i return result; } + @NotNull + private static ChainIterable describeOverload(@NotNull PyFunction function, + @NotNull List overloads, + @NotNull Function escapedNameMapper, + @NotNull Function escaper, + @NotNull TypeEvalContext context) { + final ChainIterable result = new ChainIterable<>(); + final String name = function.getName(); + + result + .addItem(escaper.apply("def ")) + .addItem(escapedNameMapper.apply(escaper.apply(name))) + .addItem(escaper.apply("\nPossible types:\n")); + + boolean first = true; + for (PyFunction overload : overloads) { + if (!first) { + result.addItem(escaper.apply("\n")); + } + result.addItem(escaper.apply("\u2022 ")); + describeTypeWithLinks(context.getType(overload), context, function, result); + first = false; + } + + return result; + } + @Nullable private static String describeExpression(@NotNull PyExpression expression, @NotNull PsiElement originalElement, diff --git a/python/testData/quickdoc/DocOnImplementationWithOverloads.html b/python/testData/quickdoc/DocOnImplementationWithOverloads.html new file mode 100644 index 000000000000..f6f2e96bd38f --- /dev/null +++ b/python/testData/quickdoc/DocOnImplementationWithOverloads.html @@ -0,0 +1 @@ +def foo
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file diff --git a/python/testData/quickdoc/DocOnImplementationWithOverloads.py b/python/testData/quickdoc/DocOnImplementationWithOverloads.py new file mode 100644 index 000000000000..215fc36a58bf --- /dev/null +++ b/python/testData/quickdoc/DocOnImplementationWithOverloads.py @@ -0,0 +1,15 @@ +from typing import overload + + +@overload +def foo(param: str) -> str: + pass + + +@overload +def foo(param: int) -> int: + pass + + +def foo(param: bool) -> bool: + pass \ No newline at end of file diff --git a/python/testData/quickdoc/HoverOverOverloads.html b/python/testData/quickdoc/HoverOverOverloads.html new file mode 100644 index 000000000000..f12dfbb035c5 --- /dev/null +++ b/python/testData/quickdoc/HoverOverOverloads.html @@ -0,0 +1,5 @@ +@typing.overload +def foo +Possible types: +• (p: int) -> int +• (p: str) -> str \ No newline at end of file diff --git a/python/testData/quickdoc/HoverOverOverloads.py b/python/testData/quickdoc/HoverOverOverloads.py new file mode 100644 index 000000000000..cd43832ba896 --- /dev/null +++ b/python/testData/quickdoc/HoverOverOverloads.py @@ -0,0 +1,14 @@ +import typing + + +@typing.overload +def foo(p: int) -> int: + pass + + +@typing.overload +def foo(p: str) -> str: + pass + + +foo(1) \ No newline at end of file diff --git a/python/testData/quickdoc/HoverOverOverloadsAndImplementation.html b/python/testData/quickdoc/HoverOverOverloadsAndImplementation.html new file mode 100644 index 000000000000..099c19496221 --- /dev/null +++ b/python/testData/quickdoc/HoverOverOverloadsAndImplementation.html @@ -0,0 +1,4 @@ +def foo +Possible types: +• (param: str) -> str +• (param: int) -> int \ No newline at end of file diff --git a/python/testData/quickdoc/HoverOverOverloadsAndImplementation.py b/python/testData/quickdoc/HoverOverOverloadsAndImplementation.py new file mode 100644 index 000000000000..f7e94a505a50 --- /dev/null +++ b/python/testData/quickdoc/HoverOverOverloadsAndImplementation.py @@ -0,0 +1,18 @@ +from typing import overload + + +@overload +def foo(param: str) -> str: + pass + + +@overload +def foo(param: int) -> int: + pass + + +def foo(param: bool) -> bool: + pass + + +foo(1) \ No newline at end of file diff --git a/python/testData/quickdoc/Overloads.html b/python/testData/quickdoc/Overloads.html new file mode 100644 index 000000000000..6ad480147de0 --- /dev/null +++ b/python/testData/quickdoc/Overloads.html @@ -0,0 +1 @@ +@typing.overload
def foo
Possible types:
• (p: int) -> int
• (p: str) -> str
\ No newline at end of file diff --git a/python/testData/quickdoc/Overloads.py b/python/testData/quickdoc/Overloads.py new file mode 100644 index 000000000000..cd43832ba896 --- /dev/null +++ b/python/testData/quickdoc/Overloads.py @@ -0,0 +1,14 @@ +import typing + + +@typing.overload +def foo(p: int) -> int: + pass + + +@typing.overload +def foo(p: str) -> str: + pass + + +foo(1) \ No newline at end of file diff --git a/python/testData/quickdoc/OverloadsAndImplementation.html b/python/testData/quickdoc/OverloadsAndImplementation.html new file mode 100644 index 000000000000..f6f2e96bd38f --- /dev/null +++ b/python/testData/quickdoc/OverloadsAndImplementation.html @@ -0,0 +1 @@ +def foo
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file diff --git a/python/testData/quickdoc/OverloadsAndImplementation.py b/python/testData/quickdoc/OverloadsAndImplementation.py new file mode 100644 index 000000000000..f7e94a505a50 --- /dev/null +++ b/python/testData/quickdoc/OverloadsAndImplementation.py @@ -0,0 +1,18 @@ +from typing import overload + + +@overload +def foo(param: str) -> str: + pass + + +@overload +def foo(param: int) -> int: + pass + + +def foo(param: bool) -> bool: + pass + + +foo(1) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index 730b875b21ee..3ffdeb95c9f9 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -351,4 +351,35 @@ public class PyQuickDocTest extends LightMarkedTestCase { public void testHoverOverClassWithAllKindSuperClassExpressions() { runWithLanguageLevel(LanguageLevel.PYTHON30, this::checkHover); } + + // PY-23247 + public void testOverloads() { + runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly); + } + + // PY-23247 + public void testHoverOverOverloads() { + runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHover); + } + + // PY-23247 + public void testOverloadsAndImplementation() { + runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly); + } + + // PY-23247 + public void testHoverOverOverloadsAndImplementation() { + runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHover); + } + + // PY-23247 + public void testDocOnImplementationWithOverloads() { + runWithLanguageLevel( + LanguageLevel.PYTHON35, + () -> { + final PsiElement originalElement = loadTest().get(""); + checkByHTML(myProvider.generateDoc(originalElement.getParent(), originalElement)); + } + ); + } }