FIR IDE: add TypeInfoProvider and mixin to host type utils

This commit is contained in:
Tianyu Geng
2021-04-01 11:18:15 -07:00
committed by Ilya Kirillov
parent 4d505f4393
commit 1496c82108
12 changed files with 123 additions and 83 deletions
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.idea.api.applicator.applicator
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.idea.frontend.api.types.isUnit
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtFunction
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider
import org.jetbrains.kotlin.idea.fir.api.applicator.presentation
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator
import org.jetbrains.kotlin.idea.frontend.api.types.isUnit
import org.jetbrains.kotlin.psi.KtNamedFunction
internal class HLRedundantUnitReturnTypeInspection :
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.quickfix.fixes
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
import org.jetbrains.kotlin.idea.frontend.api.types.isPrimitive
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtProperty
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.idea.api.applicator.applicator
import org.jetbrains.kotlin.idea.fir.api.fixes.HLQuickFix
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
import org.jetbrains.kotlin.idea.frontend.api.types.defaultInitializer
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -33,6 +33,7 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
KtSymbolDeclarationOverridesProviderMixIn,
KtExpressionTypeProviderMixIn,
KtTypeProviderMixIn,
KtTypeInfoProviderMixIn,
KtSymbolProviderMixIn,
KtSymbolContainingDeclarationProviderMixIn,
KtSubtypingComponentMixIn,
@@ -83,6 +84,9 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
internal val typeProvider: KtTypeProvider get() = typeProviderImpl
protected abstract val typeProviderImpl: KtTypeProvider
internal val typeInfoProvider: KtTypeInfoProvider get() = typeInfoProviderImpl
protected abstract val typeInfoProviderImpl: KtTypeInfoProvider
internal val subtypingComponent: KtSubtypingComponent get() = subtypingComponentImpl
protected abstract val subtypingComponentImpl: KtSubtypingComponent
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2021 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.builtins.StandardNames
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeNullability
import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeWithNullability
import org.jetbrains.kotlin.name.ClassId
abstract class KtTypeInfoProvider : KtAnalysisSessionComponent() {
abstract fun canBeNull(type: KtType): Boolean
}
interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn {
/**
* Returns true if a value of this type can potentially be null. This means this type is not a subtype of [Any]. However, it does not
* mean one can assign `null` to a variable of this type because it may be unknown if this type can accept `null`. For example, a value
* of type `T:Any?` can potentially be null. But one can not assign `null` to such a variable because the instantiated type may not be
* nullable.
*/
val KtType.canBeNull: Boolean get() = analysisSession.typeInfoProvider.canBeNull(this)
/** Returns true if the type is explicitly marked as nullable. This means it's safe to assign `null` to a variable with this type. */
val KtType.isMarkedNullable: Boolean get() = (this as? KtTypeWithNullability)?.nullability == KtTypeNullability.NULLABLE
val KtType.isUnit: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.UNIT)
val KtType.isInt: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.INT)
val KtType.isLong: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.LONG)
val KtType.isShort: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.SHORT)
val KtType.isByte: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BYTE)
val KtType.isFloat: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.FLOAT)
val KtType.isDouble: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.DOUBLE)
val KtType.isChar: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CHAR)
val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN)
val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING)
val KtType.isUInt: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uInt)
val KtType.isULong: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uLong)
val KtType.isUShort: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uShort)
val KtType.isUByte: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uByte)
fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean {
if (this !is KtClassType) return false
return this.classId == classId
}
val KtType.isPrimitive: Boolean
get() {
if (this !is KtClassType) return false
return this.classId in DefaultTypeClassIds.PRIMITIVES
}
val KtType.defaultInitializer: String?
get() = when {
isMarkedNullable -> "null"
isInt || isLong || isShort || isByte -> "0"
isFloat -> "0.0f"
isDouble -> "0.0"
isChar -> "'\\u0000'"
isBoolean -> "false"
isUnit -> "Unit"
isString -> "\"\""
isUInt -> "0.toUInt()"
isULong -> "0.toULong()"
isUShort -> "0.toUShort()"
isUByte -> "0.toUByte()"
else -> null
}
}
object DefaultTypeClassIds {
val UNIT = ClassId.topLevel(StandardNames.FqNames.unit.toSafe())
val INT = ClassId.topLevel(StandardNames.FqNames._int.toSafe())
val LONG = ClassId.topLevel(StandardNames.FqNames._long.toSafe())
val SHORT = ClassId.topLevel(StandardNames.FqNames._short.toSafe())
val BYTE = ClassId.topLevel(StandardNames.FqNames._byte.toSafe())
val FLOAT = ClassId.topLevel(StandardNames.FqNames._float.toSafe())
val DOUBLE = ClassId.topLevel(StandardNames.FqNames._double.toSafe())
val CHAR = ClassId.topLevel(StandardNames.FqNames._char.toSafe())
val BOOLEAN = ClassId.topLevel(StandardNames.FqNames._boolean.toSafe())
val STRING = ClassId.topLevel(StandardNames.FqNames.string.toSafe())
val PRIMITIVES = setOf(INT, LONG, SHORT, BYTE, FLOAT, DOUBLE, CHAR, BOOLEAN)
}
@@ -32,9 +32,6 @@ interface KtTypeProviderMixIn : KtAnalysisSessionMixIn {
fun KtNamedClassOrObjectSymbol.buildSelfClassType(): KtType =
analysisSession.typeProvider.buildSelfClassType(this)
val KtType.canBeNull: Boolean
}
@Suppress("PropertyName")
@@ -1,70 +0,0 @@
/*
* 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.types
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
val KtType.isMarkedNullable: Boolean get() = (this as? KtTypeWithNullability)?.nullability == KtTypeNullability.NULLABLE
val KtType.isUnit: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.UNIT)
val KtType.isInt: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.INT)
val KtType.isLong: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.LONG)
val KtType.isShort: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.SHORT)
val KtType.isByte: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BYTE)
val KtType.isFloat: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.FLOAT)
val KtType.isDouble: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.DOUBLE)
val KtType.isChar: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CHAR)
val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN)
val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING)
val KtType.isUInt: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uInt)
val KtType.isULong: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uLong)
val KtType.isUShort: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uShort)
val KtType.isUByte: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uByte)
fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean {
if (this !is KtClassType) return false
return this.classId == classId
}
val KtType.isPrimitive: Boolean
get() {
if (this !is KtClassType) return false
return this.classId in DefaultTypeClassIds.PRIMITIVES
}
private object DefaultTypeClassIds {
val UNIT = ClassId.topLevel(StandardNames.FqNames.unit.toSafe())
val INT = ClassId.topLevel(StandardNames.FqNames._int.toSafe())
val LONG = ClassId.topLevel(StandardNames.FqNames._long.toSafe())
val SHORT = ClassId.topLevel(StandardNames.FqNames._short.toSafe())
val BYTE = ClassId.topLevel(StandardNames.FqNames._byte.toSafe())
val FLOAT = ClassId.topLevel(StandardNames.FqNames._float.toSafe())
val DOUBLE = ClassId.topLevel(StandardNames.FqNames._double.toSafe())
val CHAR = ClassId.topLevel(StandardNames.FqNames._char.toSafe())
val BOOLEAN = ClassId.topLevel(StandardNames.FqNames._boolean.toSafe())
val STRING = ClassId.topLevel(StandardNames.FqNames.string.toSafe())
val PRIMITIVES = setOf(INT, LONG, SHORT, BYTE, FLOAT, DOUBLE, CHAR, BOOLEAN)
}
val KtType.defaultInitializer: String?
get() = when {
isMarkedNullable -> "null"
isInt || isLong || isShort || isByte -> "0"
isFloat -> "0.0f"
isDouble -> "0.0"
isChar -> "'\\u0000'"
isBoolean -> "false"
isUnit -> "Unit"
isString -> "\"\""
isUInt -> "0.toUInt()"
isULong -> "0.toULong()"
isUShort -> "0.toUShort()"
isUByte -> "0.toUByte()"
else -> null
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration
import org.jetbrains.kotlin.idea.frontend.api.components.DefaultTypeClassIds
import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.*
import org.jetbrains.kotlin.idea.frontend.api.types.*
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import java.text.StringCharacterIterator
@@ -305,6 +307,12 @@ internal fun KtType.getTypeNullability(context: KtSymbol, phase: FirResolvePhase
return if (isNotPrimitiveType) NullabilityType.NotNull else NullabilityType.Unknown
}
internal val KtType.isUnit get() = isClassTypeWithClassId(DefaultTypeClassIds.UNIT)
internal fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean {
if (this !is KtClassType) return false
return this.classId == classId
}
private fun escapeString(str: String): String = buildString {
str.forEach { char ->
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.asJava.elements.FirLightTypeParameterListForSymbol
import org.jetbrains.kotlin.idea.frontend.api.isValid
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.isUnit
import org.jetbrains.kotlin.idea.util.ifTrue
import org.jetbrains.kotlin.lexer.KtTokens
import java.util.*
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.types.canBeNull
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile
@@ -21,11 +20,9 @@ import org.jetbrains.kotlin.idea.frontend.api.tokens.ReadActionConfinementValidi
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.EnclosingDeclarationContext
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.recordCompletionContext
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -62,10 +59,10 @@ private constructor(
override val expressionInfoProviderImpl = KtFirExpressionInfoProvider(this, token)
override val KtType.canBeNull: Boolean get() = (this as KtFirType).coneType.canBeNull
override val typeProviderImpl = KtFirTypeProvider(this, token)
override val typeInfoProviderImpl = KtFirTypeInfoProvider(this, token)
override val subtypingComponentImpl = KtFirSubtypingComponent(this, token)
override fun createContextDependentCopy(originalKtFile: KtFile, fakeKtElement: KtElement): KtAnalysisSession {
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2021 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.fir.components
import org.jetbrains.kotlin.fir.types.canBeNull
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeInfoProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
internal class KtFirTypeInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtTypeInfoProvider(), KtFirAnalysisSessionComponent {
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull
}