FIR IDE: allow type rendering only in analysis session
This commit is contained in:
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.codeInsight
|
|||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.analyseInModalWindow
|
import org.jetbrains.kotlin.idea.frontend.api.analyseInModalWindow
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.render
|
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
|
||||||
class KotlinHighLevelExpressionTypeProvider : KotlinExpressionTypeProvider() {
|
class KotlinHighLevelExpressionTypeProvider : KotlinExpressionTypeProvider() {
|
||||||
|
|||||||
+8
-12
@@ -19,8 +19,6 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.render
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
||||||
@@ -36,7 +34,7 @@ internal class KotlinFirLookupElementFactory {
|
|||||||
fun KtAnalysisSession.createLookupElement(symbol: KtNamedSymbol): LookupElement? {
|
fun KtAnalysisSession.createLookupElement(symbol: KtNamedSymbol): LookupElement? {
|
||||||
val elementBuilder = when (symbol) {
|
val elementBuilder = when (symbol) {
|
||||||
is KtFunctionSymbol -> with(functionLookupElementFactory) { createLookup(symbol) }
|
is KtFunctionSymbol -> with(functionLookupElementFactory) { createLookup(symbol) }
|
||||||
is KtVariableLikeSymbol -> variableLookupElementFactory.createLookup(symbol)
|
is KtVariableLikeSymbol -> with(variableLookupElementFactory) { createLookup(symbol) }
|
||||||
is KtClassLikeSymbol -> classLookupElementFactory.createLookup(symbol)
|
is KtClassLikeSymbol -> classLookupElementFactory.createLookup(symbol)
|
||||||
is KtTypeParameterSymbol -> typeParameterLookupElementFactory.createLookup(symbol)
|
is KtTypeParameterSymbol -> typeParameterLookupElementFactory.createLookup(symbol)
|
||||||
else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol")
|
else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol")
|
||||||
@@ -66,9 +64,9 @@ private class TypeParameterLookupElementFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class VariableLookupElementFactory {
|
private class VariableLookupElementFactory {
|
||||||
fun createLookup(symbol: KtVariableLikeSymbol): LookupElementBuilder {
|
fun KtAnalysisSession.createLookup(symbol: KtVariableLikeSymbol): LookupElementBuilder {
|
||||||
return LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString())
|
return LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString())
|
||||||
.withTypeText(ShortNamesRenderer.renderType(symbol.type))
|
.withTypeText(symbol.type.render())
|
||||||
.withInsertHandler(createInsertHandler(symbol))
|
.withInsertHandler(createInsertHandler(symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ private class FunctionLookupElementFactory {
|
|||||||
return try {
|
return try {
|
||||||
LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString())
|
LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString())
|
||||||
.withTailText(getTailText(symbol), true)
|
.withTailText(getTailText(symbol), true)
|
||||||
.withTypeText(ShortNamesRenderer.renderType(symbol.type))
|
.withTypeText(symbol.type.render())
|
||||||
.withInsertHandler(createInsertHandler(symbol))
|
.withInsertHandler(createInsertHandler(symbol))
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is ControlFlowException) throw e
|
if (e is ControlFlowException) throw e
|
||||||
@@ -92,7 +90,7 @@ private class FunctionLookupElementFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KtAnalysisSession.getTailText(symbol: KtFunctionSymbol): String {
|
private fun KtAnalysisSession.getTailText(symbol: KtFunctionSymbol): String {
|
||||||
return if (insertLambdaBraces(symbol)) " {...}" else ShortNamesRenderer.renderFunctionParameters(symbol)
|
return if (insertLambdaBraces(symbol)) " {...}" else with(ShortNamesRenderer) { renderFunctionParameters(symbol) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtAnalysisSession.insertLambdaBraces(symbol: KtFunctionSymbol): Boolean {
|
private fun KtAnalysisSession.insertLambdaBraces(symbol: KtFunctionSymbol): Boolean {
|
||||||
@@ -215,13 +213,11 @@ private open class QuotedNamesAwareInsertionHandler(private val name: Name) : In
|
|||||||
|
|
||||||
|
|
||||||
private object ShortNamesRenderer {
|
private object ShortNamesRenderer {
|
||||||
fun renderFunctionParameters(function: KtFunctionSymbol): String =
|
fun KtAnalysisSession.renderFunctionParameters(function: KtFunctionSymbol): String =
|
||||||
function.valueParameters.joinToString(", ", "(", ")") { renderFunctionParameter(it) }
|
function.valueParameters.joinToString(", ", "(", ")") { renderFunctionParameter(it) }
|
||||||
|
|
||||||
fun renderType(ktType: KtType): String = ktType.render()
|
private fun KtAnalysisSession.renderFunctionParameter(param: KtFunctionParameterSymbol): String =
|
||||||
|
"${if (param.isVararg) "vararg " else ""}${param.name.asString()}: ${param.type.render()}"
|
||||||
private fun renderFunctionParameter(param: KtFunctionParameterSymbol): String =
|
|
||||||
"${if (param.isVararg) "vararg " else ""}${param.name.asString()}: ${renderType(param.type)}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Document.isTextAt(offset: Int, text: String) =
|
private fun Document.isTextAt(offset: Int, text: String) =
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ internal class FunctionCallHighlightingVisitor(
|
|||||||
|
|
||||||
private fun getTextAttributesForCal(call: KtCall): TextAttributesKey? = when {
|
private fun getTextAttributesForCal(call: KtCall): TextAttributesKey? = when {
|
||||||
call.isSuccessCallOf<KtFunctionSymbol> { it.isSuspend } -> Colors.SUSPEND_FUNCTION_CALL
|
call.isSuccessCallOf<KtFunctionSymbol> { it.isSuspend } -> Colors.SUSPEND_FUNCTION_CALL
|
||||||
call is KtFunctionCall -> when (val function = call.targetFunction) {
|
call is KtFunctionCall -> when (val function = call.targetFunction.getSuccessCallSymbolOrNull()) {
|
||||||
is KtConstructorSymbol -> Colors.CONSTRUCTOR_CALL
|
is KtConstructorSymbol -> Colors.CONSTRUCTOR_CALL
|
||||||
is KtAnonymousFunctionSymbol -> null
|
is KtAnonymousFunctionSymbol -> null
|
||||||
is KtFunctionSymbol -> when {
|
is KtFunctionSymbol -> when {
|
||||||
|
|||||||
+6
-1
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
*
|
*
|
||||||
* To create analysis session consider using [analyze]
|
* To create analysis session consider using [analyze]
|
||||||
*/
|
*/
|
||||||
abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTokenOwner {
|
abstract class KtAnalysisSession(final override val token: ValidityToken) : ValidityTokenOwner {
|
||||||
protected abstract val smartCastProvider: KtSmartCastProvider
|
protected abstract val smartCastProvider: KtSmartCastProvider
|
||||||
protected abstract val typeProvider: KtTypeProvider
|
protected abstract val typeProvider: KtTypeProvider
|
||||||
protected abstract val diagnosticProvider: KtDiagnosticProvider
|
protected abstract val diagnosticProvider: KtDiagnosticProvider
|
||||||
@@ -43,6 +43,8 @@ abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTo
|
|||||||
protected abstract val callResolver: KtCallResolver
|
protected abstract val callResolver: KtCallResolver
|
||||||
protected abstract val completionCandidateChecker: KtCompletionCandidateChecker
|
protected abstract val completionCandidateChecker: KtCompletionCandidateChecker
|
||||||
protected abstract val symbolDeclarationOverridesProvider: KtSymbolDeclarationOverridesProvider
|
protected abstract val symbolDeclarationOverridesProvider: KtSymbolDeclarationOverridesProvider
|
||||||
|
@Suppress("LeakingThis")
|
||||||
|
protected open val typeRenderer: KtTypeRenderer = KtDefaultTypeRenderer(this, token)
|
||||||
|
|
||||||
/// TODO: get rid of
|
/// TODO: get rid of
|
||||||
@Deprecated("Used only in completion now, temporary")
|
@Deprecated("Used only in completion now, temporary")
|
||||||
@@ -143,4 +145,7 @@ abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTo
|
|||||||
psiFakeCompletionExpression,
|
psiFakeCompletionExpression,
|
||||||
psiReceiverExpression
|
psiReceiverExpression
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun KtType.render(options: KtTypeRendererOptions = KtTypeRendererOptions.DEFAULT): String =
|
||||||
|
typeRenderer.render(this, options)
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -10,7 +10,6 @@ import com.intellij.openapi.components.service
|
|||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.progress.ProgressIndicator
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
import com.intellij.openapi.progress.Task
|
import com.intellij.openapi.progress.Task
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.render
|
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.utils.PrintingLogger
|
import org.jetbrains.kotlin.utils.PrintingLogger
|
||||||
|
|||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.frontend.api.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.*
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.*
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
abstract class KtTypeRenderer : KtAnalysisSessionComponent() {
|
||||||
|
abstract fun render(type: KtType, options: KtTypeRendererOptions): String
|
||||||
|
}
|
||||||
|
|
||||||
|
data class KtTypeRendererOptions(
|
||||||
|
val renderFqNames: Boolean,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val DEFAULT = KtTypeRendererOptions(
|
||||||
|
renderFqNames = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtDefaultTypeRenderer(override val analysisSession: KtAnalysisSession, override val token: ValidityToken) : KtTypeRenderer() {
|
||||||
|
override fun render(type: KtType, options: KtTypeRendererOptions): String = type.withValidityAssertion {
|
||||||
|
buildString { render(type, options) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.render(type: KtType, options: KtTypeRendererOptions) {
|
||||||
|
when (type) {
|
||||||
|
is KtDenotableType -> when (type) {
|
||||||
|
is KtClassType -> {
|
||||||
|
render(type.classId, options)
|
||||||
|
renderTypeArgumentsIfNotEmpty(type.typeArguments, options)
|
||||||
|
renderNullability(type.nullability)
|
||||||
|
}
|
||||||
|
is KtTypeParameterType -> {
|
||||||
|
append(type.name.asString())
|
||||||
|
renderNullability(type.nullability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtNonDenotableType -> when (type) {
|
||||||
|
is KtFlexibleType -> inParens {
|
||||||
|
render(type.lowerBound, options)
|
||||||
|
append("..")
|
||||||
|
render(type.upperBound, options)
|
||||||
|
}
|
||||||
|
is KtIntersectionType -> inParens {
|
||||||
|
type.conjuncts.forEachIndexed { index, conjunct ->
|
||||||
|
render(conjunct, options)
|
||||||
|
if (index != type.conjuncts.lastIndex) {
|
||||||
|
append("&")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtErrorType -> {
|
||||||
|
append(type.error)
|
||||||
|
}
|
||||||
|
else -> error("Unsupported type ${type::class}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.renderTypeArgumentsIfNotEmpty(typeArguments: List<KtTypeArgument>, options: KtTypeRendererOptions) {
|
||||||
|
if (typeArguments.isNotEmpty()) {
|
||||||
|
append("<")
|
||||||
|
typeArguments.forEachIndexed { index, typeArgument ->
|
||||||
|
render(typeArgument, options)
|
||||||
|
if (index != typeArguments.lastIndex) {
|
||||||
|
append(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append(">")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.render(typeArgument: KtTypeArgument, options: KtTypeRendererOptions) {
|
||||||
|
when (typeArgument) {
|
||||||
|
KtStarProjectionTypeArgument -> {
|
||||||
|
append("*")
|
||||||
|
}
|
||||||
|
is KtTypeArgumentWithVariance -> {
|
||||||
|
val varianceWithSpace = when (typeArgument.variance) {
|
||||||
|
KtTypeArgumentVariance.COVARIANT -> "out "
|
||||||
|
KtTypeArgumentVariance.CONTRAVARIANT -> "in "
|
||||||
|
KtTypeArgumentVariance.INVARIANT -> ""
|
||||||
|
}
|
||||||
|
append(varianceWithSpace)
|
||||||
|
render(typeArgument.type, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.renderNullability(nullability: KtTypeNullability) {
|
||||||
|
if (nullability == KtTypeNullability.NULLABLE) {
|
||||||
|
append("?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StringBuilder.render(classId: ClassId, options: KtTypeRendererOptions) {
|
||||||
|
if (options.renderFqNames) {
|
||||||
|
append(classId.asString().replace('/', '.'))
|
||||||
|
} else {
|
||||||
|
append(classId.shortClassName.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun StringBuilder.inParens(render: StringBuilder.() -> Unit) {
|
||||||
|
append("(")
|
||||||
|
render()
|
||||||
|
append(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
-106
@@ -7,109 +7,3 @@ package org.jetbrains.kotlin.idea.frontend.api.types
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.*
|
import org.jetbrains.kotlin.idea.frontend.api.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
private object KtTypeRenderer {
|
|
||||||
fun render(type: KtType, options: KtTypeRendererOptions = KtTypeRendererOptions.DEFAULT): String = type.withValidityAssertion {
|
|
||||||
buildString { render(type, options) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun StringBuilder.render(type: KtType, options: KtTypeRendererOptions) {
|
|
||||||
when (type) {
|
|
||||||
is KtDenotableType -> when (type) {
|
|
||||||
is KtClassType -> {
|
|
||||||
render(type.classId, options)
|
|
||||||
renderTypeArgumentsIfNotEmpty(type.typeArguments, options)
|
|
||||||
renderNullability(type.nullability)
|
|
||||||
}
|
|
||||||
is KtTypeParameterType -> {
|
|
||||||
append(type.name.asString())
|
|
||||||
renderNullability(type.nullability)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtNonDenotableType -> when (type) {
|
|
||||||
is KtFlexibleType -> inParens {
|
|
||||||
render(type.lowerBound, options)
|
|
||||||
append("..")
|
|
||||||
render(type.upperBound, options)
|
|
||||||
}
|
|
||||||
is KtIntersectionType -> inParens {
|
|
||||||
type.conjuncts.forEachIndexed { index, conjunct ->
|
|
||||||
render(conjunct, options)
|
|
||||||
if (index != type.conjuncts.lastIndex) {
|
|
||||||
append("&")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtErrorType -> {
|
|
||||||
append(type.error)
|
|
||||||
}
|
|
||||||
else -> error("Unsupported type ${type::class}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun StringBuilder.renderTypeArgumentsIfNotEmpty(typeArguments: List<KtTypeArgument>, options: KtTypeRendererOptions) {
|
|
||||||
if (typeArguments.isNotEmpty()) {
|
|
||||||
append("<")
|
|
||||||
typeArguments.forEachIndexed { index, typeArgument ->
|
|
||||||
render(typeArgument, options)
|
|
||||||
if (index != typeArguments.lastIndex) {
|
|
||||||
append(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
append(">")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun StringBuilder.render(typeArgument: KtTypeArgument, options: KtTypeRendererOptions) {
|
|
||||||
when (typeArgument) {
|
|
||||||
KtStarProjectionTypeArgument -> {
|
|
||||||
append("*")
|
|
||||||
}
|
|
||||||
is KtTypeArgumentWithVariance -> {
|
|
||||||
val varianceWithSpace = when (typeArgument.variance) {
|
|
||||||
KtTypeArgumentVariance.COVARIANT -> "out "
|
|
||||||
KtTypeArgumentVariance.CONTRAVARIANT -> "in "
|
|
||||||
KtTypeArgumentVariance.INVARIANT -> ""
|
|
||||||
}
|
|
||||||
append(varianceWithSpace)
|
|
||||||
render(typeArgument.type, options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun StringBuilder.renderNullability(nullability: KtTypeNullability) {
|
|
||||||
if (nullability == KtTypeNullability.NULLABLE) {
|
|
||||||
append("?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun StringBuilder.render(classId: ClassId, options: KtTypeRendererOptions) {
|
|
||||||
if (options.renderFqNames) {
|
|
||||||
append(classId.asString().replace('/', '.'))
|
|
||||||
} else {
|
|
||||||
append(classId.shortClassName.asString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun StringBuilder.inParens(render: StringBuilder.() -> Unit) {
|
|
||||||
append("(")
|
|
||||||
render()
|
|
||||||
append(")")
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class KtTypeRendererOptions(
|
|
||||||
val renderFqNames: Boolean,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
val DEFAULT = KtTypeRendererOptions(
|
|
||||||
renderFqNames = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KtType.render(options: KtTypeRendererOptions = KtTypeRendererOptions.DEFAULT): String =
|
|
||||||
KtTypeRenderer.render(this, options)
|
|
||||||
|
|
||||||
|
|||||||
+2
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.idea.frontend.api.types
|
|||||||
import com.intellij.testFramework.LightProjectDescriptor
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
import org.jetbrains.kotlin.idea.executeOnPooledThreadInReadAction
|
import org.jetbrains.kotlin.idea.executeOnPooledThreadInReadAction
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.analyze
|
import org.jetbrains.kotlin.idea.frontend.api.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
|||||||
Reference in New Issue
Block a user