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.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 {
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.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
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.resolveToCall
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
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.incremental.components.NoLookupLocation
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.renderFqName
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.parentsWithSelf
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.typeUtil.containsError
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isEnum
//hack to separate type presentation from param info presentation
const val TYPE_INFO_PREFIX = "@TYPE@"
@@ -106,11 +106,13 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
val declString = buildString {
append(TYPE_INFO_PREFIX)
if (settings.SPACE_BEFORE_TYPE_COLON)
if (settings.SPACE_BEFORE_TYPE_COLON) {
append(" ")
}
append(":")
if (settings.SPACE_AFTER_TYPE_COLON)
if (settings.SPACE_AFTER_TYPE_COLON) {
append(" ")
}
append(getInlayHintsTypeRenderer(element.analyze(), element).renderType(type))
}
listOf(InlayInfo(declString, offset))
@@ -120,21 +122,32 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
}
private fun isUnclearType(type: KotlinType, element: KtCallableDeclaration): Boolean {
if (element is KtProperty) {
val initializer = element.initializer ?: return true
if (initializer is KtConstantExpression || initializer is KtStringTemplateExpression) return false
if (initializer is KtUnaryExpression && initializer.baseExpression is KtConstantExpression) return false
if (initializer is KtCallExpression) {
val resolvedCall = initializer.resolveToCall(BodyResolveMode.FULL)
val resolvedDescriptor = resolvedCall?.candidateDescriptor
if (resolvedDescriptor is SamConstructorDescriptor) {
return false
}
if (resolvedDescriptor is ConstructorDescriptor &&
(resolvedDescriptor.constructedClass.declaredTypeParameters.isEmpty() || initializer.typeArgumentList != null)) {
return false
}
if (element !is KtProperty) return true
val initializer = element.initializer ?: return true
if (initializer is KtConstantExpression || initializer is KtStringTemplateExpression) return false
if (initializer is KtUnaryExpression && initializer.baseExpression is KtConstantExpression) return false
if (initializer is KtCallExpression) {
val resolvedCall = initializer.resolveToCall(BodyResolveMode.FULL)
val resolvedDescriptor = resolvedCall?.candidateDescriptor
if (resolvedDescriptor is SamConstructorDescriptor) {
return false
}
if (resolvedDescriptor is ConstructorDescriptor &&
(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
}
}
@@ -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() {
checkLocalVariable(
"""