mirror of
https://github.com/github/codeql.git
synced 2026-05-23 15:47:11 +02:00
Use extension functions to group extractor functionality
This commit is contained in:
@@ -2,6 +2,8 @@ package com.github.codeql
|
||||
|
||||
import com.github.codeql.utils.isInterfaceLike
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import extractClassSource
|
||||
import extractFunction
|
||||
import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
@@ -10,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.parsing.parseNumericLiteral
|
||||
import useType
|
||||
import java.io.Closeable
|
||||
import java.util.*
|
||||
|
||||
@@ -119,7 +122,7 @@ open class KotlinFileExtractor(
|
||||
val metaAnnotationSupport = MetaAnnotationSupport(logger, pluginContext, this)
|
||||
*/
|
||||
|
||||
private inline fun <T> with(kind: String, element: KtElement, f: () -> T): T {
|
||||
inline fun <T> with(kind: String, element: KtElement, f: () -> T): T {
|
||||
val name =
|
||||
when (element) {
|
||||
is KtFile -> element.virtualFilePath
|
||||
@@ -1030,180 +1033,7 @@ OLD: KE1
|
||||
|
||||
*/
|
||||
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
fun extractClassSource(
|
||||
c: KaClassSymbol,
|
||||
extractDeclarations: Boolean,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractStaticInitializer: Boolean,
|
||||
extractPrivateMembers: Boolean,
|
||||
extractFunctionBodies: Boolean
|
||||
*/
|
||||
): Label<out DbClassorinterface> {
|
||||
with("class source", c.psiSafe() ?: TODO()) {
|
||||
DeclarationStackAdjuster(c).use {
|
||||
val id = useClassSource(c)
|
||||
val pkg = c.classId?.packageFqName?.asString() ?: ""
|
||||
val cls =
|
||||
if (c.classKind == KaClassKind.ANONYMOUS_OBJECT) "" else c.name!!.asString() // TODO: Remove !!
|
||||
val pkgId = extractPackage(pkg)
|
||||
tw.writeClasses_or_interfaces(id, cls, pkgId, id)
|
||||
if (c.isInterfaceLike) {
|
||||
tw.writeIsInterface(id)
|
||||
if (c.classKind == KaClassKind.ANNOTATION_CLASS) {
|
||||
tw.writeIsAnnotType(id)
|
||||
}
|
||||
} else {
|
||||
val kind = c.classKind
|
||||
if (kind == KaClassKind.ENUM_CLASS) {
|
||||
tw.writeIsEnumType(id)
|
||||
} else if (
|
||||
kind != KaClassKind.CLASS &&
|
||||
kind != KaClassKind.OBJECT //&&
|
||||
//OLD KE1: kind != ClassKind.ENUM_ENTRY
|
||||
) {
|
||||
logger.warnElement("Unrecognised class kind $kind", c.psiSafe() ?: TODO())
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.origin == IrDeclarationOrigin.FILE_CLASS) {
|
||||
tw.writeFile_class(id)
|
||||
}
|
||||
*/
|
||||
|
||||
if ((c as? KaNamedClassSymbol)?.isData == true) {
|
||||
tw.writeKtDataClasses(id)
|
||||
}
|
||||
}
|
||||
|
||||
val locId = tw.getLocation(c.psiSafe() ?: TODO())
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
// OLD: KE1
|
||||
//extractEnclosingClass(c.parent, id, c, locId, listOf())
|
||||
//val javaClass = (c.source as? JavaSourceElement)?.javaElement as? JavaClass
|
||||
|
||||
c.typeParameters.mapIndexed { idx, param ->
|
||||
//extractTypeParameter(param, idx, javaClass?.typeParameters?.getOrNull(idx))
|
||||
}
|
||||
if (extractDeclarations) {
|
||||
if (c.classKind == KaClassKind.ANNOTATION_CLASS) {
|
||||
c.declaredMemberScope.declarations.filterIsInstance<KaPropertySymbol>().forEach {
|
||||
val getter = it.getter
|
||||
if (getter == null) {
|
||||
logger.warnElement(
|
||||
"Expected an annotation property to have a getter",
|
||||
it.psiSafe() ?: TODO()
|
||||
)
|
||||
} else {
|
||||
extractFunction(
|
||||
getter,
|
||||
id,
|
||||
/* OLD: KE1
|
||||
extractBody = false,
|
||||
extractMethodAndParameterTypeAccesses =
|
||||
extractFunctionBodies,
|
||||
extractAnnotations = true,
|
||||
null,
|
||||
listOf()
|
||||
*/
|
||||
)
|
||||
?.also { functionLabel ->
|
||||
tw.writeIsAnnotElem(functionLabel.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
val decl = c.declaredMemberScope.declarations.toList()
|
||||
c.declaredMemberScope.declarations.forEach {
|
||||
extractDeclaration(
|
||||
it,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractPrivateMembers = extractPrivateMembers,
|
||||
extractFunctionBodies = extractFunctionBodies,
|
||||
extractAnnotations = true
|
||||
*/
|
||||
)
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (extractStaticInitializer) extractStaticInitializer(c, { id })
|
||||
extractJvmStaticProxyMethods(
|
||||
c,
|
||||
id,
|
||||
extractPrivateMembers,
|
||||
extractFunctionBodies
|
||||
)
|
||||
*/
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// A Kotlin bug causes this to throw: https://youtrack.jetbrains.com/issue/KT-63847/K2-IllegalStateException-IrFieldPublicSymbolImpl-for-java.time-Clock.OffsetClock.offset0-is-already-bound
|
||||
// TODO: This should either be removed or log something, once the bug is fixed
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.isNonCompanionObject) {
|
||||
// For `object MyObject { ... }`, the .class has an
|
||||
// automatically-generated `public static final MyObject INSTANCE`
|
||||
// field that may be referenced from Java code, and is used in our
|
||||
// IrGetObjectValue support. We therefore need to fabricate it
|
||||
// here.
|
||||
val instance = useObjectClassInstance(c)
|
||||
val type = useSimpleTypeClass(c, emptyList(), false)
|
||||
tw.writeFields(instance.id, instance.name, type.javaResult.id, id, instance.id)
|
||||
tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(instance.id, locId)
|
||||
addModifiers(instance.id, "public", "static", "final")
|
||||
tw.writeClass_object(id, instance.id)
|
||||
}
|
||||
*/
|
||||
if (c.classKind == KaClassKind.OBJECT) {
|
||||
addModifiers(id, "static")
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (extractFunctionBodies && needsObinitFunction(c)) {
|
||||
extractObinitFunction(c, id)
|
||||
}
|
||||
|
||||
extractClassModifiers(c, id)
|
||||
extractClassSupertypes(
|
||||
c,
|
||||
id,
|
||||
inReceiverContext = true
|
||||
) // inReceiverContext = true is specified to force extraction of member prototypes
|
||||
// of base types
|
||||
|
||||
linesOfCode?.linesOfCodeInDeclaration(c, id)
|
||||
|
||||
val additionalAnnotations =
|
||||
if (
|
||||
c.kind == ClassKind.ANNOTATION_CLASS &&
|
||||
c.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
)
|
||||
metaAnnotationSupport.generateJavaMetaAnnotations(c, extractFunctionBodies)
|
||||
else listOf()
|
||||
|
||||
extractAnnotations(
|
||||
c,
|
||||
c.annotations + additionalAnnotations,
|
||||
id,
|
||||
extractFunctionBodies
|
||||
)
|
||||
|
||||
if (extractFunctionBodies && !c.isAnonymousObject && !c.isLocal)
|
||||
externalClassExtractor.writeStubTrapFile(c)
|
||||
*/
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
val jvmStaticFqName = FqName("kotlin.jvm.JvmStatic")
|
||||
@@ -1871,79 +1701,6 @@ OLD: KE1
|
||||
}
|
||||
*/
|
||||
|
||||
private fun extractFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody: Boolean,
|
||||
extractMethodAndParameterTypeAccesses: Boolean,
|
||||
extractAnnotations: Boolean,
|
||||
typeSubstitution: TypeSubstitution?,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): Label<out DbCallable> {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (isFake(f)) {
|
||||
if (needsInterfaceForwarder(f)) {
|
||||
return makeInterfaceForwarder(
|
||||
f,
|
||||
parentId,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
// Work around an apparent bug causing redeclarations of `fun toString(): String`
|
||||
// specifically in interfaces loaded from Java classes show up like fake overrides.
|
||||
val overriddenVisibility =
|
||||
if (f.isFakeOverride && isJavaBinaryObjectMethodRedeclaration(f))
|
||||
OverriddenFunctionAttributes(visibility = DescriptorVisibilities.PUBLIC)
|
||||
else null
|
||||
*/
|
||||
return forceExtractFunction(
|
||||
f,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
extractAnnotations,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overriddenAttributes = overriddenVisibility
|
||||
*/
|
||||
)
|
||||
/*
|
||||
OLD: KE1
|
||||
.also {
|
||||
// The defaults-forwarder function is a static utility, not a member, so we only
|
||||
// need to extract this for the unspecialised instance of this class.
|
||||
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
|
||||
extractDefaultsFunction(
|
||||
f,
|
||||
parentId,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
)
|
||||
extractGeneratedOverloads(
|
||||
f,
|
||||
parentId,
|
||||
null,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses
|
||||
)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
private fun extractDefaultsFunction(
|
||||
@@ -2388,58 +2145,6 @@ OLD: KE1
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Can this be inlined?
|
||||
private fun extractMethod(
|
||||
id: Label<out DbMethod>,
|
||||
/*
|
||||
OLD: KE1
|
||||
locId: Label<out DbLocation>,
|
||||
*/
|
||||
shortName: String,
|
||||
returnType: KaType,
|
||||
paramsSignature: String,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
sourceDeclaration: Label<out DbMethod>,
|
||||
origin: IrDeclarationOrigin?,
|
||||
extractTypeAccess: Boolean
|
||||
*/
|
||||
) {
|
||||
val returnTypeResults = useType(returnType, TypeContext.RETURN)
|
||||
tw.writeMethods(
|
||||
id,
|
||||
shortName,
|
||||
"$shortName$paramsSignature",
|
||||
returnTypeResults.javaResult.id,
|
||||
parentId,
|
||||
id, // OLD: KE1: sourceDeclaration
|
||||
)
|
||||
/*
|
||||
OLD: KE1
|
||||
tw.writeMethodsKotlinType(id, returnTypeResults.kotlinResult.id)
|
||||
when (origin) {
|
||||
IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.GENERATED_DATA_CLASS_MEMBER.kind
|
||||
)
|
||||
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.DEFAULT_PROPERTY_ACCESSOR.kind
|
||||
)
|
||||
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.ENUM_CLASS_SPECIAL_MEMBER.kind
|
||||
)
|
||||
}
|
||||
if (extractTypeAccess) {
|
||||
extractTypeAccessRecursive(returnType, locId, id, -1)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
@@ -2512,251 +2217,6 @@ OLD: KE1
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Can this be inlined?
|
||||
private fun forceExtractFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody: Boolean,
|
||||
extractMethodAndParameterTypeAccesses: Boolean,
|
||||
extractAnnotations: Boolean,
|
||||
typeSubstitution: TypeSubstitution?,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
extractOrigin: Boolean = true,
|
||||
overriddenAttributes: OverriddenFunctionAttributes? = null
|
||||
*/
|
||||
): Label<out DbCallable> {
|
||||
with("function", f.psiSafe() ?: TODO()) {
|
||||
/*
|
||||
OLD: KE1
|
||||
DeclarationStackAdjuster(f, overriddenAttributes).use {
|
||||
val javaCallable = getJavaCallable(f)
|
||||
getFunctionTypeParameters(f).mapIndexed { idx, tp ->
|
||||
extractTypeParameter(
|
||||
tp,
|
||||
idx,
|
||||
(javaCallable as? JavaTypeParameterListOwner)
|
||||
?.typeParameters
|
||||
?.getOrNull(idx)
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
val id =
|
||||
/*
|
||||
OLD: KE1
|
||||
overriddenAttributes?.id
|
||||
?: // If this is a class that would ordinarily be replaced by a Java
|
||||
// equivalent (e.g. kotlin.Map -> java.util.Map),
|
||||
// don't replace here, really extract the Kotlin version:
|
||||
*/
|
||||
useFunction<DbCallable>(
|
||||
f,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
noReplace = true
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
val sourceDeclaration =
|
||||
overriddenAttributes?.sourceDeclarationId
|
||||
?: if (typeSubstitution != null && overriddenAttributes?.id == null) {
|
||||
val sourceFunId = useFunction<DbCallable>(f)
|
||||
if (sourceFunId == null) {
|
||||
logger.errorElement("Cannot get source ID for function", f)
|
||||
id // TODO: This is wrong; we ought to just fail in this case
|
||||
} else {
|
||||
sourceFunId
|
||||
}
|
||||
} else {
|
||||
id
|
||||
}
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
// The following parameter order is correct, because member $default methods (where
|
||||
// the order would be [dispatchParam], [extensionParam], normalParams) are not
|
||||
// extracted here
|
||||
val fParameters =
|
||||
listOfNotNull(extReceiver) +
|
||||
(overriddenAttributes?.valueParameters ?: f.valueParameters)
|
||||
val paramTypes =
|
||||
fParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(
|
||||
vp,
|
||||
id,
|
||||
i,
|
||||
typeSubstitution,
|
||||
sourceDeclaration,
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
extractTypeAccess = extractMethodAndParameterTypeAccesses,
|
||||
overriddenAttributes?.sourceLoc
|
||||
)
|
||||
}
|
||||
if (extReceiver != null) {
|
||||
val extendedType = paramTypes[0]
|
||||
tw.writeKtExtensionFunctions(
|
||||
id.cast<DbMethod>(),
|
||||
extendedType.javaResult.id,
|
||||
extendedType.kotlinResult.id
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
val paramsSignature = "()" // TODO:
|
||||
/*
|
||||
OLD: KE1
|
||||
paramTypes.joinToString(separator = ",", prefix = "(", postfix = ")") {
|
||||
signatureOrWarn(it.javaResult, f)
|
||||
}
|
||||
|
||||
val adjustedReturnType =
|
||||
addJavaLoweringWildcards(
|
||||
getAdjustedReturnType(f),
|
||||
false,
|
||||
(javaCallable as? JavaMethod)?.returnType
|
||||
)
|
||||
val substReturnType =
|
||||
typeSubstitution?.let {
|
||||
it(adjustedReturnType, TypeContext.RETURN, pluginContext)
|
||||
} ?: adjustedReturnType
|
||||
*/
|
||||
val functionSyntax = f.psi as? KtDeclarationWithBody
|
||||
val locId =
|
||||
tw.getLocation(functionSyntax ?: TODO())
|
||||
/*
|
||||
OLD: KE1
|
||||
overriddenAttributes?.sourceLoc
|
||||
?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val shortName =
|
||||
when {
|
||||
adjustedReturnType.isAnonymous -> ""
|
||||
typeSubstitution != null ->
|
||||
useType(substReturnType).javaResult.shortName
|
||||
else ->
|
||||
adjustedReturnType.classFqName?.shortName()?.asString()
|
||||
?: f.name.asString()
|
||||
}
|
||||
extractConstructor(
|
||||
id.cast(),
|
||||
shortName,
|
||||
paramsSignature,
|
||||
parentId,
|
||||
sourceDeclaration.cast()
|
||||
)
|
||||
} else {
|
||||
val shortNames = getFunctionShortName(f)
|
||||
*/
|
||||
val methodId = id.cast<DbMethod>()
|
||||
extractMethod(
|
||||
methodId,
|
||||
/*
|
||||
OLD: KE1
|
||||
locId,
|
||||
*/
|
||||
f.name!!.asString(), // TODO: Remove !!, // OLD: KE1: shortNames.nameInDB,
|
||||
f.returnType, // OLD: KE1: substReturnType,
|
||||
paramsSignature,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
sourceDeclaration.cast(),
|
||||
if (extractOrigin) f.origin else null,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (shortNames.nameInDB != shortNames.kotlinName) {
|
||||
tw.writeKtFunctionOriginalNames(methodId, shortNames.kotlinName)
|
||||
}
|
||||
|
||||
if (f.hasInterfaceParent() && f.body != null) {
|
||||
addModifiers(
|
||||
methodId,
|
||||
"default"
|
||||
) // The actual output class file may or may not have this modifier,
|
||||
// depending on the -Xjvm-default setting.
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
tw.writeHasLocation(id, locId)
|
||||
val body = functionSyntax?.bodyExpression ?: functionSyntax?.bodyBlockExpression
|
||||
if (body != null /* TODO && extractBody */) {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (typeSubstitution != null)
|
||||
logger.errorElement(
|
||||
"Type substitution should only be used to extract a function prototype, not the body",
|
||||
f
|
||||
)
|
||||
*/
|
||||
extractBody(body, id)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
extractVisibility(f, id, overriddenAttributes?.visibility ?: f.visibility)
|
||||
|
||||
if (f.isInline) {
|
||||
addModifiers(id, "inline")
|
||||
}
|
||||
if (f.shouldExtractAsStatic) {
|
||||
addModifiers(id, "static")
|
||||
}
|
||||
if (f is IrSimpleFunction && f.overriddenSymbols.isNotEmpty()) {
|
||||
addModifiers(id, "override")
|
||||
}
|
||||
if (f.isSuspend) {
|
||||
addModifiers(id, "suspend")
|
||||
}
|
||||
if (f.symbol !is IrConstructorSymbol) {
|
||||
when (overriddenAttributes?.modality ?: (f as? IrSimpleFunction)?.modality) {
|
||||
Modality.ABSTRACT -> addModifiers(id, "abstract")
|
||||
Modality.FINAL -> addModifiers(id, "final")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
linesOfCode?.linesOfCodeInDeclaration(f, id)
|
||||
|
||||
if (extractAnnotations) {
|
||||
val extraAnnotations =
|
||||
if (f.symbol is IrConstructorSymbol) listOf()
|
||||
else
|
||||
listOfNotNull(
|
||||
getNullabilityAnnotation(
|
||||
f.returnType,
|
||||
f.origin,
|
||||
f.annotations,
|
||||
getJavaCallable(f)?.annotations
|
||||
)
|
||||
)
|
||||
extractAnnotations(
|
||||
f,
|
||||
f.annotations + extraAnnotations,
|
||||
id,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
return id
|
||||
/*
|
||||
OLD: KE1
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
private fun isStaticFunction(f: IrFunction): Boolean {
|
||||
@@ -3018,7 +2478,7 @@ OLD: KE1
|
||||
}
|
||||
*/
|
||||
|
||||
private fun extractBody(b: KtExpression, callable: Label<out DbCallable>) {
|
||||
fun extractBody(b: KtExpression, callable: Label<out DbCallable>) {
|
||||
with("body", b) {
|
||||
when (b) {
|
||||
is KtBlockExpression -> extractBlockBody(b, callable)
|
||||
@@ -9458,7 +8918,7 @@ OLD: KE1
|
||||
}
|
||||
|
||||
*/
|
||||
private inner class DeclarationStackAdjuster(
|
||||
inner class DeclarationStackAdjuster(
|
||||
val declaration: KaDeclarationSymbol,
|
||||
val overriddenAttributes: OverriddenFunctionAttributes? = null
|
||||
) : Closeable {
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.analysis.api.types.KaClassType
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.asJava.elements.psiType
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import useClassSource
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
@@ -138,23 +139,6 @@ open class KotlinUsesExtractor(
|
||||
)
|
||||
*/
|
||||
|
||||
fun useType(t: KaType, context: TypeContext = TypeContext.OTHER): TypeResults {
|
||||
when (t) {
|
||||
is KaClassType -> return useClassType(t)
|
||||
else -> TODO()
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
when (t) {
|
||||
is IrSimpleType -> return useSimpleType(t, context)
|
||||
else -> {
|
||||
logger.error("Unrecognised IrType: " + t.javaClass)
|
||||
return extractErrorType()
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
private fun extractJavaErrorType(): TypeResult<DbErrortype> {
|
||||
@@ -559,81 +543,7 @@ open class KotlinUsesExtractor(
|
||||
return Pair(p?.first ?: c, p?.second ?: argsIncludingOuterClassesBeforeReplacement)
|
||||
}
|
||||
|
||||
// `typeArgs` can be null to describe a raw generic type.
|
||||
// For non-generic types it will be zero-length list.
|
||||
*/
|
||||
private fun addClassLabel(
|
||||
c: KaClassType, // TODO cBeforeReplacement: IrClass,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?,
|
||||
inReceiverContext: Boolean = false
|
||||
*/
|
||||
): TypeResult<DbClassorinterface> {
|
||||
/*
|
||||
OLD: KE1
|
||||
val replaced =
|
||||
tryReplaceType(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
|
||||
val replacedClass = replaced.first
|
||||
val replacedArgsIncludingOuterClasses = replaced.second
|
||||
|
||||
*/
|
||||
val classLabelResult = getClassLabel(c /* TODO replacedClass, replacedArgsIncludingOuterClasses */)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
var instanceSeenBefore = true
|
||||
*/
|
||||
|
||||
val classLabel: Label<out DbClassorinterface> =
|
||||
tw.getLabelFor(classLabelResult.classLabel) {
|
||||
/*
|
||||
OLD: KE1
|
||||
instanceSeenBefore = false
|
||||
|
||||
extractClassLaterIfExternal(replacedClass)
|
||||
*/
|
||||
// TODO: This shouldn't be done here, but keeping it simple for now
|
||||
val pkgId = extractPackage(c.classId.packageFqName.asString())
|
||||
tw.writeClasses_or_interfaces(it, c.classId.relativeClassName.asString(), pkgId, it)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (
|
||||
replacedArgsIncludingOuterClasses == null ||
|
||||
replacedArgsIncludingOuterClasses.isNotEmpty()
|
||||
) {
|
||||
// If this is a generic type instantiation or a raw type then it has no
|
||||
// source entity, so we need to extract it here
|
||||
val shouldExtractClassDetails =
|
||||
inReceiverContext &&
|
||||
tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)
|
||||
if (!instanceSeenBefore || shouldExtractClassDetails) {
|
||||
this.withFileOfClass(replacedClass)
|
||||
.extractClassInstance(
|
||||
classLabel,
|
||||
replacedClass,
|
||||
replacedArgsIncludingOuterClasses,
|
||||
!instanceSeenBefore,
|
||||
shouldExtractClassDetails
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val fqName = replacedClass.fqNameWhenAvailable
|
||||
val signature =
|
||||
if (replacedClass.isAnonymousObject) {
|
||||
null
|
||||
} else if (fqName == null) {
|
||||
logger.error("Unable to find signature/fqName for ${replacedClass.name}")
|
||||
null
|
||||
} else {
|
||||
fqName.asString()
|
||||
}
|
||||
*/
|
||||
return TypeResult(classLabel /* TODO , signature, classLabelResult.shortName */)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
@@ -734,13 +644,6 @@ OLD: KE1
|
||||
return TypeResults(javaResult, kotlinResult)
|
||||
}
|
||||
*/
|
||||
fun useClassType(
|
||||
c: KaClassType
|
||||
): TypeResults {
|
||||
val javaResult = addClassLabel(c)
|
||||
val kotlinResult = TypeResult(fakeKotlinType() /* , "TODO", "TODO" */)
|
||||
return TypeResults(javaResult, kotlinResult)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
@@ -1120,92 +1023,6 @@ OLD: KE1
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
private val IrDeclaration.isAnonymousFunction
|
||||
get() = this is IrSimpleFunction && name == SpecialNames.NO_NAME_PROVIDED
|
||||
|
||||
data class FunctionNames(val nameInDB: String, val kotlinName: String)
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun getJvmModuleName(f: IrFunction) =
|
||||
NameUtils.sanitizeAsJavaIdentifier(
|
||||
getJvmModuleNameForDeserializedDescriptor(f.descriptor)
|
||||
?: JvmCodegenUtil.getModuleName(pluginContext.moduleDescriptor)
|
||||
)
|
||||
|
||||
fun getFunctionShortName(f: IrFunction): FunctionNames {
|
||||
if (f.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || f.isAnonymousFunction)
|
||||
return FunctionNames(
|
||||
OperatorNameConventions.INVOKE.asString(),
|
||||
OperatorNameConventions.INVOKE.asString()
|
||||
)
|
||||
|
||||
fun getSuffixIfInternal() =
|
||||
if (
|
||||
f.visibility == DescriptorVisibilities.INTERNAL &&
|
||||
f !is IrConstructor &&
|
||||
!(f.parent is IrFile || isExternalFileClassMember(f))
|
||||
) {
|
||||
"\$" + getJvmModuleName(f)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
(f as? IrSimpleFunction)?.correspondingPropertySymbol?.let {
|
||||
val propName = it.owner.name.asString()
|
||||
val getter = it.owner.getter
|
||||
val setter = it.owner.setter
|
||||
|
||||
if (it.owner.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS) {
|
||||
if (getter == null) {
|
||||
logger.error(
|
||||
"Expected to find a getter for a property inside an annotation class"
|
||||
)
|
||||
return FunctionNames(propName, propName)
|
||||
} else {
|
||||
val jvmName = getJvmName(getter)
|
||||
return FunctionNames(jvmName ?: propName, propName)
|
||||
}
|
||||
}
|
||||
|
||||
val maybeFunctionName =
|
||||
when (f) {
|
||||
getter -> JvmAbi.getterName(propName)
|
||||
setter -> JvmAbi.setterName(propName)
|
||||
else -> {
|
||||
logger.error(
|
||||
"Function has a corresponding property, but is neither the getter nor the setter"
|
||||
)
|
||||
null
|
||||
}
|
||||
}
|
||||
maybeFunctionName?.let { defaultFunctionName ->
|
||||
val suffix =
|
||||
if (
|
||||
f.visibility == DescriptorVisibilities.PRIVATE &&
|
||||
f.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
|
||||
) {
|
||||
"\$private"
|
||||
} else {
|
||||
getSuffixIfInternal()
|
||||
}
|
||||
return FunctionNames(
|
||||
getJvmName(f) ?: "$defaultFunctionName$suffix",
|
||||
defaultFunctionName
|
||||
)
|
||||
}
|
||||
}
|
||||
return FunctionNames(
|
||||
getJvmName(f) ?: "${f.name.asString()}${getSuffixIfInternal()}",
|
||||
f.name.asString()
|
||||
)
|
||||
}
|
||||
|
||||
// This excludes class type parameters that show up in (at least) constructors' typeParameters
|
||||
// list.
|
||||
fun getFunctionTypeParameters(f: IrFunction): List<IrTypeParameter> {
|
||||
return if (f is IrConstructor) f.typeParameters
|
||||
else f.typeParameters.filter { it.parent == f }
|
||||
}
|
||||
|
||||
private fun getTypeParameters(dp: IrDeclarationParent): List<IrTypeParameter> =
|
||||
when (dp) {
|
||||
@@ -1405,213 +1222,6 @@ OLD: KE1
|
||||
else it.toBuilder().also { builder -> builder.arguments = newArgs }.buildSimpleType()
|
||||
} ?: t
|
||||
|
||||
/*
|
||||
* This is the normal getFunctionLabel function to use. If you want
|
||||
* to refer to the function in its source class then
|
||||
* classTypeArgsIncludingOuterClasses should be null. Otherwise, it
|
||||
* is the list of type arguments that need to be applied to its
|
||||
* enclosing classes to get the instantiation that this function is
|
||||
* in.
|
||||
*/
|
||||
fun getFunctionLabel(
|
||||
f: IrFunction,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
): String? {
|
||||
val parentId = useDeclarationParentOf(f, false, classTypeArgsIncludingOuterClasses, true)
|
||||
if (parentId == null) {
|
||||
logger.error("Couldn't get parent ID for function label")
|
||||
return null
|
||||
}
|
||||
return getFunctionLabel(f, parentId, classTypeArgsIncludingOuterClasses)
|
||||
}
|
||||
|
||||
/*
|
||||
* There are some pairs of classes (e.g. `kotlin.Throwable` and
|
||||
* `java.lang.Throwable`) which are really just 2 different names
|
||||
* for the same class. However, we extract them as separate
|
||||
* classes. When extracting `kotlin.Throwable`'s methods, if we
|
||||
* looked up the parent ID ourselves, we would get as ID for
|
||||
* `java.lang.Throwable`, which isn't what we want. So we have to
|
||||
* allow it to be passed in.
|
||||
*
|
||||
* `maybeParameterList` can be supplied to override the function's
|
||||
* value parameters; this is used for generating labels of overloads
|
||||
* that omit one or more parameters that has a default value specified.
|
||||
*/
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
*/
|
||||
fun getFunctionLabel(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
maybeParameterList: List<IrValueParameter>? = null
|
||||
*/
|
||||
): String =
|
||||
getFunctionLabel(
|
||||
/*
|
||||
OLD: KE1
|
||||
f.parent,
|
||||
*/
|
||||
parentId,
|
||||
f.name!!.asString(), // TODO: Remove the !! // OLD KE1: getFunctionShortName(f).nameInDB,
|
||||
/*
|
||||
OLD: KE1
|
||||
(maybeParameterList ?: f.valueParameters).map { it.type },
|
||||
getAdjustedReturnType(f),
|
||||
f.extensionReceiverParameter?.type,
|
||||
getFunctionTypeParameters(f),
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overridesCollectionsMethodWithAlteredParameterTypes(f),
|
||||
getJavaCallable(f),
|
||||
!getInnermostWildcardSupppressionAnnotation(f)
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
/*
|
||||
* This function actually generates the label for a function.
|
||||
* Sometimes, a function is only generated by kotlinc when writing a
|
||||
* class file, so there is no corresponding `IrFunction` for it.
|
||||
* This function therefore takes all the constituent parts of a
|
||||
* function instead.
|
||||
*/
|
||||
*/
|
||||
fun getFunctionLabel(
|
||||
/*
|
||||
OLD: KE1
|
||||
// The parent of the function; normally f.parent.
|
||||
parent: IrDeclarationParent,
|
||||
*/
|
||||
// OLD: KE1: The ID of the function's parent, or null if we should work it out ourselves.
|
||||
parentId: Label<out DbElement>,
|
||||
// OLD: KE1: The name of the function; normally f.name.asString().
|
||||
name: String,
|
||||
/*
|
||||
OLD: KE1
|
||||
// The types of the value parameters that the functions takes; normally
|
||||
// f.valueParameters.map { it.type }.
|
||||
parameterTypes: List<IrType>,
|
||||
// The return type of the function; normally f.returnType.
|
||||
returnType: IrType,
|
||||
// The extension receiver of the function, if any; normally
|
||||
// f.extensionReceiverParameter?.type.
|
||||
extensionParamType: IrType?,
|
||||
// The type parameters of the function. This does not include type parameters of enclosing
|
||||
// classes.
|
||||
functionTypeParameters: List<IrTypeParameter>,
|
||||
// The type arguments of enclosing classes of the function.
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
// If true, this method implements a Java Collections interface (Collection, Map or List)
|
||||
// and may need
|
||||
// parameter erasure to match the way this class will appear to an external consumer of the
|
||||
// .class file.
|
||||
overridesCollectionsMethod: Boolean,
|
||||
// The Java signature of this callable, if known.
|
||||
javaSignature: JavaMember?,
|
||||
// If true, Java wildcards implied by Kotlin type parameter variance should be added by
|
||||
// default to this function's value parameters' types.
|
||||
// (Return-type wildcard addition is always off by default)
|
||||
addParameterWildcardsByDefault: Boolean,
|
||||
// The prefix used in the label. "callable", unless a property label is created, then it's
|
||||
// "property".
|
||||
prefix: String = "callable"
|
||||
*/
|
||||
): String {
|
||||
/*
|
||||
OLD: KE1
|
||||
val allParamTypes =
|
||||
if (extensionParamType == null) parameterTypes
|
||||
else listOf(extensionParamType) + parameterTypes
|
||||
|
||||
val substitutionMap =
|
||||
classTypeArgsIncludingOuterClasses?.let { notNullArgs ->
|
||||
if (notNullArgs.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
val enclosingClass = getEnclosingClass(parent)
|
||||
enclosingClass?.let { notNullClass ->
|
||||
makeTypeGenericSubstitutionMap(notNullClass, notNullArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
val getIdForFunctionLabel = { it: IndexedValue<IrType> ->
|
||||
// Kotlin rewrites certain Java collections types adding additional generic
|
||||
// constraints-- for example,
|
||||
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin
|
||||
// universe.
|
||||
// If this has happened, erase the type again to get the correct Java signature.
|
||||
val maybeAmendedForCollections =
|
||||
if (overridesCollectionsMethod)
|
||||
eraseCollectionsMethodParameterType(it.value, name, it.index)
|
||||
else it.value
|
||||
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of
|
||||
// this function:
|
||||
val withAddedWildcards =
|
||||
addJavaLoweringWildcards(
|
||||
maybeAmendedForCollections,
|
||||
addParameterWildcardsByDefault,
|
||||
javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) }
|
||||
)
|
||||
// Now substitute any class type parameters in:
|
||||
val maybeSubbed =
|
||||
withAddedWildcards.substituteTypeAndArguments(
|
||||
substitutionMap,
|
||||
TypeContext.OTHER,
|
||||
pluginContext
|
||||
)
|
||||
// Finally, mimic the Java extractor's behaviour by naming functions with type
|
||||
// parameters for their erased types;
|
||||
// those without type parameters are named for the generic type.
|
||||
val maybeErased =
|
||||
if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
|
||||
"{${useType(maybeErased).javaResult.id}}"
|
||||
}
|
||||
val paramTypeIds =
|
||||
allParamTypes
|
||||
.withIndex()
|
||||
.joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val labelReturnType =
|
||||
if (name == "<init>") pluginContext.irBuiltIns.unitType
|
||||
else
|
||||
erase(
|
||||
returnType.substituteTypeAndArguments(
|
||||
substitutionMap,
|
||||
TypeContext.RETURN,
|
||||
pluginContext
|
||||
)
|
||||
)
|
||||
// Note that `addJavaLoweringWildcards` is not required here because the return type used to
|
||||
// form the function
|
||||
// label is always erased.
|
||||
val returnTypeId = useType(labelReturnType, TypeContext.RETURN).javaResult.id
|
||||
// This suffix is added to generic methods (and constructors) to match the Java extractor's
|
||||
// behaviour.
|
||||
// Comments in that extractor indicates it didn't want the label of the callable to clash
|
||||
// with the raw
|
||||
// method (and presumably that disambiguation is never needed when the method belongs to a
|
||||
// parameterized
|
||||
// instance of a generic class), but as of now I don't know when the raw method would be
|
||||
// referred to.
|
||||
val typeArgSuffix =
|
||||
if (
|
||||
functionTypeParameters.isNotEmpty() &&
|
||||
classTypeArgsIncludingOuterClasses.isNullOrEmpty()
|
||||
)
|
||||
"<${functionTypeParameters.size}>"
|
||||
else ""
|
||||
*/
|
||||
val prefix = "callable" // TODO
|
||||
val paramTypeIds = "x" // TODO
|
||||
val returnTypeId = "x" // TODO
|
||||
val typeArgSuffix = "" // TODO
|
||||
return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}$typeArgSuffix\""
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
val javaLangClass by lazy { referenceExternalClass("java.lang.Class") }
|
||||
|
||||
fun kClassToJavaClass(t: IrType): IrType {
|
||||
@@ -1853,56 +1463,6 @@ OLD: KE1
|
||||
}
|
||||
*/
|
||||
|
||||
fun <T : DbCallable> useFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
noReplace: Boolean = false
|
||||
*/
|
||||
): Label<out T> {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (f.isLocalFunction()) {
|
||||
val ids = getLocallyVisibleFunctionLabels(f)
|
||||
return ids.function.cast<T>()
|
||||
}
|
||||
*/
|
||||
val javaFun = f // TODO: kotlinFunctionToJavaEquivalent(f, noReplace)
|
||||
return useFunction(f, javaFun, parentId /* TODO , classTypeArgsIncludingOuterClasses */)
|
||||
}
|
||||
|
||||
private fun <T : DbCallable> useFunction(
|
||||
f: KaFunctionSymbol,
|
||||
javaFun: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): Label<out T> {
|
||||
println("=== useFunction")
|
||||
println(f)
|
||||
println(f.returnType)
|
||||
val label = getFunctionLabel(javaFun, parentId /* TODO , classTypeArgsIncludingOuterClasses */)
|
||||
val id: Label<T> =
|
||||
tw.getLabelFor(label) {
|
||||
/*
|
||||
OLD: KE1
|
||||
extractPrivateSpecialisedDeclaration(f, classTypeArgsIncludingOuterClasses)
|
||||
*/
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (isExternalDeclaration(javaFun)) {
|
||||
extractFunctionLaterIfExternalFileMember(javaFun)
|
||||
extractExternalEnclosingClassLater(javaFun)
|
||||
}
|
||||
*/
|
||||
return id
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
private fun extractPrivateSpecialisedDeclaration(
|
||||
@@ -1997,93 +1557,6 @@ OLD: KE1
|
||||
|
||||
data class ClassLabelResults(val classLabel: String /* TODO , val shortName: String */)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
/**
|
||||
* This returns the `X` in c's label `@"class;X"`.
|
||||
*
|
||||
* `argsIncludingOuterClasses` can be null to describe a raw generic type. For non-generic types
|
||||
* it will be zero-length list.
|
||||
*/
|
||||
*/
|
||||
private fun getUnquotedClassLabel(
|
||||
c: KaClassType,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): ClassLabelResults {
|
||||
val pkg = c.classId.packageFqName.asString()
|
||||
val cls = c.classId.relativeClassName.asString()
|
||||
val label =
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.isAnonymousObject) "{${useAnonymousClass(c).javaResult.id}}"
|
||||
else
|
||||
when (val parent = c.parent) {
|
||||
is IrClass -> {
|
||||
"${getUnquotedClassLabel(parent, listOf()).classLabel}\$$cls"
|
||||
}
|
||||
is IrFunction -> {
|
||||
"{${useFunction<DbMethod>(parent)}}.$cls"
|
||||
}
|
||||
is IrField -> {
|
||||
"{${useField(parent)}}.$cls"
|
||||
}
|
||||
else -> {
|
||||
*/
|
||||
if (pkg.isEmpty()) cls else "$pkg.$cls"
|
||||
/*
|
||||
OLD: KE1
|
||||
}
|
||||
}
|
||||
|
||||
val reorderedArgs = orderTypeArgsLeftToRight(c, argsIncludingOuterClasses)
|
||||
val typeArgLabels = reorderedArgs?.map { getTypeArgumentLabel(it) }
|
||||
val typeArgsShortName =
|
||||
if (typeArgLabels == null) "<>"
|
||||
else if (typeArgLabels.isEmpty()) ""
|
||||
else
|
||||
typeArgLabels.takeLast(c.typeParameters.size).joinToString(
|
||||
prefix = "<",
|
||||
postfix = ">",
|
||||
separator = ","
|
||||
) {
|
||||
it.shortName
|
||||
}
|
||||
val shortNamePrefix = if (c.isAnonymousObject) "" else cls
|
||||
*/
|
||||
|
||||
return ClassLabelResults(
|
||||
label // OLD: KE1: + (typeArgLabels?.joinToString(separator = "") { ";{${it.id}}" } ?: "<>"),
|
||||
/*
|
||||
OLD: KE1
|
||||
shortNamePrefix + typeArgsShortName
|
||||
*/
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
// `args` can be null to describe a raw generic type.
|
||||
// For non-generic types it will be zero-length list.
|
||||
*/
|
||||
fun getClassLabel(
|
||||
c: KaClassType,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): ClassLabelResults {
|
||||
val unquotedLabel = getUnquotedClassLabel(c /* TODO , argsIncludingOuterClasses */)
|
||||
return ClassLabelResults("@\"class;${unquotedLabel.classLabel}\"" /* TODO , unquotedLabel.shortName */)
|
||||
}
|
||||
|
||||
fun useClassSource(c: KaClassSymbol): Label<out DbClassorinterface> {
|
||||
// For source classes, the label doesn't include any type arguments
|
||||
val classTypeResult = addClassLabel(buildClassType(c) as KaClassType)
|
||||
return classTypeResult.id
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
|
||||
374
java/kotlin-extractor2/src/main/kotlin/entities/Class.kt
Normal file
374
java/kotlin-extractor2/src/main/kotlin/entities/Class.kt
Normal file
@@ -0,0 +1,374 @@
|
||||
import com.github.codeql.*
|
||||
import com.github.codeql.KotlinUsesExtractor.ClassLabelResults
|
||||
import com.github.codeql.KotlinUsesExtractor.TypeContext
|
||||
import com.github.codeql.utils.isInterfaceLike
|
||||
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaClassType
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
|
||||
context(KaSession)
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
fun KotlinFileExtractor.extractClassSource(
|
||||
c: KaClassSymbol,
|
||||
extractDeclarations: Boolean,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractStaticInitializer: Boolean,
|
||||
extractPrivateMembers: Boolean,
|
||||
extractFunctionBodies: Boolean
|
||||
*/
|
||||
): Label<out DbClassorinterface> {
|
||||
with("class source", c.psiSafe() ?: TODO()) {
|
||||
DeclarationStackAdjuster(c).use {
|
||||
val id = useClassSource(c)
|
||||
val pkg = c.classId?.packageFqName?.asString() ?: ""
|
||||
val cls =
|
||||
if (c.classKind == KaClassKind.ANONYMOUS_OBJECT) "" else c.name!!.asString() // TODO: Remove !!
|
||||
val pkgId = extractPackage(pkg)
|
||||
tw.writeClasses_or_interfaces(id, cls, pkgId, id)
|
||||
if (c.isInterfaceLike) {
|
||||
tw.writeIsInterface(id)
|
||||
if (c.classKind == KaClassKind.ANNOTATION_CLASS) {
|
||||
tw.writeIsAnnotType(id)
|
||||
}
|
||||
} else {
|
||||
val kind = c.classKind
|
||||
if (kind == KaClassKind.ENUM_CLASS) {
|
||||
tw.writeIsEnumType(id)
|
||||
} else if (
|
||||
kind != KaClassKind.CLASS &&
|
||||
kind != KaClassKind.OBJECT //&&
|
||||
//OLD KE1: kind != ClassKind.ENUM_ENTRY
|
||||
) {
|
||||
logger.warnElement("Unrecognised class kind $kind", c.psiSafe() ?: TODO())
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.origin == IrDeclarationOrigin.FILE_CLASS) {
|
||||
tw.writeFile_class(id)
|
||||
}
|
||||
*/
|
||||
|
||||
if ((c as? KaNamedClassSymbol)?.isData == true) {
|
||||
tw.writeKtDataClasses(id)
|
||||
}
|
||||
}
|
||||
|
||||
val locId = tw.getLocation(c.psiSafe() ?: TODO())
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
// OLD: KE1
|
||||
//extractEnclosingClass(c.parent, id, c, locId, listOf())
|
||||
//val javaClass = (c.source as? JavaSourceElement)?.javaElement as? JavaClass
|
||||
|
||||
c.typeParameters.mapIndexed { idx, param ->
|
||||
//extractTypeParameter(param, idx, javaClass?.typeParameters?.getOrNull(idx))
|
||||
}
|
||||
if (extractDeclarations) {
|
||||
if (c.classKind == KaClassKind.ANNOTATION_CLASS) {
|
||||
c.declaredMemberScope.declarations.filterIsInstance<KaPropertySymbol>().forEach {
|
||||
val getter = it.getter
|
||||
if (getter == null) {
|
||||
logger.warnElement(
|
||||
"Expected an annotation property to have a getter",
|
||||
it.psiSafe() ?: TODO()
|
||||
)
|
||||
} else {
|
||||
extractFunction(
|
||||
getter,
|
||||
id,
|
||||
/* OLD: KE1
|
||||
extractBody = false,
|
||||
extractMethodAndParameterTypeAccesses =
|
||||
extractFunctionBodies,
|
||||
extractAnnotations = true,
|
||||
null,
|
||||
listOf()
|
||||
*/
|
||||
)
|
||||
?.also { functionLabel ->
|
||||
tw.writeIsAnnotElem(functionLabel.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
val decl = c.declaredMemberScope.declarations.toList()
|
||||
c.declaredMemberScope.declarations.forEach {
|
||||
extractDeclaration(
|
||||
it,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractPrivateMembers = extractPrivateMembers,
|
||||
extractFunctionBodies = extractFunctionBodies,
|
||||
extractAnnotations = true
|
||||
*/
|
||||
)
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (extractStaticInitializer) extractStaticInitializer(c, { id })
|
||||
extractJvmStaticProxyMethods(
|
||||
c,
|
||||
id,
|
||||
extractPrivateMembers,
|
||||
extractFunctionBodies
|
||||
)
|
||||
*/
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// A Kotlin bug causes this to throw: https://youtrack.jetbrains.com/issue/KT-63847/K2-IllegalStateException-IrFieldPublicSymbolImpl-for-java.time-Clock.OffsetClock.offset0-is-already-bound
|
||||
// TODO: This should either be removed or log something, once the bug is fixed
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.isNonCompanionObject) {
|
||||
// For `object MyObject { ... }`, the .class has an
|
||||
// automatically-generated `public static final MyObject INSTANCE`
|
||||
// field that may be referenced from Java code, and is used in our
|
||||
// IrGetObjectValue support. We therefore need to fabricate it
|
||||
// here.
|
||||
val instance = useObjectClassInstance(c)
|
||||
val type = useSimpleTypeClass(c, emptyList(), false)
|
||||
tw.writeFields(instance.id, instance.name, type.javaResult.id, id, instance.id)
|
||||
tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(instance.id, locId)
|
||||
addModifiers(instance.id, "public", "static", "final")
|
||||
tw.writeClass_object(id, instance.id)
|
||||
}
|
||||
*/
|
||||
if (c.classKind == KaClassKind.OBJECT) {
|
||||
addModifiers(id, "static")
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (extractFunctionBodies && needsObinitFunction(c)) {
|
||||
extractObinitFunction(c, id)
|
||||
}
|
||||
|
||||
extractClassModifiers(c, id)
|
||||
extractClassSupertypes(
|
||||
c,
|
||||
id,
|
||||
inReceiverContext = true
|
||||
) // inReceiverContext = true is specified to force extraction of member prototypes
|
||||
// of base types
|
||||
|
||||
linesOfCode?.linesOfCodeInDeclaration(c, id)
|
||||
|
||||
val additionalAnnotations =
|
||||
if (
|
||||
c.kind == ClassKind.ANNOTATION_CLASS &&
|
||||
c.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
)
|
||||
metaAnnotationSupport.generateJavaMetaAnnotations(c, extractFunctionBodies)
|
||||
else listOf()
|
||||
|
||||
extractAnnotations(
|
||||
c,
|
||||
c.annotations + additionalAnnotations,
|
||||
id,
|
||||
extractFunctionBodies
|
||||
)
|
||||
|
||||
if (extractFunctionBodies && !c.isAnonymousObject && !c.isLocal)
|
||||
externalClassExtractor.writeStubTrapFile(c)
|
||||
*/
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
// `args` can be null to describe a raw generic type.
|
||||
// For non-generic types it will be zero-length list.
|
||||
*/
|
||||
private fun KotlinUsesExtractor.getClassLabel(
|
||||
c: KaClassType,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): ClassLabelResults {
|
||||
val unquotedLabel = getUnquotedClassLabel(c /* TODO , argsIncludingOuterClasses */)
|
||||
return ClassLabelResults("@\"class;${unquotedLabel.classLabel}\"" /* TODO , unquotedLabel.shortName */)
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
fun KotlinUsesExtractor.useClassSource(c: KaClassSymbol): Label<out DbClassorinterface> {
|
||||
// For source classes, the label doesn't include any type arguments
|
||||
val classTypeResult = addClassLabel(buildClassType(c) as KaClassType)
|
||||
return classTypeResult.id
|
||||
}
|
||||
|
||||
// `typeArgs` can be null to describe a raw generic type.
|
||||
// For non-generic types it will be zero-length list.
|
||||
private fun KotlinUsesExtractor.addClassLabel(
|
||||
c: KaClassType, // TODO cBeforeReplacement: IrClass,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?,
|
||||
inReceiverContext: Boolean = false
|
||||
*/
|
||||
): TypeResult<DbClassorinterface> {
|
||||
/*
|
||||
OLD: KE1
|
||||
val replaced =
|
||||
tryReplaceType(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
|
||||
val replacedClass = replaced.first
|
||||
val replacedArgsIncludingOuterClasses = replaced.second
|
||||
|
||||
*/
|
||||
val classLabelResult = getClassLabel(c /* TODO replacedClass, replacedArgsIncludingOuterClasses */)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
var instanceSeenBefore = true
|
||||
*/
|
||||
|
||||
val classLabel: Label<out DbClassorinterface> =
|
||||
tw.getLabelFor(classLabelResult.classLabel) {
|
||||
/*
|
||||
OLD: KE1
|
||||
instanceSeenBefore = false
|
||||
|
||||
extractClassLaterIfExternal(replacedClass)
|
||||
*/
|
||||
// TODO: This shouldn't be done here, but keeping it simple for now
|
||||
val pkgId = extractPackage(c.classId.packageFqName.asString())
|
||||
tw.writeClasses_or_interfaces(it, c.classId.relativeClassName.asString(), pkgId, it)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (
|
||||
replacedArgsIncludingOuterClasses == null ||
|
||||
replacedArgsIncludingOuterClasses.isNotEmpty()
|
||||
) {
|
||||
// If this is a generic type instantiation or a raw type then it has no
|
||||
// source entity, so we need to extract it here
|
||||
val shouldExtractClassDetails =
|
||||
inReceiverContext &&
|
||||
tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)
|
||||
if (!instanceSeenBefore || shouldExtractClassDetails) {
|
||||
this.withFileOfClass(replacedClass)
|
||||
.extractClassInstance(
|
||||
classLabel,
|
||||
replacedClass,
|
||||
replacedArgsIncludingOuterClasses,
|
||||
!instanceSeenBefore,
|
||||
shouldExtractClassDetails
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val fqName = replacedClass.fqNameWhenAvailable
|
||||
val signature =
|
||||
if (replacedClass.isAnonymousObject) {
|
||||
null
|
||||
} else if (fqName == null) {
|
||||
logger.error("Unable to find signature/fqName for ${replacedClass.name}")
|
||||
null
|
||||
} else {
|
||||
fqName.asString()
|
||||
}
|
||||
*/
|
||||
return TypeResult(classLabel /* TODO , signature, classLabelResult.shortName */)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
/**
|
||||
* This returns the `X` in c's label `@"class;X"`.
|
||||
*
|
||||
* `argsIncludingOuterClasses` can be null to describe a raw generic type. For non-generic types
|
||||
* it will be zero-length list.
|
||||
*/
|
||||
*/
|
||||
private fun KotlinUsesExtractor.getUnquotedClassLabel(
|
||||
c: KaClassType,
|
||||
/*
|
||||
OLD: KE1
|
||||
argsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): ClassLabelResults {
|
||||
val pkg = c.classId.packageFqName.asString()
|
||||
val cls = c.classId.relativeClassName.asString()
|
||||
val label =
|
||||
/*
|
||||
OLD: KE1
|
||||
if (c.isAnonymousObject) "{${useAnonymousClass(c).javaResult.id}}"
|
||||
else
|
||||
when (val parent = c.parent) {
|
||||
is IrClass -> {
|
||||
"${getUnquotedClassLabel(parent, listOf()).classLabel}\$$cls"
|
||||
}
|
||||
is IrFunction -> {
|
||||
"{${useFunction<DbMethod>(parent)}}.$cls"
|
||||
}
|
||||
is IrField -> {
|
||||
"{${useField(parent)}}.$cls"
|
||||
}
|
||||
else -> {
|
||||
*/
|
||||
if (pkg.isEmpty()) cls else "$pkg.$cls"
|
||||
/*
|
||||
OLD: KE1
|
||||
}
|
||||
}
|
||||
|
||||
val reorderedArgs = orderTypeArgsLeftToRight(c, argsIncludingOuterClasses)
|
||||
val typeArgLabels = reorderedArgs?.map { getTypeArgumentLabel(it) }
|
||||
val typeArgsShortName =
|
||||
if (typeArgLabels == null) "<>"
|
||||
else if (typeArgLabels.isEmpty()) ""
|
||||
else
|
||||
typeArgLabels.takeLast(c.typeParameters.size).joinToString(
|
||||
prefix = "<",
|
||||
postfix = ">",
|
||||
separator = ","
|
||||
) {
|
||||
it.shortName
|
||||
}
|
||||
val shortNamePrefix = if (c.isAnonymousObject) "" else cls
|
||||
*/
|
||||
|
||||
return ClassLabelResults(
|
||||
label // OLD: KE1: + (typeArgLabels?.joinToString(separator = "") { ";{${it.id}}" } ?: "<>"),
|
||||
/*
|
||||
OLD: KE1
|
||||
shortNamePrefix + typeArgsShortName
|
||||
*/
|
||||
)
|
||||
}
|
||||
|
||||
private fun KotlinUsesExtractor.useClassType(
|
||||
c: KaClassType
|
||||
): TypeResults {
|
||||
val javaResult = addClassLabel(c)
|
||||
val kotlinResult = TypeResult(fakeKotlinType() /* , "TODO", "TODO" */)
|
||||
return TypeResults(javaResult, kotlinResult)
|
||||
}
|
||||
|
||||
fun KotlinUsesExtractor.useType(t: KaType, context: TypeContext = TypeContext.OTHER): TypeResults {
|
||||
when (t) {
|
||||
is KaClassType -> return useClassType(t)
|
||||
else -> TODO()
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
when (t) {
|
||||
is IrSimpleType -> return useSimpleType(t, context)
|
||||
else -> {
|
||||
logger.error("Unrecognised IrType: " + t.javaClass)
|
||||
return extractErrorType()
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
722
java/kotlin-extractor2/src/main/kotlin/entities/Function.kt
Normal file
722
java/kotlin-extractor2/src/main/kotlin/entities/Function.kt
Normal file
@@ -0,0 +1,722 @@
|
||||
import com.github.codeql.*
|
||||
import com.github.codeql.KotlinUsesExtractor.TypeContext
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.name
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.psiSafe
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
|
||||
/*
|
||||
* There are some pairs of classes (e.g. `kotlin.Throwable` and
|
||||
* `java.lang.Throwable`) which are really just 2 different names
|
||||
* for the same class. However, we extract them as separate
|
||||
* classes. When extracting `kotlin.Throwable`'s methods, if we
|
||||
* looked up the parent ID ourselves, we would get as ID for
|
||||
* `java.lang.Throwable`, which isn't what we want. So we have to
|
||||
* allow it to be passed in.
|
||||
*
|
||||
* `maybeParameterList` can be supplied to override the function's
|
||||
* value parameters; this is used for generating labels of overloads
|
||||
* that omit one or more parameters that has a default value specified.
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
*/
|
||||
fun KotlinUsesExtractor.getFunctionLabel(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
maybeParameterList: List<IrValueParameter>? = null
|
||||
*/
|
||||
): String =
|
||||
getFunctionLabel(
|
||||
/*
|
||||
OLD: KE1
|
||||
f.parent,
|
||||
*/
|
||||
parentId,
|
||||
f.name!!.asString(), // TODO: Remove the !! // OLD KE1: getFunctionShortName(f).nameInDB,
|
||||
/*
|
||||
OLD: KE1
|
||||
(maybeParameterList ?: f.valueParameters).map { it.type },
|
||||
getAdjustedReturnType(f),
|
||||
f.extensionReceiverParameter?.type,
|
||||
getFunctionTypeParameters(f),
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overridesCollectionsMethodWithAlteredParameterTypes(f),
|
||||
getJavaCallable(f),
|
||||
!getInnermostWildcardSupppressionAnnotation(f)
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
/*
|
||||
* This function actually generates the label for a function.
|
||||
* Sometimes, a function is only generated by kotlinc when writing a
|
||||
* class file, so there is no corresponding `IrFunction` for it.
|
||||
* This function therefore takes all the constituent parts of a
|
||||
* function instead.
|
||||
*/
|
||||
*/
|
||||
fun KotlinUsesExtractor.getFunctionLabel(
|
||||
/*
|
||||
OLD: KE1
|
||||
// The parent of the function; normally f.parent.
|
||||
parent: IrDeclarationParent,
|
||||
*/
|
||||
// OLD: KE1: The ID of the function's parent, or null if we should work it out ourselves.
|
||||
parentId: Label<out DbElement>,
|
||||
// OLD: KE1: The name of the function; normally f.name.asString().
|
||||
name: String,
|
||||
/*
|
||||
OLD: KE1
|
||||
// The types of the value parameters that the functions takes; normally
|
||||
// f.valueParameters.map { it.type }.
|
||||
parameterTypes: List<IrType>,
|
||||
// The return type of the function; normally f.returnType.
|
||||
returnType: IrType,
|
||||
// The extension receiver of the function, if any; normally
|
||||
// f.extensionReceiverParameter?.type.
|
||||
extensionParamType: IrType?,
|
||||
// The type parameters of the function. This does not include type parameters of enclosing
|
||||
// classes.
|
||||
functionTypeParameters: List<IrTypeParameter>,
|
||||
// The type arguments of enclosing classes of the function.
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
// If true, this method implements a Java Collections interface (Collection, Map or List)
|
||||
// and may need
|
||||
// parameter erasure to match the way this class will appear to an external consumer of the
|
||||
// .class file.
|
||||
overridesCollectionsMethod: Boolean,
|
||||
// The Java signature of this callable, if known.
|
||||
javaSignature: JavaMember?,
|
||||
// If true, Java wildcards implied by Kotlin type parameter variance should be added by
|
||||
// default to this function's value parameters' types.
|
||||
// (Return-type wildcard addition is always off by default)
|
||||
addParameterWildcardsByDefault: Boolean,
|
||||
// The prefix used in the label. "callable", unless a property label is created, then it's
|
||||
// "property".
|
||||
prefix: String = "callable"
|
||||
*/
|
||||
): String {
|
||||
/*
|
||||
OLD: KE1
|
||||
val allParamTypes =
|
||||
if (extensionParamType == null) parameterTypes
|
||||
else listOf(extensionParamType) + parameterTypes
|
||||
|
||||
val substitutionMap =
|
||||
classTypeArgsIncludingOuterClasses?.let { notNullArgs ->
|
||||
if (notNullArgs.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
val enclosingClass = getEnclosingClass(parent)
|
||||
enclosingClass?.let { notNullClass ->
|
||||
makeTypeGenericSubstitutionMap(notNullClass, notNullArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
val getIdForFunctionLabel = { it: IndexedValue<IrType> ->
|
||||
// Kotlin rewrites certain Java collections types adding additional generic
|
||||
// constraints-- for example,
|
||||
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin
|
||||
// universe.
|
||||
// If this has happened, erase the type again to get the correct Java signature.
|
||||
val maybeAmendedForCollections =
|
||||
if (overridesCollectionsMethod)
|
||||
eraseCollectionsMethodParameterType(it.value, name, it.index)
|
||||
else it.value
|
||||
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of
|
||||
// this function:
|
||||
val withAddedWildcards =
|
||||
addJavaLoweringWildcards(
|
||||
maybeAmendedForCollections,
|
||||
addParameterWildcardsByDefault,
|
||||
javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) }
|
||||
)
|
||||
// Now substitute any class type parameters in:
|
||||
val maybeSubbed =
|
||||
withAddedWildcards.substituteTypeAndArguments(
|
||||
substitutionMap,
|
||||
TypeContext.OTHER,
|
||||
pluginContext
|
||||
)
|
||||
// Finally, mimic the Java extractor's behaviour by naming functions with type
|
||||
// parameters for their erased types;
|
||||
// those without type parameters are named for the generic type.
|
||||
val maybeErased =
|
||||
if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
|
||||
"{${useType(maybeErased).javaResult.id}}"
|
||||
}
|
||||
val paramTypeIds =
|
||||
allParamTypes
|
||||
.withIndex()
|
||||
.joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val labelReturnType =
|
||||
if (name == "<init>") pluginContext.irBuiltIns.unitType
|
||||
else
|
||||
erase(
|
||||
returnType.substituteTypeAndArguments(
|
||||
substitutionMap,
|
||||
TypeContext.RETURN,
|
||||
pluginContext
|
||||
)
|
||||
)
|
||||
// Note that `addJavaLoweringWildcards` is not required here because the return type used to
|
||||
// form the function
|
||||
// label is always erased.
|
||||
val returnTypeId = useType(labelReturnType, TypeContext.RETURN).javaResult.id
|
||||
// This suffix is added to generic methods (and constructors) to match the Java extractor's
|
||||
// behaviour.
|
||||
// Comments in that extractor indicates it didn't want the label of the callable to clash
|
||||
// with the raw
|
||||
// method (and presumably that disambiguation is never needed when the method belongs to a
|
||||
// parameterized
|
||||
// instance of a generic class), but as of now I don't know when the raw method would be
|
||||
// referred to.
|
||||
val typeArgSuffix =
|
||||
if (
|
||||
functionTypeParameters.isNotEmpty() &&
|
||||
classTypeArgsIncludingOuterClasses.isNullOrEmpty()
|
||||
)
|
||||
"<${functionTypeParameters.size}>"
|
||||
else ""
|
||||
*/
|
||||
val prefix = "callable" // TODO
|
||||
val paramTypeIds = "x" // TODO
|
||||
val returnTypeId = "x" // TODO
|
||||
val typeArgSuffix = "" // TODO
|
||||
return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}$typeArgSuffix\""
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
private val IrDeclaration.isAnonymousFunction
|
||||
get() = this is IrSimpleFunction && name == SpecialNames.NO_NAME_PROVIDED
|
||||
|
||||
data class FunctionNames(val nameInDB: String, val kotlinName: String)
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun getJvmModuleName(f: IrFunction) =
|
||||
NameUtils.sanitizeAsJavaIdentifier(
|
||||
getJvmModuleNameForDeserializedDescriptor(f.descriptor)
|
||||
?: JvmCodegenUtil.getModuleName(pluginContext.moduleDescriptor)
|
||||
)
|
||||
|
||||
fun getFunctionShortName(f: IrFunction): FunctionNames {
|
||||
if (f.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || f.isAnonymousFunction)
|
||||
return FunctionNames(
|
||||
OperatorNameConventions.INVOKE.asString(),
|
||||
OperatorNameConventions.INVOKE.asString()
|
||||
)
|
||||
|
||||
fun getSuffixIfInternal() =
|
||||
if (
|
||||
f.visibility == DescriptorVisibilities.INTERNAL &&
|
||||
f !is IrConstructor &&
|
||||
!(f.parent is IrFile || isExternalFileClassMember(f))
|
||||
) {
|
||||
"\$" + getJvmModuleName(f)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
(f as? IrSimpleFunction)?.correspondingPropertySymbol?.let {
|
||||
val propName = it.owner.name.asString()
|
||||
val getter = it.owner.getter
|
||||
val setter = it.owner.setter
|
||||
|
||||
if (it.owner.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS) {
|
||||
if (getter == null) {
|
||||
logger.error(
|
||||
"Expected to find a getter for a property inside an annotation class"
|
||||
)
|
||||
return FunctionNames(propName, propName)
|
||||
} else {
|
||||
val jvmName = getJvmName(getter)
|
||||
return FunctionNames(jvmName ?: propName, propName)
|
||||
}
|
||||
}
|
||||
|
||||
val maybeFunctionName =
|
||||
when (f) {
|
||||
getter -> JvmAbi.getterName(propName)
|
||||
setter -> JvmAbi.setterName(propName)
|
||||
else -> {
|
||||
logger.error(
|
||||
"Function has a corresponding property, but is neither the getter nor the setter"
|
||||
)
|
||||
null
|
||||
}
|
||||
}
|
||||
maybeFunctionName?.let { defaultFunctionName ->
|
||||
val suffix =
|
||||
if (
|
||||
f.visibility == DescriptorVisibilities.PRIVATE &&
|
||||
f.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
|
||||
) {
|
||||
"\$private"
|
||||
} else {
|
||||
getSuffixIfInternal()
|
||||
}
|
||||
return FunctionNames(
|
||||
getJvmName(f) ?: "$defaultFunctionName$suffix",
|
||||
defaultFunctionName
|
||||
)
|
||||
}
|
||||
}
|
||||
return FunctionNames(
|
||||
getJvmName(f) ?: "${f.name.asString()}${getSuffixIfInternal()}",
|
||||
f.name.asString()
|
||||
)
|
||||
}
|
||||
|
||||
// This excludes class type parameters that show up in (at least) constructors' typeParameters
|
||||
// list.
|
||||
fun getFunctionTypeParameters(f: IrFunction): List<IrTypeParameter> {
|
||||
return if (f is IrConstructor) f.typeParameters
|
||||
else f.typeParameters.filter { it.parent == f }
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the normal getFunctionLabel function to use. If you want
|
||||
* to refer to the function in its source class then
|
||||
* classTypeArgsIncludingOuterClasses should be null. Otherwise, it
|
||||
* is the list of type arguments that need to be applied to its
|
||||
* enclosing classes to get the instantiation that this function is
|
||||
* in.
|
||||
*/
|
||||
fun getFunctionLabel(
|
||||
f: IrFunction,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
): String? {
|
||||
val parentId = useDeclarationParentOf(f, false, classTypeArgsIncludingOuterClasses, true)
|
||||
if (parentId == null) {
|
||||
logger.error("Couldn't get parent ID for function label")
|
||||
return null
|
||||
}
|
||||
return getFunctionLabel(f, parentId, classTypeArgsIncludingOuterClasses)
|
||||
}
|
||||
*/
|
||||
|
||||
fun KotlinFileExtractor.extractFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody: Boolean,
|
||||
extractMethodAndParameterTypeAccesses: Boolean,
|
||||
extractAnnotations: Boolean,
|
||||
typeSubstitution: TypeSubstitution?,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): Label<out DbCallable> {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (isFake(f)) {
|
||||
if (needsInterfaceForwarder(f)) {
|
||||
return makeInterfaceForwarder(
|
||||
f,
|
||||
parentId,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
// Work around an apparent bug causing redeclarations of `fun toString(): String`
|
||||
// specifically in interfaces loaded from Java classes show up like fake overrides.
|
||||
val overriddenVisibility =
|
||||
if (f.isFakeOverride && isJavaBinaryObjectMethodRedeclaration(f))
|
||||
OverriddenFunctionAttributes(visibility = DescriptorVisibilities.PUBLIC)
|
||||
else null
|
||||
*/
|
||||
return forceExtractFunction(
|
||||
f,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
extractAnnotations,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overriddenAttributes = overriddenVisibility
|
||||
*/
|
||||
)
|
||||
/*
|
||||
OLD: KE1
|
||||
.also {
|
||||
// The defaults-forwarder function is a static utility, not a member, so we only
|
||||
// need to extract this for the unspecialised instance of this class.
|
||||
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
|
||||
extractDefaultsFunction(
|
||||
f,
|
||||
parentId,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
)
|
||||
extractGeneratedOverloads(
|
||||
f,
|
||||
parentId,
|
||||
null,
|
||||
extractBody,
|
||||
extractMethodAndParameterTypeAccesses,
|
||||
typeSubstitution,
|
||||
classTypeArgsIncludingOuterClasses
|
||||
)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// TODO: Can this be inlined?
|
||||
private fun KotlinFileExtractor.forceExtractFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
extractBody: Boolean,
|
||||
extractMethodAndParameterTypeAccesses: Boolean,
|
||||
extractAnnotations: Boolean,
|
||||
typeSubstitution: TypeSubstitution?,
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
extractOrigin: Boolean = true,
|
||||
overriddenAttributes: OverriddenFunctionAttributes? = null
|
||||
*/
|
||||
): Label<out DbCallable> {
|
||||
with("function", f.psiSafe() ?: TODO()) {
|
||||
/*
|
||||
OLD: KE1
|
||||
DeclarationStackAdjuster(f, overriddenAttributes).use {
|
||||
val javaCallable = getJavaCallable(f)
|
||||
getFunctionTypeParameters(f).mapIndexed { idx, tp ->
|
||||
extractTypeParameter(
|
||||
tp,
|
||||
idx,
|
||||
(javaCallable as? JavaTypeParameterListOwner)
|
||||
?.typeParameters
|
||||
?.getOrNull(idx)
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
val id =
|
||||
/*
|
||||
OLD: KE1
|
||||
overriddenAttributes?.id
|
||||
?: // If this is a class that would ordinarily be replaced by a Java
|
||||
// equivalent (e.g. kotlin.Map -> java.util.Map),
|
||||
// don't replace here, really extract the Kotlin version:
|
||||
*/
|
||||
useFunction<DbCallable>(
|
||||
f,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
noReplace = true
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
val sourceDeclaration =
|
||||
overriddenAttributes?.sourceDeclarationId
|
||||
?: if (typeSubstitution != null && overriddenAttributes?.id == null) {
|
||||
val sourceFunId = useFunction<DbCallable>(f)
|
||||
if (sourceFunId == null) {
|
||||
logger.errorElement("Cannot get source ID for function", f)
|
||||
id // TODO: This is wrong; we ought to just fail in this case
|
||||
} else {
|
||||
sourceFunId
|
||||
}
|
||||
} else {
|
||||
id
|
||||
}
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
// The following parameter order is correct, because member $default methods (where
|
||||
// the order would be [dispatchParam], [extensionParam], normalParams) are not
|
||||
// extracted here
|
||||
val fParameters =
|
||||
listOfNotNull(extReceiver) +
|
||||
(overriddenAttributes?.valueParameters ?: f.valueParameters)
|
||||
val paramTypes =
|
||||
fParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(
|
||||
vp,
|
||||
id,
|
||||
i,
|
||||
typeSubstitution,
|
||||
sourceDeclaration,
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
extractTypeAccess = extractMethodAndParameterTypeAccesses,
|
||||
overriddenAttributes?.sourceLoc
|
||||
)
|
||||
}
|
||||
if (extReceiver != null) {
|
||||
val extendedType = paramTypes[0]
|
||||
tw.writeKtExtensionFunctions(
|
||||
id.cast<DbMethod>(),
|
||||
extendedType.javaResult.id,
|
||||
extendedType.kotlinResult.id
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
val paramsSignature = "()" // TODO:
|
||||
/*
|
||||
OLD: KE1
|
||||
paramTypes.joinToString(separator = ",", prefix = "(", postfix = ")") {
|
||||
signatureOrWarn(it.javaResult, f)
|
||||
}
|
||||
|
||||
val adjustedReturnType =
|
||||
addJavaLoweringWildcards(
|
||||
getAdjustedReturnType(f),
|
||||
false,
|
||||
(javaCallable as? JavaMethod)?.returnType
|
||||
)
|
||||
val substReturnType =
|
||||
typeSubstitution?.let {
|
||||
it(adjustedReturnType, TypeContext.RETURN, pluginContext)
|
||||
} ?: adjustedReturnType
|
||||
*/
|
||||
val functionSyntax = f.psi as? KtDeclarationWithBody
|
||||
val locId =
|
||||
tw.getLocation(functionSyntax ?: TODO())
|
||||
/*
|
||||
OLD: KE1
|
||||
overriddenAttributes?.sourceLoc
|
||||
?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val shortName =
|
||||
when {
|
||||
adjustedReturnType.isAnonymous -> ""
|
||||
typeSubstitution != null ->
|
||||
useType(substReturnType).javaResult.shortName
|
||||
else ->
|
||||
adjustedReturnType.classFqName?.shortName()?.asString()
|
||||
?: f.name.asString()
|
||||
}
|
||||
extractConstructor(
|
||||
id.cast(),
|
||||
shortName,
|
||||
paramsSignature,
|
||||
parentId,
|
||||
sourceDeclaration.cast()
|
||||
)
|
||||
} else {
|
||||
val shortNames = getFunctionShortName(f)
|
||||
*/
|
||||
val methodId = id.cast<DbMethod>()
|
||||
extractMethod(
|
||||
methodId,
|
||||
/*
|
||||
OLD: KE1
|
||||
locId,
|
||||
*/
|
||||
f.name!!.asString(), // TODO: Remove !!, // OLD: KE1: shortNames.nameInDB,
|
||||
f.returnType, // OLD: KE1: substReturnType,
|
||||
paramsSignature,
|
||||
parentId,
|
||||
/*
|
||||
OLD: KE1
|
||||
sourceDeclaration.cast(),
|
||||
if (extractOrigin) f.origin else null,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
*/
|
||||
)
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
if (shortNames.nameInDB != shortNames.kotlinName) {
|
||||
tw.writeKtFunctionOriginalNames(methodId, shortNames.kotlinName)
|
||||
}
|
||||
|
||||
if (f.hasInterfaceParent() && f.body != null) {
|
||||
addModifiers(
|
||||
methodId,
|
||||
"default"
|
||||
) // The actual output class file may or may not have this modifier,
|
||||
// depending on the -Xjvm-default setting.
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
tw.writeHasLocation(id, locId)
|
||||
val body = functionSyntax?.bodyExpression ?: functionSyntax?.bodyBlockExpression
|
||||
if (body != null /* TODO && extractBody */) {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (typeSubstitution != null)
|
||||
logger.errorElement(
|
||||
"Type substitution should only be used to extract a function prototype, not the body",
|
||||
f
|
||||
)
|
||||
*/
|
||||
extractBody(body, id)
|
||||
}
|
||||
|
||||
/*
|
||||
OLD: KE1
|
||||
extractVisibility(f, id, overriddenAttributes?.visibility ?: f.visibility)
|
||||
|
||||
if (f.isInline) {
|
||||
addModifiers(id, "inline")
|
||||
}
|
||||
if (f.shouldExtractAsStatic) {
|
||||
addModifiers(id, "static")
|
||||
}
|
||||
if (f is IrSimpleFunction && f.overriddenSymbols.isNotEmpty()) {
|
||||
addModifiers(id, "override")
|
||||
}
|
||||
if (f.isSuspend) {
|
||||
addModifiers(id, "suspend")
|
||||
}
|
||||
if (f.symbol !is IrConstructorSymbol) {
|
||||
when (overriddenAttributes?.modality ?: (f as? IrSimpleFunction)?.modality) {
|
||||
Modality.ABSTRACT -> addModifiers(id, "abstract")
|
||||
Modality.FINAL -> addModifiers(id, "final")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
linesOfCode?.linesOfCodeInDeclaration(f, id)
|
||||
|
||||
if (extractAnnotations) {
|
||||
val extraAnnotations =
|
||||
if (f.symbol is IrConstructorSymbol) listOf()
|
||||
else
|
||||
listOfNotNull(
|
||||
getNullabilityAnnotation(
|
||||
f.returnType,
|
||||
f.origin,
|
||||
f.annotations,
|
||||
getJavaCallable(f)?.annotations
|
||||
)
|
||||
)
|
||||
extractAnnotations(
|
||||
f,
|
||||
f.annotations + extraAnnotations,
|
||||
id,
|
||||
extractMethodAndParameterTypeAccesses
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
return id
|
||||
/*
|
||||
OLD: KE1
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Can this be inlined?
|
||||
private fun KotlinFileExtractor.extractMethod(
|
||||
id: Label<out DbMethod>,
|
||||
/*
|
||||
OLD: KE1
|
||||
locId: Label<out DbLocation>,
|
||||
*/
|
||||
shortName: String,
|
||||
returnType: KaType,
|
||||
paramsSignature: String,
|
||||
parentId: Label<out DbReftype>,
|
||||
/*
|
||||
OLD: KE1
|
||||
sourceDeclaration: Label<out DbMethod>,
|
||||
origin: IrDeclarationOrigin?,
|
||||
extractTypeAccess: Boolean
|
||||
*/
|
||||
) {
|
||||
val returnTypeResults = useType(returnType, TypeContext.RETURN)
|
||||
tw.writeMethods(
|
||||
id,
|
||||
shortName,
|
||||
"$shortName$paramsSignature",
|
||||
returnTypeResults.javaResult.id,
|
||||
parentId,
|
||||
id, // OLD: KE1: sourceDeclaration
|
||||
)
|
||||
/*
|
||||
OLD: KE1
|
||||
tw.writeMethodsKotlinType(id, returnTypeResults.kotlinResult.id)
|
||||
when (origin) {
|
||||
IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.GENERATED_DATA_CLASS_MEMBER.kind
|
||||
)
|
||||
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.DEFAULT_PROPERTY_ACCESSOR.kind
|
||||
)
|
||||
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER ->
|
||||
tw.writeCompiler_generated(
|
||||
id,
|
||||
CompilerGeneratedKinds.ENUM_CLASS_SPECIAL_MEMBER.kind
|
||||
)
|
||||
}
|
||||
if (extractTypeAccess) {
|
||||
extractTypeAccessRecursive(returnType, locId, id, -1)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun <T : DbCallable> KotlinUsesExtractor.useFunction(
|
||||
f: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
noReplace: Boolean = false
|
||||
*/
|
||||
): Label<out T> {
|
||||
/*
|
||||
OLD: KE1
|
||||
if (f.isLocalFunction()) {
|
||||
val ids = getLocallyVisibleFunctionLabels(f)
|
||||
return ids.function.cast<T>()
|
||||
}
|
||||
*/
|
||||
val javaFun = f // TODO: kotlinFunctionToJavaEquivalent(f, noReplace)
|
||||
return useFunction(f, javaFun, parentId /* TODO , classTypeArgsIncludingOuterClasses */)
|
||||
}
|
||||
|
||||
private fun <T : DbCallable> KotlinUsesExtractor.useFunction(
|
||||
f: KaFunctionSymbol,
|
||||
javaFun: KaFunctionSymbol,
|
||||
parentId: Label<out DbElement>,
|
||||
/*
|
||||
OLD: KE1
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
|
||||
*/
|
||||
): Label<out T> {
|
||||
println("=== useFunction")
|
||||
println(f)
|
||||
println(f.returnType)
|
||||
val label = getFunctionLabel(javaFun, parentId /* TODO , classTypeArgsIncludingOuterClasses */)
|
||||
val id: Label<T> =
|
||||
tw.getLabelFor(label) {
|
||||
/*
|
||||
OLD: KE1
|
||||
extractPrivateSpecialisedDeclaration(f, classTypeArgsIncludingOuterClasses)
|
||||
*/
|
||||
}
|
||||
/*
|
||||
OLD: KE1
|
||||
if (isExternalDeclaration(javaFun)) {
|
||||
extractFunctionLaterIfExternalFileMember(javaFun)
|
||||
extractExternalEnclosingClassLater(javaFun)
|
||||
}
|
||||
*/
|
||||
return id
|
||||
}
|
||||
Reference in New Issue
Block a user