mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
Extract generated <obinit> method, and calls to it
This commit is contained in:
@@ -43,7 +43,7 @@ class KotlinExtractorExtension(private val invocationTrapFile: String, private v
|
||||
moduleFragment.files.mapIndexed { index: Int, file: IrFile ->
|
||||
val fileTrapWriter = FileTrapWriter(lm, invocationTrapFileBW, file)
|
||||
fileTrapWriter.writeCompilation_compiling_files(compilation, index, fileTrapWriter.fileId)
|
||||
doFile(invocationTrapFile, fileTrapWriter, checkTrapIdentical, logCounter, trapDir, srcDir, file)
|
||||
doFile(invocationTrapFile, fileTrapWriter, checkTrapIdentical, logCounter, trapDir, srcDir, file, pluginContext)
|
||||
}
|
||||
logger.printLimitedWarningCounts()
|
||||
// We don't want the compiler to continue and generate class
|
||||
@@ -94,7 +94,14 @@ private fun equivalentTrap(f1: File, f2: File): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
fun doFile(invocationTrapFile: String, fileTrapWriter: FileTrapWriter, checkTrapIdentical: Boolean, logCounter: LogCounter, trapDir: File, srcDir: File, file: IrFile) {
|
||||
fun doFile(invocationTrapFile: String,
|
||||
fileTrapWriter: FileTrapWriter,
|
||||
checkTrapIdentical: Boolean,
|
||||
logCounter: LogCounter,
|
||||
trapDir: File,
|
||||
srcDir: File,
|
||||
file: IrFile,
|
||||
pluginContext: IrPluginContext) {
|
||||
val filePath = file.path
|
||||
val logger = FileLogger(logCounter, fileTrapWriter)
|
||||
logger.info("Extracting file $filePath")
|
||||
@@ -116,7 +123,7 @@ fun doFile(invocationTrapFile: String, fileTrapWriter: FileTrapWriter, checkTrap
|
||||
trapTmpFile.bufferedWriter().use { trapFileBW ->
|
||||
trapFileBW.write("// Generated by invocation ${invocationTrapFile.replace("\n", "\n// ")}\n")
|
||||
val tw = FileTrapWriter(TrapLabelManager(), trapFileBW, file)
|
||||
val fileExtractor = KotlinFileExtractor(logger, tw, file)
|
||||
val fileExtractor = KotlinFileExtractor(logger, tw, file, pluginContext)
|
||||
fileExtractor.extractFileContents(tw.fileId)
|
||||
}
|
||||
if (checkTrapIdentical && trapFile.exists()) {
|
||||
@@ -151,7 +158,7 @@ fun <T> fakeLabel(): Label<T> {
|
||||
return IntLabel(0)
|
||||
}
|
||||
|
||||
class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val file: IrFile) {
|
||||
class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val file: IrFile, val pluginContext: IrPluginContext) {
|
||||
val fileClass by lazy {
|
||||
extractFileClass(file)
|
||||
}
|
||||
@@ -213,11 +220,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
is IrClass -> extractClass(declaration)
|
||||
is IrFunction -> extractFunction(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
|
||||
is IrAnonymousInitializer -> {
|
||||
// todo: how do we want to represent this?
|
||||
// there could be multiple 'init' blocks inside a declaration.
|
||||
// We could add a generated 'init' method, with all the statements inside the blocks.
|
||||
// In Kotlin/JVM, the statements inside 'init' blocks get copied to the default constructor, or if there's no default then to all of them.
|
||||
logger.warnElement(Severity.ErrorSevere, "Todo: handle IrAnonymousInitializer", declaration)
|
||||
// Leaving this intentionally empty. init blocks are extracted during class extraction.
|
||||
}
|
||||
is IrProperty -> extractProperty(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
|
||||
else -> logger.warnElement(Severity.ErrorSevere, "Unrecognised IrDeclaration: " + declaration.javaClass, declaration)
|
||||
@@ -363,6 +366,9 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
}
|
||||
}
|
||||
c.declarations.map { extractDeclaration(it, Optional.of(id)) }
|
||||
|
||||
extractObjectInitializerFunction(c, id)
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
@@ -399,10 +405,14 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
}
|
||||
|
||||
private fun getFunctionLabel(f: IrFunction) : String {
|
||||
val paramTypeIds = f.valueParameters.joinToString() { "{${useType(erase(it.type)).toString()}}" }
|
||||
val returnTypeId = useType(erase(f.returnType))
|
||||
val parentId = useDeclarationParent(f.parent)
|
||||
val label = "@\"callable;{$parentId}.${f.name.asString()}($paramTypeIds){$returnTypeId}\""
|
||||
return getFunctionLabel(f.parent, f.name.asString(), f.valueParameters, f.returnType)
|
||||
}
|
||||
|
||||
private fun getFunctionLabel(parent: IrDeclarationParent, name: String, parameters: List<IrValueParameter>, returnType: IrType) : String {
|
||||
val paramTypeIds = parameters.joinToString() { "{${useType(erase(it.type)).toString()}}" }
|
||||
val returnTypeId = useType(erase(returnType))
|
||||
val parentId = useDeclarationParent(parent)
|
||||
val label = "@\"callable;{$parentId}.$name($paramTypeIds){$returnTypeId}\""
|
||||
return label
|
||||
}
|
||||
|
||||
@@ -459,6 +469,19 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
tw.writeParamName(id, vp.name.asString())
|
||||
}
|
||||
|
||||
private fun extractObjectInitializerFunction(c: IrClass, parentid: Label<out DbReftype>) {
|
||||
var methodLabel = getFunctionLabel(c, "<obinit>", listOf(), pluginContext.irBuiltIns.unitType)
|
||||
val methodId = tw.getLabelFor<DbMethod>(methodLabel)
|
||||
val signature = "TODO"
|
||||
val returnTypeId = useType(pluginContext.irBuiltIns.unitType)
|
||||
tw.writeMethods(methodId, "<obinit>", signature, returnTypeId, parentid, methodId)
|
||||
|
||||
val locId = tw.getLocation(c)
|
||||
tw.writeHasLocation(methodId, locId)
|
||||
|
||||
// todo add body with non-static field initializers, and init blocks
|
||||
}
|
||||
|
||||
fun extractFunction(f: IrFunction, parentid: Label<out DbReftype>) {
|
||||
val id = useFunction(f)
|
||||
val locId = tw.getLocation(f)
|
||||
@@ -702,11 +725,19 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
val callableLabel = useFunction(irCallable)
|
||||
when(e) {
|
||||
is IrInstanceInitializerCall -> {
|
||||
// todo: how do we want to handle this?
|
||||
// In Kotlin/JVM, this seems like a no-op.
|
||||
if (e.classSymbol.owner.declarations.any { it is IrAnonymousInitializer }) {
|
||||
// we could add a call to a generated 'init' function.
|
||||
if (irCallable is IrConstructor && irCallable.isPrimary) {
|
||||
// Todo add parameter to field assignments
|
||||
}
|
||||
|
||||
// Add call to <obinit>:
|
||||
val id = tw.getFreshIdLabel<DbMethodaccess>()
|
||||
val typeId = useType(e.type)
|
||||
val locId = tw.getLocation(e)
|
||||
var methodLabel = getFunctionLabel(irCallable.parent, "<obinit>", listOf(), e.type)
|
||||
val methodId = tw.getLabelFor<DbMethod>(methodLabel)
|
||||
tw.writeExprs_methodaccess(id, typeId, parent, idx)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableBinding(id, methodId)
|
||||
}
|
||||
is IrDelegatingConstructorCall -> {
|
||||
val delegatingClass = e.symbol.owner.parent as IrClass
|
||||
|
||||
Reference in New Issue
Block a user