diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index b6715f872ef..7f7a9d79abe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -21,19 +21,26 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability -class ConeUnresolvedReferenceError(val name: Name? = null) : ConeDiagnostic() { +sealed class ConeUnresolvedError : ConeDiagnostic() { + abstract val qualifier: String? +} + +class ConeUnresolvedReferenceError(val name: Name? = null) : ConeUnresolvedError() { + override val qualifier: String? get() = name?.asString() override val reason: String get() = "Unresolved reference" + if (name != null) ": ${name.asString()}" else "" } -class ConeUnresolvedSymbolError(val classId: ClassId) : ConeDiagnostic() { +class ConeUnresolvedSymbolError(val classId: ClassId) : ConeUnresolvedError() { + override val qualifier: String get() = classId.asSingleFqName().asString() override val reason: String get() = "Symbol not found for $classId" } -class ConeUnresolvedQualifierError(val qualifier: String) : ConeDiagnostic() { +class ConeUnresolvedQualifierError(override val qualifier: String) : ConeUnresolvedError() { override val reason: String get() = "Symbol not found for $qualifier" } -class ConeUnresolvedNameError(val name: Name) : ConeDiagnostic() { +class ConeUnresolvedNameError(val name: Name) : ConeUnresolvedError() { + override val qualifier: String get() = name.asString() override val reason: String get() = "Unresolved name: $name" } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt index 1f5af31414f..8ab71d86a38 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt @@ -307,6 +307,7 @@ internal abstract class KtGenerateMembersHandler : AbstractGenerateMembersHandle typeRendererOptions = KtTypeRendererOptions( shortQualifiedNames = true, renderFunctionType = true, + renderUnresolvedTypeAsResolved = true, ) ) } diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationRendererProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationRendererProvider.kt index aad26cf72c9..3ee5e557c70 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationRendererProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtSymbolDeclarationRendererProvider.kt @@ -24,6 +24,13 @@ data class KtTypeRendererOptions( * @sample Function0 returns () -> Int */ val renderFunctionType: Boolean = true, + + /** + * When met type with unresolved qualifier, render it as it is resolved + * When `true` will render as `UnresolvedQualifier` + * When `false` will render as "ERROR_TYPE " + */ + val renderUnresolvedTypeAsResolved: Boolean = true ) { companion object { val DEFAULT = KtTypeRendererOptions() diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/renderer/ConeTypeIdeRenderer.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/renderer/ConeTypeIdeRenderer.kt index a9167743888..bc42ed4c63d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/renderer/ConeTypeIdeRenderer.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/renderer/ConeTypeIdeRenderer.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirTypeParameter import org.jetbrains.kotlin.fir.declarations.isInner import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedError import org.jetbrains.kotlin.fir.resolve.inference.* import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -18,7 +19,9 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.asJava.applyIf import org.jetbrains.kotlin.idea.fir.low.level.api.api.collectDesignation import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.renderer.render internal class ConeTypeIdeRenderer( private val session: FirSession, @@ -48,7 +51,7 @@ internal class ConeTypeIdeRenderer( when (type) { is ConeKotlinErrorType -> { - appendError(type.diagnostic.reason) + renderErrorType(type) } //is Dynamic??? -> append("dynamic") is ConeClassLikeType -> { @@ -83,6 +86,16 @@ internal class ConeTypeIdeRenderer( } } + private fun StringBuilder.renderErrorType(type: ConeKotlinErrorType) { + val diagnostic = type.diagnostic + if (options.renderUnresolvedTypeAsResolved && diagnostic is ConeUnresolvedError) { + val qualifierRendered = diagnostic.qualifier?.let { FqName(it).render() }.orEmpty() + append(qualifierRendered) + } else { + appendError(diagnostic.reason) + } + } + private fun StringBuilder.renderNullability(type: ConeKotlinType) { if (type.nullability == ConeNullability.NULLABLE) { append("?") diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/TypeCreatorTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/TypeCreatorTest.kt index 4bbd1549518..dcd2f03bf61 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/TypeCreatorTest.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/TypeCreatorTest.kt @@ -85,6 +85,6 @@ internal class TypeCreatorTest : KotlinLightCodeInsightFixtureTestCase() { companion object { - private val RENDERING_OPTIONS = KtTypeRendererOptions.SHORT_NAMES + private val RENDERING_OPTIONS = KtTypeRendererOptions.SHORT_NAMES.copy(renderUnresolvedTypeAsResolved = false) } } \ No newline at end of file diff --git a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt b/idea/testData/codeInsight/overrideImplement/unresolvedType.kt index d91a7808526..2c59fc1e748 100644 --- a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt +++ b/idea/testData/codeInsight/overrideImplement/unresolvedType.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // DISABLE-ERRORS interface A { fun install(pipeline: TPipeline, configure: TBuilder.() -> Unit): TFeature diff --git a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.after b/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.after index 6366d495431..90efab98d32 100644 --- a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.after +++ b/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.after @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // DISABLE-ERRORS interface A { fun install(pipeline: TPipeline, configure: TBuilder.() -> Unit): TFeature diff --git a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.fir.after b/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.fir.after deleted file mode 100644 index c65cea44c8a..00000000000 --- a/idea/testData/codeInsight/overrideImplement/unresolvedType.kt.fir.after +++ /dev/null @@ -1,10 +0,0 @@ -// DISABLE-ERRORS -interface A { - fun install(pipeline: TPipeline, configure: TBuilder.() -> Unit): TFeature -} - -class X : A { - override fun install(pipeline: String, configure: ERROR_TYPE.() -> Unit) { - TODO("Not yet implemented") - } -} \ No newline at end of file