Fix for KT-14819 Quick documentation for special Enum functions doesn't work
#KT-14819 fixed
This commit is contained in:
committed by
Simon Ogorodnik
parent
fa01a4efad
commit
d0cf1b0c5f
@@ -46,4 +46,16 @@ public abstract class Enum<E : Enum<E>>(name: String, ordinal: Int): Comparable<
|
||||
public override final fun equals(other: Any?): Boolean
|
||||
public override final fun hashCode(): Int
|
||||
public override fun toString(): String
|
||||
|
||||
/**
|
||||
* Returns an array containing the constants of this enum type, in the order they're declared.
|
||||
* This method may be used to iterate over the constants.
|
||||
* @values
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
|
||||
* @throws IllegalArgumentException if this enum type has no constant with the specified name
|
||||
* @valueOf
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -27,14 +27,13 @@ import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
|
||||
import org.jetbrains.kotlin.idea.kdoc.KDocRenderer
|
||||
import org.jetbrains.kotlin.idea.kdoc.findKDoc
|
||||
import org.jetbrains.kotlin.idea.kdoc.isBoringBuiltinClass
|
||||
@@ -42,15 +41,18 @@ import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.deprecatedByAnnotationReplaceWithExpression
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.getDeprecations
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||
@@ -102,8 +104,60 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
|
||||
renderCompanionObjectName = true
|
||||
}
|
||||
|
||||
private fun renderEnumSpecialFunction(element: KtClass, functionDescriptor: FunctionDescriptor, quickNavigation: Boolean): String {
|
||||
var renderedDecl = DESCRIPTOR_RENDERER.render(functionDescriptor)
|
||||
|
||||
if (quickNavigation) return renderedDecl
|
||||
|
||||
val declarationDescriptor = element.resolveToDescriptorIfAny()
|
||||
val enumDescriptor = (declarationDescriptor as? ClassDescriptor)?.getSuperClassNotAny() ?: return renderedDecl
|
||||
|
||||
val enumDeclaration =
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, enumDescriptor) as? KtDeclaration ?: return renderedDecl
|
||||
|
||||
val enumSource = SourceNavigationHelper.getNavigationElement(enumDeclaration)
|
||||
val functionName = functionDescriptor.fqNameSafe.shortName().asString()
|
||||
val kdoc = enumSource.findDescendantOfType<KDoc> {
|
||||
it.getChildrenOfType<KDocSection>().any { it.findTagByName(functionName) != null }
|
||||
}
|
||||
|
||||
if (kdoc != null) {
|
||||
val renderedComment = KDocRenderer.renderKDoc(kdoc.getDefaultSection())
|
||||
if (renderedComment.startsWith("<p>")) {
|
||||
renderedDecl += renderedComment
|
||||
}
|
||||
else {
|
||||
renderedDecl = "$renderedDecl<br/>$renderedComment"
|
||||
}
|
||||
}
|
||||
|
||||
return renderedDecl
|
||||
}
|
||||
|
||||
private fun renderEnum(element: KtClass, originalElement: PsiElement?, quickNavigation: Boolean): String? {
|
||||
val referenceExpression = originalElement?.getNonStrictParentOfType<KtReferenceExpression>()
|
||||
if (referenceExpression != null) {
|
||||
// When caret on special enum function (e.g SomeEnum.values<caret>())
|
||||
// element is not an KtReferenceExpression, but KtClass of enum
|
||||
// so reference extracted from originalElement
|
||||
val context = referenceExpression.analyze(BodyResolveMode.PARTIAL)
|
||||
(context[BindingContext.REFERENCE_TARGET, referenceExpression] ?:
|
||||
context[BindingContext.REFERENCE_TARGET, referenceExpression.getChildOfType<KtReferenceExpression>()])?.let {
|
||||
if (it is FunctionDescriptor) // To protect from Some<caret>Enum.values()
|
||||
return renderEnumSpecialFunction(element, it, quickNavigation)
|
||||
}
|
||||
}
|
||||
return renderKotlinDeclaration(element, quickNavigation)
|
||||
}
|
||||
|
||||
private fun getText(element: PsiElement, originalElement: PsiElement?, quickNavigation: Boolean): String? {
|
||||
if (element is KtDeclaration) {
|
||||
|
||||
if (element is KtClass && element.isEnum()) {
|
||||
// When caret on special enum function (e.g SomeEnum.values<caret>())
|
||||
// element is not an KtReferenceExpression, but KtClass of enum
|
||||
return renderEnum(element, originalElement, quickNavigation)
|
||||
}
|
||||
else if (element is KtDeclaration) {
|
||||
return renderKotlinDeclaration(element, quickNavigation)
|
||||
}
|
||||
else if (element is KtNameReferenceExpression && element.getReferencedName() == "it") {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Useless one
|
||||
*/
|
||||
enum class SomeEnum
|
||||
|
||||
fun use() {
|
||||
Some<caret>Enum::class
|
||||
}
|
||||
|
||||
//INFO: <pre><b>public</b> <b>final</b> <b>enum class</b> SomeEnum : <a href="psi_element://kotlin.Enum">Enum</a><<a href="psi_element://SomeEnum">SomeEnum</a>> <i>defined in</i> root package</pre><p>Useless one</p>
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Useless one
|
||||
*/
|
||||
enum class SomeEnum<caret>
|
||||
|
||||
//INFO: <pre><b>public</b> <b>final</b> <b>enum class</b> SomeEnum : <a href="psi_element://kotlin.Enum">Enum</a><<a href="psi_element://SomeEnum">SomeEnum</a>> <i>defined in</i> root package</pre><p>Useless one</p>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Enum of 1, 2
|
||||
*/
|
||||
enum class SomeEnum(val i: Int) {
|
||||
One(1), Two(2);
|
||||
}
|
||||
|
||||
fun use() {
|
||||
Some<caret>Enum.One
|
||||
}
|
||||
|
||||
//INFO: <pre><b>public</b> <b>final</b> <b>enum class</b> SomeEnum : <a href="psi_element://kotlin.Enum">Enum</a><<a href="psi_element://SomeEnum">SomeEnum</a>> <i>defined in</i> root package</pre><p>Enum of 1, 2</p>
|
||||
@@ -0,0 +1,11 @@
|
||||
enum class E {
|
||||
A
|
||||
}
|
||||
|
||||
fun use() {
|
||||
E.valueOf<caret>("A")
|
||||
}
|
||||
|
||||
|
||||
//INFO: <b>public</b> <b>final</b> <b>fun</b> valueOf(value: String): <a href="psi_element://E">E</a> <i>defined in</i> E<p>Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)</p>
|
||||
//INFO: <dl><dt><b>Throws:</b></dt><dd><code>IllegalArgumentException</code> - if this enum type has no constant with the specified name</dd></dl>
|
||||
@@ -0,0 +1,9 @@
|
||||
enum class E {
|
||||
|
||||
}
|
||||
|
||||
fun use() {
|
||||
E.values<caret>()
|
||||
}
|
||||
|
||||
//INFO: <b>public</b> <b>final</b> <b>fun</b> values(): Array<<a href="psi_element://E">E</a>> <i>defined in</i> E<p>Returns an array containing the constants of this enum type, in the order they're declared. This method may be used to iterate over the constants.</p>
|
||||
+30
@@ -144,6 +144,36 @@ public class QuickDocProviderTestGenerated extends AbstractQuickDocProviderTest
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnEnumClassReference.kt")
|
||||
public void testOnEnumClassReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnEnumClassReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnEnumDeclaration.kt")
|
||||
public void testOnEnumDeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnEnumDeclaration.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnEnumUsage.kt")
|
||||
public void testOnEnumUsage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnEnumUsage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnEnumValueOfFunction.kt")
|
||||
public void testOnEnumValueOfFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnEnumValuesFunction.kt")
|
||||
public void testOnEnumValuesFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnEnumValuesFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnFunctionDeclarationWithPackage.kt")
|
||||
public void testOnFunctionDeclarationWithPackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
Reference in New Issue
Block a user