Skip to content

Commit eb27428

Browse files
committed
Kotlin: Handle IrExternalPackageFragment when dealing with external decls
1 parent 72af8ac commit eb27428

File tree

5 files changed

+69
-16
lines changed

5 files changed

+69
-16
lines changed

java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,10 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
8888
nextBatch.forEach { workPair ->
8989
val (irDecl, possiblyLongSignature) = workPair
9090
extractElement(irDecl, possiblyLongSignature, false) { trapFileBW, signature, manager ->
91-
val containingClass = getContainingClassOrSelf(irDecl)
92-
if (containingClass == null) {
93-
logger.errorElement("Unable to get containing class", irDecl)
91+
val binaryPath = getIrDeclarationBinaryPath(irDecl)
92+
if (binaryPath == null) {
93+
logger.errorElement("Unable to get binary path", irDecl)
9494
} else {
95-
val binaryPath = getIrClassBinaryPath(containingClass)
96-
9795
// We want our comments to be the first thing in the file,
9896
// so start off with a PlainTrapWriter
9997
val tw = PlainTrapWriter(logger.loggerBase, TrapLabelManager(), trapFileBW, diagnosticTrapWriter)

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,10 @@ open class KotlinFileExtractor(
409409

410410
private fun getLocation(decl: IrDeclaration, typeArgs: List<IrTypeArgument>?): Label<DbLocation> {
411411
return if (typeArgs != null && typeArgs.isNotEmpty()) {
412-
val c = getContainingClassOrSelf(decl)
413-
if (c == null) {
412+
val binaryPath = getIrDeclarationBinaryPath(decl)
413+
if (binaryPath == null) {
414414
tw.getLocation(decl)
415415
} else {
416-
val binaryPath = getIrClassBinaryPath(c)
417416
val newTrapWriter = tw.makeFileTrapWriter(binaryPath, true)
418417
newTrapWriter.getWholeFileLocation()
419418
}

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ open class KotlinUsesExtractor(
274274
is IrClass -> extractExternalClassLater(parent)
275275
is IrFunction -> extractExternalEnclosingClassLater(parent)
276276
is IrFile -> logger.error("extractExternalEnclosingClassLater but no enclosing class.")
277-
else -> logger.error("Unrecognised extractExternalEnclosingClassLater: " + d.javaClass)
277+
is IrExternalPackageFragment -> {
278+
// The parent is a (multi)file class. We don't need
279+
// extract it separately.
280+
}
281+
else -> logger.error("Unrecognised extractExternalEnclosingClassLater ${parent.javaClass} for ${d.javaClass}")
278282
}
279283
}
280284

@@ -317,7 +321,17 @@ open class KotlinUsesExtractor(
317321

318322
private fun extractFunctionLaterIfExternalFileMember(f: IrFunction) {
319323
if (isExternalFileClassMember(f)) {
320-
extractExternalClassLater(f.parentAsClass)
324+
val p = f.parent
325+
when (p) {
326+
is IrClass -> extractExternalClassLater(p)
327+
is IrExternalPackageFragment -> {
328+
// The parent is a (multi)file class. We don't need
329+
// extract it separately.
330+
}
331+
else -> {
332+
logger.warn("Unexpected parent type ${p.javaClass} for external file class member")
333+
}
334+
}
321335
(f as? IrSimpleFunction)?.correspondingPropertySymbol?.let {
322336
extractPropertyLaterIfExternalFileMember(it.owner)
323337
// No need to extract the function specifically, as the property's

java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.IrElement
1313
import org.jetbrains.kotlin.ir.declarations.*
1414
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
1515
import org.jetbrains.kotlin.ir.util.parentClassOrNull
16+
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
1617
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
1718

1819
// Adapted from Kotlin's interpreter/Utils.kt function 'internalName'
@@ -108,14 +109,40 @@ private fun getRawIrClassBinaryPath(irClass: IrClass) =
108109
fun getIrClassBinaryPath(irClass: IrClass): String {
109110
return getRawIrClassBinaryPath(irClass)
110111
// Otherwise, make up a fake location:
111-
?: "/!unknown-binary-location/${getIrElementBinaryName(irClass).replace(".", "/")}.class"
112+
?: getUnknownBinaryLocation(getIrElementBinaryName(irClass))
112113
}
113114

114-
fun getContainingClassOrSelf(decl: IrDeclaration): IrClass? {
115-
return when(decl) {
116-
is IrClass -> decl
117-
else -> decl.parentClassOrNull
115+
fun getIrDeclarationBinaryPath(d: IrDeclaration): String? {
116+
if (d is IrClass) {
117+
return getIrClassBinaryPath(d)
118118
}
119+
val parentClass = d.parentClassOrNull
120+
if (parentClass != null) {
121+
return getIrClassBinaryPath(parentClass)
122+
}
123+
if (d.parent is IrExternalPackageFragment) {
124+
// This is in a file class.
125+
// Get the name in a similar way to the compiler's ExternalPackageParentPatcherLowering
126+
// visitMemberAccess/generateOrGetFacadeClass.
127+
if (d is IrMemberWithContainerSource) {
128+
val containerSource = d.containerSource
129+
if (containerSource is FacadeClassSource) {
130+
val facadeClassName = containerSource.facadeClassName
131+
if (facadeClassName != null) {
132+
// This is a multifile-class
133+
return getUnknownBinaryLocation(facadeClassName.fqNameForTopLevelClassMaybeWithDollars.asString())
134+
} else {
135+
// This is a file-class
136+
return getUnknownBinaryLocation(containerSource.className.fqNameForTopLevelClassMaybeWithDollars.asString())
137+
}
138+
}
139+
}
140+
}
141+
return null
142+
}
143+
144+
fun getUnknownBinaryLocation(s: String): String {
145+
return "/!unknown-binary-location/${s.replace(".", "/")}.class"
119146
}
120147

121148
fun getJavaEquivalentClassId(c: IrClass) =

java/kotlin-extractor/src/main/kotlin/utils/ExternalDecls.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.github.codeql.utils
33
import org.jetbrains.kotlin.ir.declarations.IrClass
44
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
55
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
6+
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
67
import org.jetbrains.kotlin.ir.util.isFileClass
78
import org.jetbrains.kotlin.ir.util.parentClassOrNull
89

@@ -28,6 +29,10 @@ fun isExternalDeclaration(d: IrDeclaration): Boolean {
2829
CONST Int type=kotlin.Int value=-2147483648
2930
*/
3031
val p = d.parent
32+
if (p is IrExternalPackageFragment) {
33+
// This is an external declaration in a (multi)file class
34+
return true
35+
}
3136
if (p is IrDeclaration) {
3237
return isExternalDeclaration(p)
3338
}
@@ -37,5 +42,15 @@ fun isExternalDeclaration(d: IrDeclaration): Boolean {
3742
/**
3843
* Returns true if `d` is not itself a class, but is a member of an external file class.
3944
*/
40-
fun isExternalFileClassMember(d: IrDeclaration) = d !is IrClass && (d.parentClassOrNull?.let { it.isFileClass } ?: false)
45+
fun isExternalFileClassMember(d: IrDeclaration): Boolean {
46+
if (d is IrClass) { return false }
47+
val p = d.parent
48+
when (p) {
49+
is IrClass -> return p.isFileClass
50+
is IrExternalPackageFragment ->
51+
// This is an external declaration in a (multi)file class
52+
return true
53+
}
54+
return false
55+
}
4156

0 commit comments

Comments
 (0)