Respect imports when rendering class names in type hints
#KT-19524 Fixed
This commit is contained in:
@@ -29,7 +29,7 @@ fun provideLambdaImplicitHints(lambda: KtLambdaExpression): List<InlayInfo> {
|
|||||||
val text = buildString {
|
val text = buildString {
|
||||||
append(TYPE_INFO_PREFIX)
|
append(TYPE_INFO_PREFIX)
|
||||||
append("this: ")
|
append("this: ")
|
||||||
append(inlayHintsTypeRenderer.renderType(implicitReceiver.type))
|
append(getInlayHintsTypeRenderer(bindingContext, lambda).renderType(implicitReceiver.type))
|
||||||
}
|
}
|
||||||
return listOf(InlayInfo(text, lbrace.textRange.endOffset))
|
return listOf(InlayInfo(text, lbrace.textRange.endOffset))
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ fun provideLambdaImplicitHints(lambda: KtLambdaExpression): List<InlayInfo> {
|
|||||||
val text = buildString {
|
val text = buildString {
|
||||||
append(TYPE_INFO_PREFIX)
|
append(TYPE_INFO_PREFIX)
|
||||||
append("it: ")
|
append("it: ")
|
||||||
append(inlayHintsTypeRenderer.renderType(type))
|
append(getInlayHintsTypeRenderer(bindingContext, lambda).renderType(type))
|
||||||
}
|
}
|
||||||
return listOf(InlayInfo(text, lbrace.textRange.endOffset))
|
return listOf(InlayInfo(text, lbrace.textRange.endOffset))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,28 +8,56 @@ 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.ClassifierDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
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.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.util.getResolutionScope
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.RenderingFormat
|
import org.jetbrains.kotlin.renderer.RenderingFormat
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
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
|
||||||
|
|
||||||
//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@"
|
||||||
val inlayHintsTypeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
|
||||||
textFormat = RenderingFormat.PLAIN
|
class ImportAwareClassifierNamePolicy(
|
||||||
renderUnabbreviatedType = false
|
val bindingContext: BindingContext,
|
||||||
|
val context: KtElement
|
||||||
|
) : ClassifierNamePolicy {
|
||||||
|
override fun renderClassifier(classifier: ClassifierDescriptor, renderer: DescriptorRenderer): String {
|
||||||
|
if (classifier.containingDeclaration is ClassDescriptor) {
|
||||||
|
val resolutionFacade = context.getResolutionFacade()
|
||||||
|
val scope = context.getResolutionScope(bindingContext, resolutionFacade)
|
||||||
|
if (scope.findClassifier(classifier.name, NoLookupLocation.FROM_IDE) == classifier) {
|
||||||
|
return classifier.name.asString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getInlayHintsTypeRenderer(bindingContext: BindingContext, context: KtElement) =
|
||||||
|
DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
||||||
|
textFormat = RenderingFormat.PLAIN
|
||||||
|
renderUnabbreviatedType = false
|
||||||
|
classifierNamePolicy = ImportAwareClassifierNamePolicy(bindingContext, context)
|
||||||
|
}
|
||||||
|
|
||||||
fun providePropertyTypeHint(elem: PsiElement): List<InlayInfo> {
|
fun providePropertyTypeHint(elem: PsiElement): List<InlayInfo> {
|
||||||
(elem as? KtCallableDeclaration)?.let { property ->
|
(elem as? KtCallableDeclaration)?.let { property ->
|
||||||
property.nameIdentifier?.let { ident ->
|
property.nameIdentifier?.let { ident ->
|
||||||
@@ -50,14 +78,13 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
|
|||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
type = type.immediateSupertypes().singleOrNull() ?: return emptyList()
|
type = type.immediateSupertypes().singleOrNull() ?: return emptyList()
|
||||||
}
|
} else if (name?.isSpecial == true) {
|
||||||
else if (name?.isSpecial == true) {
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (isUnclearType(type, element)) {
|
return if (isUnclearType(type, element)) {
|
||||||
val settings = CodeStyleSettingsManager.getInstance(element.project).currentSettings
|
val settings = CodeStyleSettingsManager.getInstance(element.project).currentSettings
|
||||||
.getCustomSettings(KotlinCodeStyleSettings::class.java)
|
.getCustomSettings(KotlinCodeStyleSettings::class.java)
|
||||||
|
|
||||||
val declString = buildString {
|
val declString = buildString {
|
||||||
append(TYPE_INFO_PREFIX)
|
append(TYPE_INFO_PREFIX)
|
||||||
@@ -66,11 +93,10 @@ fun provideTypeHint(element: KtCallableDeclaration, offset: Int): List<InlayInfo
|
|||||||
append(":")
|
append(":")
|
||||||
if (settings.SPACE_AFTER_TYPE_COLON)
|
if (settings.SPACE_AFTER_TYPE_COLON)
|
||||||
append(" ")
|
append(" ")
|
||||||
append(inlayHintsTypeRenderer.renderType(type))
|
append(getInlayHintsTypeRenderer(element.analyze(), element).renderType(type))
|
||||||
}
|
}
|
||||||
listOf(InlayInfo(declString, offset))
|
listOf(InlayInfo(declString, offset))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,4 +110,19 @@ class InlayTypeHintsTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
HintType.PROPERTY_HINT.option.set(true)
|
HintType.PROPERTY_HINT.option.set(true)
|
||||||
check("""val x = Runnable { }""")
|
check("""val x = Runnable { }""")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testNestedClassImports() {
|
||||||
|
HintType.PROPERTY_HINT.option.set(true)
|
||||||
|
check(
|
||||||
|
"""import kotlin.collections.Map.Entry
|
||||||
|
val entries<hint text=": Set<Entry<Int, String>>" /> = mapOf(1 to "1").entries"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testNestedClassWithoutImport() {
|
||||||
|
HintType.PROPERTY_HINT.option.set(true)
|
||||||
|
check(
|
||||||
|
"""val entries<hint text=": Set<Map.Entry<Int, String>>" /> = mapOf(1 to "1").entries"""
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user