From de28a41caa9184d9616be5b0374b8cf686176616 Mon Sep 17 00:00:00 2001 From: Yuku Kotani Date: Tue, 28 Apr 2020 00:15:24 +0900 Subject: [PATCH] KT-32163: Open Quick Documentation when cursor inside function / constructor brackets (#2502) * Show function docs when cursor is in args of the function call * Show constructor docs when cursor is in args of the constructor call * Show function docs when cursor is in args of the kt function call * Add some tests * Use JavaDocumentationProvider to fetch java method document * Support caret in params #KT-32163 fixed --- .../idea/KotlinDocumentationProvider.kt | 20 ++++++++++++++++++- .../JavaClassConstructorUsedInKotlin.kt | 7 +++++++ ...JavaClassConstructorUsedInKotlin_Data.java | 11 ++++++++++ .../quickDoc/JavaMethodUsedInKotlinInParen.kt | 10 ++++++++++ .../JavaMethodUsedInKotlinInParen_Data.java | 8 ++++++++ .../editor/quickDoc/OnMethodUsageInParen.kt | 18 +++++++++++++++++ .../AbstractQuickDocProviderTest.java | 19 ++++++++++++++++++ .../QuickDocProviderTestGenerated.java | 15 ++++++++++++++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin.kt create mode 100644 idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin_Data.java create mode 100644 idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen.kt create mode 100644 idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen_Data.java create mode 100644 idea/testData/editor/quickDoc/OnMethodUsageInParen.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt index d708bbe67ef..68c68c06876 100644 --- a/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinDocumentationProvider.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea import com.google.common.html.HtmlEscapers +import com.intellij.codeInsight.documentation.DocumentationManager import com.intellij.codeInsight.documentation.DocumentationManagerUtil import com.intellij.codeInsight.javadoc.JavaDocInfoGeneratorFactory import com.intellij.lang.documentation.AbstractDocumentationProvider @@ -13,7 +14,12 @@ import com.intellij.lang.documentation.DocumentationMarkup.* import com.intellij.lang.java.JavaDocumentationProvider import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Editor -import com.intellij.psi.* +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.impl.compiled.ClsMethodImpl import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.descriptors.* @@ -156,6 +162,7 @@ open class KotlinDocumentationProviderCompatBase : AbstractDocumentationProvider companion object { private val LOG = Logger.getInstance(KotlinDocumentationProvider::class.java) + private val javaDocumentProvider = JavaDocumentationProvider() private val DESCRIPTOR_RENDERER = DescriptorRenderer.HTML.withOptions { classifierNamePolicy = HtmlClassifierNamePolicy(ClassifierNamePolicy.SHORT) @@ -270,6 +277,17 @@ open class KotlinDocumentationProviderCompatBase : AbstractDocumentationProvider } else if (element is KtLightDeclaration<*, *>) { val origin = element.kotlinOrigin ?: return null return renderKotlinDeclaration(origin, quickNavigation) + } else if (element is KtValueArgumentList) { + val referenceExpression = element.prevSibling as? KtSimpleNameExpression ?: return null + val calledElement = referenceExpression.mainReference.resolve() + if (calledElement is KtNamedFunction || calledElement is KtConstructor<*>) { // In case of Kotlin function or constructor + return renderKotlinDeclaration(calledElement as KtExpression, quickNavigation) + } else if (calledElement is ClsMethodImpl || calledElement is PsiMethod) { // In case of java function or constructor + return javaDocumentProvider.generateDoc(calledElement, referenceExpression) + } + } else if (element is KtCallExpression) { + val calledElement = element.referenceExpression()?.mainReference?.resolve() + return calledElement?.let { getTextImpl(it, originalElement, quickNavigation) } } else if (element.isModifier()) { when (element.text) { KtTokens.LATEINIT_KEYWORD.value -> return KotlinBundle.message("quick.doc.text.lateinit") diff --git a/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin.kt b/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin.kt new file mode 100644 index 00000000000..0be5b523ccf --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin.kt @@ -0,0 +1,7 @@ +fun testing() { + SomeClassWithParen("param", 1) +} + +//INFO:
SomeClassWithParen
@Contract(pure = true)  +//INFO: public SomeClassWithParen(String str, +//INFO: int num)

Inferred annotations:

@org.jetbrains.annotations.Contract(pure = true)

diff --git a/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin_Data.java b/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin_Data.java new file mode 100644 index 00000000000..57781595074 --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin_Data.java @@ -0,0 +1,11 @@ +/** + * Some Java Class + */ +public class SomeClassWithParen { + String str; + int num; + public SomeClassWithParen(String str, int num) { + this.str = str; + this.num = num; + } +} \ No newline at end of file diff --git a/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen.kt b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen.kt new file mode 100644 index 00000000000..711b0fe59b6 --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen.kt @@ -0,0 +1,10 @@ +fun ktTestWithParen() { + TestWithParen.foo("SomeTest", 1) +} + +//INFO:
TestWithParen
@Contract(value = "_, _ -> new", pure = true)  +//INFO: @NotNull  +//INFO: public static Object[] foo(String str, +//INFO: int num)
+//INFO: Java Method +//INFO:

Inferred annotations:

@org.jetbrains.annotations.Contract(value = "_, _ -> new", pure = true) @org.jetbrains.annotations.NotNull

diff --git a/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen_Data.java b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen_Data.java new file mode 100644 index 00000000000..3dbca4c5b2b --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen_Data.java @@ -0,0 +1,8 @@ +class TestWithParen { + /** + * Java Method + */ + public static Object[] foo(String str, int num) { + return new Object[0]; + } +} \ No newline at end of file diff --git a/idea/testData/editor/quickDoc/OnMethodUsageInParen.kt b/idea/testData/editor/quickDoc/OnMethodUsageInParen.kt new file mode 100644 index 00000000000..49be5f402c8 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageInParen.kt @@ -0,0 +1,18 @@ +/** +Some documentation + + * @param a Some int + * @param b String + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
OnMethodUsageInParen.kt
public fun testMethod( +//INFO: a: Int, +//INFO: b: String +//INFO: ): Unit

Some documentation

Params:

a - Some int

b - String

diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractQuickDocProviderTest.java b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractQuickDocProviderTest.java index 4bec92b2692..b797fc1978f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractQuickDocProviderTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractQuickDocProviderTest.java @@ -6,6 +6,9 @@ package org.jetbrains.kotlin.idea.editor.quickDoc; import com.intellij.codeInsight.documentation.DocumentationManager; +import com.intellij.codeInsight.hint.ParameterInfoController; +import com.intellij.codeInsight.lookup.LookupEx; +import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; @@ -32,6 +35,22 @@ public abstract class AbstractQuickDocProviderTest extends KotlinLightCodeInsigh PsiElement targetElement = documentationManager.findTargetElement(myFixture.getEditor(), myFixture.getFile()); PsiElement originalElement = DocumentationManager.getOriginalElement(targetElement); + PsiElement list = ParameterInfoController.findArgumentList(myFixture.getFile(), myFixture.getEditor().getCaretModel().getOffset(), -1); + PsiElement expressionList = null; + if (list != null) { + LookupEx lookup = LookupManager.getInstance(myFixture.getProject()).getActiveLookup(); + if (lookup != null) { + expressionList = null; // take completion variants for documentation then + } + else { + expressionList = list; + } + } + + if (targetElement == null && expressionList != null) { + targetElement = expressionList; + } + String info = DocumentationManager.getProviderFromElement(targetElement).generateDoc(targetElement, originalElement); if (info != null) { info = StringUtil.convertLineSeparators(info); diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocProviderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocProviderTestGenerated.java index cc270cc7bec..acc30f72095 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocProviderTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocProviderTestGenerated.java @@ -98,6 +98,11 @@ public class QuickDocProviderTestGenerated extends AbstractQuickDocProviderTest runTest("idea/testData/editor/quickDoc/IndentedCodeBlock.kt"); } + @TestMetadata("JavaClassConstructorUsedInKotlin.kt") + public void testJavaClassConstructorUsedInKotlin() throws Exception { + runTest("idea/testData/editor/quickDoc/JavaClassConstructorUsedInKotlin.kt"); + } + @TestMetadata("JavaClassUsedInKotlin.kt") public void testJavaClassUsedInKotlin() throws Exception { runTest("idea/testData/editor/quickDoc/JavaClassUsedInKotlin.kt"); @@ -118,6 +123,11 @@ public class QuickDocProviderTestGenerated extends AbstractQuickDocProviderTest runTest("idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt"); } + @TestMetadata("JavaMethodUsedInKotlinInParen.kt") + public void testJavaMethodUsedInKotlinInParen() throws Exception { + runTest("idea/testData/editor/quickDoc/JavaMethodUsedInKotlinInParen.kt"); + } + @TestMetadata("KotlinClassUsedFromJava.java") public void testKotlinClassUsedFromJava() throws Exception { runTest("idea/testData/editor/quickDoc/KotlinClassUsedFromJava.java"); @@ -203,6 +213,11 @@ public class QuickDocProviderTestGenerated extends AbstractQuickDocProviderTest runTest("idea/testData/editor/quickDoc/OnMethodUsage.kt"); } + @TestMetadata("OnMethodUsageInParen.kt") + public void testOnMethodUsageInParen() throws Exception { + runTest("idea/testData/editor/quickDoc/OnMethodUsageInParen.kt"); + } + @TestMetadata("OnMethodUsageMultiline.kt") public void testOnMethodUsageMultiline() throws Exception { runTest("idea/testData/editor/quickDoc/OnMethodUsageMultiline.kt");