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
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun testing() {
|
||||
SomeClassWithParen("param", 1<caret>)
|
||||
}
|
||||
|
||||
//INFO: <div class='definition'><pre><a href="psi_element://SomeClassWithParen"><code>SomeClassWithParen</code></a><br><i>@Contract(pure = true)</i>
|
||||
//INFO: public <b>SomeClassWithParen</b>(<a href="psi_element://java.lang.String"><code>String</code></a> str,
|
||||
//INFO: int num)</pre></div><table class='sections'><p><tr><td valign='top' class='section'><p><i>Inferred</i> annotations:</td><td valign='top'><p><i>@org.jetbrains.annotations.Contract(pure = true)</i></td></table>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fun ktTestWithParen() {
|
||||
TestWithParen.foo("SomeTest", 1<caret>)
|
||||
}
|
||||
|
||||
//INFO: <div class='definition'><pre><a href="psi_element://TestWithParen"><code>TestWithParen</code></a><br><i>@Contract(value = "_, _ -> new", pure = true)</i>
|
||||
//INFO: <i>@<a href="psi_element://org.jetbrains.annotations.NotNull"><code>NotNull</code></a></i>
|
||||
//INFO: public static <a href="psi_element://java.lang.Object"><code>Object</code></a>[] <b>foo</b>(<a href="psi_element://java.lang.String"><code>String</code></a> str,
|
||||
//INFO: int num)</pre></div><div class='content'>
|
||||
//INFO: Java Method
|
||||
//INFO: <p></div><table class='sections'><p><tr><td valign='top' class='section'><p><i>Inferred</i> annotations:</td><td valign='top'><p><i>@org.jetbrains.annotations.Contract(value = "_, _ -> new", pure = true)</i> <i>@<a href="psi_element://org.jetbrains.annotations.NotNull">org.jetbrains.annotations.NotNull</a></i></td></table>
|
||||
@@ -0,0 +1,8 @@
|
||||
class TestWithParen {
|
||||
/**
|
||||
* Java Method
|
||||
*/
|
||||
public static Object[] foo(String str, int num) {
|
||||
return new Object[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
Some documentation
|
||||
|
||||
* @param a Some int
|
||||
* @param b String
|
||||
*/
|
||||
fun testMethod(a: Int, b: String) {
|
||||
|
||||
}
|
||||
|
||||
fun test() {
|
||||
testMethod(<caret>1, "value")
|
||||
}
|
||||
|
||||
//INFO: <div class='definition'><pre><font color="808080"><i>OnMethodUsageInParen.kt</i></font><br>public fun <b>testMethod</b>(
|
||||
//INFO: a: Int,
|
||||
//INFO: b: String
|
||||
//INFO: ): Unit</pre></div><div class='content'><p>Some documentation</p></div><table class='sections'><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><p><code>a</code> - Some int<p><code>b</code> - String</td></table>
|
||||
+19
@@ -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);
|
||||
|
||||
+15
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user