Don't show types for enum entries with enum name is present in initializer (KT-26057)

#KT-26057 Fixed
This commit is contained in:
Nikolay Krasko
2018-09-06 12:27:58 +03:00
parent ab3f8db743
commit 307586e435
3 changed files with 105 additions and 21 deletions
@@ -77,6 +77,7 @@ fun KotlinType.isPrimitiveNumberOrNullableType(): Boolean =
fun KotlinType.isTypeParameter(): Boolean = TypeUtils.isTypeParameter(this) fun KotlinType.isTypeParameter(): Boolean = TypeUtils.isTypeParameter(this)
fun KotlinType.isInterface(): Boolean = (constructor.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.INTERFACE fun KotlinType.isInterface(): Boolean = (constructor.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.INTERFACE
fun KotlinType.isEnum(): Boolean = (constructor.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS
fun KotlinType?.isArrayOfNothing(): Boolean { fun KotlinType?.isArrayOfNothing(): Boolean {
if (this == null || !KotlinBuiltIns.isArray(this)) return false if (this == null || !KotlinBuiltIns.isArray(this)) return false
@@ -8,15 +8,13 @@ package org.jetbrains.kotlin.idea.parameterInfo
import com.intellij.codeInsight.hints.InlayInfo import com.intellij.codeInsight.hints.InlayInfo
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
@@ -28,6 +26,7 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.RenderingFormat import org.jetbrains.kotlin.renderer.RenderingFormat
import org.jetbrains.kotlin.renderer.renderFqName import org.jetbrains.kotlin.renderer.renderFqName
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -35,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.containsError import org.jetbrains.kotlin.types.typeUtil.containsError
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isEnum
//hack to separate type presentation from param info presentation //hack to separate type presentation from param info presentation
const val TYPE_INFO_PREFIX = "@TYPE@" const val TYPE_INFO_PREFIX = "@TYPE@"
@@ -106,11 +106,13 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
val declString = buildString { val declString = buildString {
append(TYPE_INFO_PREFIX) append(TYPE_INFO_PREFIX)
if (settings.SPACE_BEFORE_TYPE_COLON) if (settings.SPACE_BEFORE_TYPE_COLON) {
append(" ") append(" ")
}
append(":") append(":")
if (settings.SPACE_AFTER_TYPE_COLON) if (settings.SPACE_AFTER_TYPE_COLON) {
append(" ") append(" ")
}
append(getInlayHintsTypeRenderer(element.analyze(), element).renderType(type)) append(getInlayHintsTypeRenderer(element.analyze(), element).renderType(type))
} }
listOf(InlayInfo(declString, offset)) listOf(InlayInfo(declString, offset))
@@ -120,21 +122,32 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
} }
private fun isUnclearType(type: KotlinType, element: KtCallableDeclaration): Boolean { private fun isUnclearType(type: KotlinType, element: KtCallableDeclaration): Boolean {
if (element is KtProperty) { if (element !is KtProperty) return true
val initializer = element.initializer ?: return true
if (initializer is KtConstantExpression || initializer is KtStringTemplateExpression) return false val initializer = element.initializer ?: return true
if (initializer is KtUnaryExpression && initializer.baseExpression is KtConstantExpression) return false if (initializer is KtConstantExpression || initializer is KtStringTemplateExpression) return false
if (initializer is KtCallExpression) { if (initializer is KtUnaryExpression && initializer.baseExpression is KtConstantExpression) return false
val resolvedCall = initializer.resolveToCall(BodyResolveMode.FULL) if (initializer is KtCallExpression) {
val resolvedDescriptor = resolvedCall?.candidateDescriptor val resolvedCall = initializer.resolveToCall(BodyResolveMode.FULL)
if (resolvedDescriptor is SamConstructorDescriptor) { val resolvedDescriptor = resolvedCall?.candidateDescriptor
return false if (resolvedDescriptor is SamConstructorDescriptor) {
} return false
if (resolvedDescriptor is ConstructorDescriptor && }
(resolvedDescriptor.constructedClass.declaredTypeParameters.isEmpty() || initializer.typeArgumentList != null)) { if (resolvedDescriptor is ConstructorDescriptor &&
return false (resolvedDescriptor.constructedClass.declaredTypeParameters.isEmpty() || initializer.typeArgumentList != null)) {
} return false
} }
} }
if (type.isEnum() && initializer is KtDotQualifiedExpression) {
// Do not show type for enums if initializer has enum entry with explicit enum name: val p = Enum.ENTRY
val enumEntrySelector = initializer.selectorExpression
val enumEntryDescriptor: DeclarationDescriptor? = enumEntrySelector?.resolveMainReferenceToDescriptors()?.singleOrNull()
if (enumEntryDescriptor != null && DescriptorUtils.isEnumEntry(enumEntryDescriptor)) {
return false
}
}
return true return true
} }
@@ -98,6 +98,76 @@ class InlayTypeHintsTest : KotlinLightCodeInsightFixtureTestCase() {
) )
} }
fun testEnumEntry() {
checkPropertyHint(
"""
enum class E { ENTRY }
val test = E.ENTRY
""".trimIndent()
)
}
fun testEnumEntryLikeProperty() {
checkPropertyHint(
"""
enum class E {
ENTRY;
companion object {
val test: E = ENTRY
}
}
val test<hint text=": E"/> = E.test
""".trimIndent()
)
}
fun testEnumEntryLikeFunction() {
checkPropertyHint(
"""
enum class E { ENTRY;
companion object {
fun test(): E = ENTRY
}
}
val test<hint text=": E"/> = E.test()
""".trimIndent()
)
}
fun testImportedEnumEntry() {
checkPropertyHint(
"""
import E.ENTRY
enum class E { ENTRY }
val test<hint text=": E"/> = ENTRY
""".trimIndent()
)
}
fun testEnumEntryCompanion() {
checkPropertyHint(
"""
enum class E {
ENTRY;
companion object {}
}
val test<hint text=": E"/> = E.Companion
"""
)
}
fun testEnumEntryQualified() {
checkPropertyHint(
"""
package a
enum class E { ENTRY }
val test = a.E.ENTRY
"""
)
}
fun testDestructuring() { fun testDestructuring() {
checkLocalVariable( checkLocalVariable(
""" """