org.jetbrains.kotlin.backend.common.CodegenUtil.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2024 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.backend.common
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.SourceCodeAnalysisException
import org.jetbrains.kotlin.util.getExceptionMessage
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.exceptions.rethrowIntellijPlatformExceptionIfNeeded
object CodegenUtil {
@JvmStatic
fun getDelegatePropertyIfAny(
expression: KtExpression, classDescriptor: ClassDescriptor, bindingContext: BindingContext
): PropertyDescriptor? {
val call = (expression as? KtSimpleNameExpression)?.getResolvedCall(bindingContext) ?: return null
val callResultingDescriptor = call.resultingDescriptor as? ValueParameterDescriptor ?: return null
// constructor parameter
if (callResultingDescriptor.containingDeclaration is ConstructorDescriptor) {
// constructor of my class
if (callResultingDescriptor.containingDeclaration.containingDeclaration === classDescriptor) {
return bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, callResultingDescriptor)
}
}
return null
}
@JvmStatic
fun isFinalPropertyWithBackingField(propertyDescriptor: PropertyDescriptor?, bindingContext: BindingContext): Boolean {
return propertyDescriptor != null &&
!propertyDescriptor.isVar &&
(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false)
}
@JvmStatic
fun getSuperClassBySuperTypeListEntry(specifier: KtSuperTypeListEntry, bindingContext: BindingContext): ClassDescriptor? {
val superType = bindingContext.get(BindingContext.TYPE, specifier.typeReference!!)
return superType?.constructor?.declarationDescriptor as? ClassDescriptor
}
// Returns the descriptor for a function (whose parameters match the given predicate) which should be generated in the class.
// Note that we always generate equals/hashCode/toString in data classes, unless that would lead to a JVM signature clash with
// another method, which can only happen if the method is declared in the data class (manually or via delegation).
// Also there are no hard asserts or assumptions because such methods are generated for erroneous code as well (in light classes mode).
fun getMemberToGenerate(
classDescriptor: ClassDescriptor,
name: String,
isReturnTypeOk: (KotlinType) -> Boolean,
areParametersOk: (List) -> Boolean
): FunctionDescriptor? =
classDescriptor.unsubstitutedMemberScope.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
.singleOrNull { function ->
function.kind.let { kind -> kind == CallableMemberDescriptor.Kind.SYNTHESIZED || kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } &&
function.modality != Modality.FINAL &&
areParametersOk(function.valueParameters) &&
function.returnType != null &&
isReturnTypeOk(function.returnType!!) &&
function.extensionReceiverParameter == null
}
/**
* Returns functions, properties and type aliases in the given [file] which should be generated by the back-end.
*/
@JvmStatic
fun getMemberDeclarationsToGenerate(file: KtFile): List {
val declarations = ApplicationManager.getApplication().runReadAction> { file.declarations }
return declarations.filter { declaration ->
!declaration.hasExpectModifier() && (declaration is KtNamedFunction || declaration is KtProperty || declaration is KtTypeAlias)
}
}
@JvmStatic
fun getMemberDescriptorsToGenerate(file: KtFile, bindingContext: BindingContext): List =
getMemberDeclarationsToGenerate(file).mapNotNull { declaration ->
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration) as MemberDescriptor?
}
@JvmStatic
fun reportBackendException(
exception: Throwable,
phase: String,
location: String?,
additionalMessage: String? = null,
linesMapping: (Int) -> Pair? = { _ -> null },
): Nothing {
// CompilationException (the only KotlinExceptionWithAttachments possible here) is already supposed
// to have all information about the context.
if (exception is KotlinExceptionWithAttachments) throw exception
rethrowIntellijPlatformExceptionIfNeeded(exception)
val locationWithLineAndOffset = location
?.let { exception as? SourceCodeAnalysisException }
?.let { linesMapping(it.source.startOffset) }
?.let { (line, offset) -> "$location:${line + 1}:${offset + 1}" }
?: location
throw BackendException(
getExceptionMessage("Backend", "Exception during $phase", exception, locationWithLineAndOffset) +
additionalMessage?.let { "\n" + it }.orEmpty(),
exception
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy