mirror of
https://github.com/github/codeql.git
synced 2025-12-20 02:44:30 +01:00
Revert moving extraction to SourceFileExtractor
This commit is contained in:
@@ -123,10 +123,39 @@ open class KotlinFileExtractor(
|
||||
return id
|
||||
}
|
||||
|
||||
private val anonymousTypeMapping: MutableMap<IrClass, TypeResults> = mutableMapOf()
|
||||
|
||||
fun useAnonymousClass(c: IrClass): TypeResults {
|
||||
var res = anonymousTypeMapping[c]
|
||||
if (res == null) {
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
res = TypeResults(javaResult, kotlinResult)
|
||||
anonymousTypeMapping[c] = res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
private fun extractAnonymousClassStmt(c: IrClass, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val id = extractClassSource(c) as Label<out DbClass>
|
||||
extractAnonymousClassStmt(id, c, callable, parent, idx)
|
||||
}
|
||||
|
||||
private fun extractAnonymousClassStmt(id: Label<out DbClass>, locElement: IrElement, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
val stmtId = tw.getFreshIdLabel<DbAnonymousclassdeclstmt>()
|
||||
tw.writeStmts_anonymousclassdeclstmt(stmtId, parent, idx, callable)
|
||||
tw.writeKtAnonymousClassDeclarationStmts(stmtId, id)
|
||||
val locId = tw.getLocation(locElement)
|
||||
tw.writeHasLocation(stmtId, locId)
|
||||
}
|
||||
|
||||
fun extractClassSource(c: IrClass): Label<out DbClassorinterface> {
|
||||
val id = if (c.isAnonymousObject) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
withSourceFile(c.fileOrNull!!).useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
} else {
|
||||
useClassSource(c)
|
||||
}
|
||||
@@ -156,7 +185,7 @@ open class KotlinFileExtractor(
|
||||
val parentId =
|
||||
if (parent.isAnonymousObject) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
withSourceFile(c.fileOrNull!!).useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
} else {
|
||||
useClassInstance(parent, listOf()).typeResult.id
|
||||
}
|
||||
@@ -323,7 +352,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
val id =
|
||||
if (f.isLocalFunction())
|
||||
withSourceFile(f.fileOrNull!!).getLocalFunctionLabels(f).function
|
||||
getLocalFunctionLabels(f).function
|
||||
else
|
||||
useFunction<DbCallable>(f)
|
||||
|
||||
@@ -507,16 +536,15 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
is IrClass -> {
|
||||
if (s.isAnonymousObject) {
|
||||
withSourceFile(s.fileOrNull!!).extractAnonymousClassStmt(s, callable, parent, idx)
|
||||
extractAnonymousClassStmt(s, callable, parent, idx)
|
||||
} else {
|
||||
logger.warnElement(Severity.ErrorSevere, "Found non anonymous IrClass as IrStatement: " + s.javaClass, s)
|
||||
}
|
||||
}
|
||||
is IrFunction -> {
|
||||
if (s.isLocalFunction()) {
|
||||
val extractor = withSourceFile(s.fileOrNull!!)
|
||||
val classId = extractor.extractGeneratedClass(s, listOf(pluginContext.irBuiltIns.anyType))
|
||||
extractor.extractAnonymousClassStmt(classId, s, callable, parent, idx)
|
||||
val classId = extractGeneratedClass(s, listOf(pluginContext.irBuiltIns.anyType))
|
||||
extractAnonymousClassStmt(classId, s, callable, parent, idx)
|
||||
} else {
|
||||
logger.warnElement(Severity.ErrorSevere, "Expected to find local function", s)
|
||||
}
|
||||
@@ -684,7 +712,7 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
|
||||
if (callTarget.isLocalFunction()) {
|
||||
val ids = withSourceFile(callTarget.fileOrNull!!).getLocalFunctionLabels(callTarget)
|
||||
val ids = getLocalFunctionLabels(callTarget)
|
||||
|
||||
val methodId = ids.function
|
||||
tw.writeCallableBinding(id, methodId)
|
||||
@@ -1063,7 +1091,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
val c = (e.type as IrSimpleType).classifier.owner as IrClass
|
||||
|
||||
type = withSourceFile(c.fileOrNull!!).useAnonymousClass(c)
|
||||
type = useAnonymousClass(c)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeIsAnonymClass(type.javaResult.id as Label<DbClass>, id)
|
||||
@@ -1737,4 +1765,71 @@ open class KotlinFileExtractor(
|
||||
|
||||
private val IrType.isAnonymous: Boolean
|
||||
get() = ((this as? IrSimpleType)?.classifier?.owner as? IrClass)?.isAnonymousObject ?: false
|
||||
|
||||
|
||||
private val generatedLocalFunctionTypeMapping: MutableMap<IrFunction, LocalFunctionLabels> = mutableMapOf()
|
||||
|
||||
data class LocalFunctionLabels(val type: TypeResults, val constructor: Label<DbConstructor>, val function: Label<DbMethod>)
|
||||
|
||||
fun getLocalFunctionLabels(f: IrFunction): LocalFunctionLabels {
|
||||
if (!f.isLocalFunction()){
|
||||
logger.warnElement(Severity.ErrorSevere, "Extracting a non-local function as a local one", f)
|
||||
}
|
||||
|
||||
var res = generatedLocalFunctionTypeMapping[f]
|
||||
if (res == null) {
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
res = LocalFunctionLabels(
|
||||
TypeResults(javaResult, kotlinResult),
|
||||
tw.getFreshIdLabel(),
|
||||
tw.getFreshIdLabel())
|
||||
generatedLocalFunctionTypeMapping[f] = res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fun extractGeneratedClass(localFunction: IrFunction, superTypes: List<IrType>) : Label<out DbClass> {
|
||||
val ids = getLocalFunctionLabels(localFunction)
|
||||
|
||||
// Write class
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val id = ids.type.javaResult.id as Label<out DbClass>
|
||||
val pkgId = extractPackage("")
|
||||
tw.writeClasses(id, "", pkgId, id)
|
||||
val locId = tw.getLocation(localFunction)
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
// Extract local function as a member
|
||||
extractFunction(localFunction, id)
|
||||
|
||||
// Extract constructor
|
||||
tw.writeConstrs(ids.constructor, "", "", ids.type.javaResult.id, ids.type.kotlinResult.id, id, ids.constructor)
|
||||
tw.writeHasLocation(ids.constructor, locId)
|
||||
|
||||
// Constructor body
|
||||
val constructorBlockId = tw.getFreshIdLabel<DbBlock>()
|
||||
tw.writeStmts_block(constructorBlockId, ids.constructor, 0, ids.constructor)
|
||||
tw.writeHasLocation(constructorBlockId, locId)
|
||||
|
||||
// Super call
|
||||
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
|
||||
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.function)
|
||||
|
||||
val baseConstructor = superTypes.first().classOrNull!!.owner.declarations.find { it is IrFunction && it.symbol is IrConstructorSymbol }
|
||||
val baseConstructorId = useFunction<DbConstructor>(baseConstructor as IrFunction)
|
||||
|
||||
tw.writeHasLocation(superCallId, locId)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeCallableBinding(superCallId as Label<DbCaller>, baseConstructorId)
|
||||
|
||||
// TODO: We might need to add an `<obinit>` function, and a call to it to match other classes
|
||||
|
||||
addModifiers(id, "public", "static", "final")
|
||||
extractClassSupertypes(superTypes, listOf(), id)
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,11 @@ package com.github.codeql
|
||||
|
||||
import com.github.codeql.comments.CommentExtractor
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.util.packageFqName
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
|
||||
@@ -27,32 +21,7 @@ class KotlinSourceFileExtractor(
|
||||
) :
|
||||
KotlinFileExtractor(logger, tw, null, externalClassExtractor, primitiveTypeMapping, pluginContext) {
|
||||
|
||||
init {
|
||||
if (!stateCache.containsKey(file)){
|
||||
stateCache[file] = SourceFileExtractionState()
|
||||
}
|
||||
}
|
||||
|
||||
data class SourceFileExtractionState(val anonymousTypeMapping: MutableMap<IrClass, TypeResults> = mutableMapOf(),
|
||||
val generatedLocalFunctionTypeMapping: MutableMap<IrFunction, LocalFunctionLabels> = mutableMapOf(),
|
||||
/**
|
||||
* It is not easy to assign keys to local variables, so they get
|
||||
* given `*` IDs. However, the same variable may be referred to
|
||||
* from distant places in the IR, so we need a way to find out
|
||||
* which label is used for a given local variable. This information
|
||||
* is stored in this mapping.
|
||||
*/
|
||||
val variableLabelMapping: MutableMap<IrVariable, Label<DbLocalvar>> = mutableMapOf())
|
||||
|
||||
companion object {
|
||||
private val stateCache: MutableMap<IrFile, SourceFileExtractionState> = mutableMapOf()
|
||||
}
|
||||
|
||||
private val fileExtractionState by lazy {
|
||||
stateCache[file]!!
|
||||
}
|
||||
|
||||
private val fileClass by lazy {
|
||||
val fileClass by lazy {
|
||||
extractFileClass(file)
|
||||
}
|
||||
|
||||
@@ -101,109 +70,4 @@ class KotlinSourceFileExtractor(
|
||||
return id
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the label used for a local variable, creating one
|
||||
* if none currently exists.
|
||||
*/
|
||||
fun <T> getVariableLabelFor(v: IrVariable): Label<DbLocalvar> {
|
||||
val maybeLabel = fileExtractionState.variableLabelMapping[v]
|
||||
if (maybeLabel == null) {
|
||||
val label = tw.getFreshIdLabel<DbLocalvar>()
|
||||
fileExtractionState.variableLabelMapping[v] = label
|
||||
return label
|
||||
} else {
|
||||
return maybeLabel
|
||||
}
|
||||
}
|
||||
|
||||
fun useAnonymousClass(c: IrClass): TypeResults {
|
||||
var res = fileExtractionState.anonymousTypeMapping[c]
|
||||
if (res == null) {
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
res = TypeResults(javaResult, kotlinResult)
|
||||
fileExtractionState.anonymousTypeMapping[c] = res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
data class LocalFunctionLabels(val type: TypeResults, val constructor: Label<DbConstructor>, val function: Label<DbMethod>)
|
||||
|
||||
fun getLocalFunctionLabels(f: IrFunction): LocalFunctionLabels {
|
||||
if (!f.isLocalFunction()){
|
||||
logger.warnElement(Severity.ErrorSevere, "Extracting a non-local function as a local one", f)
|
||||
}
|
||||
|
||||
var res = fileExtractionState.generatedLocalFunctionTypeMapping[f]
|
||||
if (res == null) {
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
res = LocalFunctionLabels(
|
||||
TypeResults(javaResult, kotlinResult),
|
||||
tw.getFreshIdLabel(),
|
||||
tw.getFreshIdLabel())
|
||||
fileExtractionState.generatedLocalFunctionTypeMapping[f] = res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fun extractGeneratedClass(localFunction: IrFunction, superTypes: List<IrType>) : Label<out DbClass> {
|
||||
val ids = getLocalFunctionLabels(localFunction)
|
||||
|
||||
// Write class
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val id = ids.type.javaResult.id as Label<out DbClass>
|
||||
val pkgId = extractPackage("")
|
||||
tw.writeClasses(id, "", pkgId, id)
|
||||
val locId = tw.getLocation(localFunction)
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
// Extract local function as a member
|
||||
extractFunction(localFunction, id)
|
||||
|
||||
// Extract constructor
|
||||
tw.writeConstrs(ids.constructor, "", "", ids.type.javaResult.id, ids.type.kotlinResult.id, id, ids.constructor)
|
||||
tw.writeHasLocation(ids.constructor, locId)
|
||||
|
||||
// Constructor body
|
||||
val constructorBlockId = tw.getFreshIdLabel<DbBlock>()
|
||||
tw.writeStmts_block(constructorBlockId, ids.constructor, 0, ids.constructor)
|
||||
tw.writeHasLocation(constructorBlockId, locId)
|
||||
|
||||
// Super call
|
||||
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
|
||||
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.function)
|
||||
|
||||
val baseConstructor = superTypes.first().classOrNull!!.owner.declarations.find { it is IrFunction && it.symbol is IrConstructorSymbol }
|
||||
val baseConstructorId = useFunction<DbConstructor>(baseConstructor as IrFunction)
|
||||
|
||||
tw.writeHasLocation(superCallId, locId)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeCallableBinding(superCallId as Label<DbCaller>, baseConstructorId)
|
||||
|
||||
// TODO: We might need to add an `<obinit>` function, and a call to it to match other classes
|
||||
|
||||
addModifiers(id, "public", "static", "final")
|
||||
extractClassSupertypes(superTypes, listOf(), id)
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractAnonymousClassStmt(c: IrClass, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val id = extractClassSource(c) as Label<out DbClass>
|
||||
extractAnonymousClassStmt(id, c, callable, parent, idx)
|
||||
}
|
||||
|
||||
fun extractAnonymousClassStmt(id: Label<out DbClass>, locElement: IrElement, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
val stmtId = tw.getFreshIdLabel<DbAnonymousclassdeclstmt>()
|
||||
tw.writeStmts_anonymousclassdeclstmt(stmtId, parent, idx, callable)
|
||||
tw.writeKtAnonymousClassDeclarationStmts(stmtId, id)
|
||||
val locId = tw.getLocation(locElement)
|
||||
tw.writeHasLocation(stmtId, locId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ open class KotlinUsesExtractor(
|
||||
?.let { pluginContext.referenceClass(it.asSingleFqName()) }
|
||||
?.owner
|
||||
|
||||
fun withSourceFile(clsFile: IrFile): KotlinSourceFileExtractor {
|
||||
private fun withSourceFile(clsFile: IrFile): KotlinFileExtractor {
|
||||
val newTrapWriter = tw.makeSourceFileTrapWriter(clsFile, false)
|
||||
val newLogger = FileLogger(logger.logCounter, newTrapWriter)
|
||||
return KotlinSourceFileExtractor(newLogger, newTrapWriter, clsFile, externalClassExtractor, primitiveTypeMapping, pluginContext)
|
||||
@@ -75,7 +75,7 @@ open class KotlinUsesExtractor(
|
||||
/**
|
||||
* Gets a KotlinFileExtractor based on this one, except it attributes locations to the file that declares the given class.
|
||||
*/
|
||||
fun withSourceFileOfClass(cls: IrClass): KotlinFileExtractor {
|
||||
private fun withSourceFileOfClass(cls: IrClass): KotlinFileExtractor {
|
||||
val clsFile = cls.fileOrNull
|
||||
|
||||
if (isExternalDeclaration(cls) || clsFile == null) {
|
||||
@@ -720,8 +720,8 @@ class X {
|
||||
fun useTypeAlias(ta: IrTypeAlias): Label<out DbKt_type_alias> =
|
||||
tw.getLabelFor(getTypeAliasLabel(ta))
|
||||
|
||||
fun useVariable(v: IrVariable): Label<DbLocalvar> {
|
||||
return withSourceFile(v.fileOrNull!!).getVariableLabelFor<DbLocalvar>(v)
|
||||
fun useVariable(v: IrVariable): Label<out DbLocalvar> {
|
||||
return tw.getVariableLabelFor<DbLocalvar>(v)
|
||||
}
|
||||
|
||||
fun withQuestionMark(t: IrType, hasQuestionMark: Boolean) = if(hasQuestionMark) t.makeNullable() else t.makeNotNull()
|
||||
|
||||
@@ -39,9 +39,7 @@ class TrapLabelManager {
|
||||
* instances will have different additional state, but they must all
|
||||
* share the same `TrapLabelManager` and `BufferedWriter`.
|
||||
*/
|
||||
open class TrapWriter (
|
||||
protected val lm: TrapLabelManager,
|
||||
private val bw: BufferedWriter) {
|
||||
open class TrapWriter (protected val lm: TrapLabelManager, private val bw: BufferedWriter) {
|
||||
/**
|
||||
* Returns the label that is defined to be the given key, if such
|
||||
* a label exists, and `null` otherwise. Most users will want to use
|
||||
@@ -71,6 +69,30 @@ open class TrapWriter (
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It is not easy to assign keys to local variables, so they get
|
||||
* given `*` IDs. However, the same variable may be referred to
|
||||
* from distant places in the IR, so we need a way to find out
|
||||
* which label is used for a given local variable. This information
|
||||
* is stored in this mapping.
|
||||
*/
|
||||
private val variableLabelMapping: MutableMap<IrVariable, Label<out DbLocalvar>> = mutableMapOf<IrVariable, Label<out DbLocalvar>>()
|
||||
/**
|
||||
* This returns the label used for a local variable, creating one
|
||||
* if none currently exists.
|
||||
*/
|
||||
fun <T> getVariableLabelFor(v: IrVariable): Label<out DbLocalvar> {
|
||||
val maybeLabel = variableLabelMapping.get(v)
|
||||
if(maybeLabel == null) {
|
||||
val label = lm.getFreshLabel<DbLocalvar>()
|
||||
variableLabelMapping.put(v, label)
|
||||
writeTrap("$label = *\n")
|
||||
return label
|
||||
} else {
|
||||
return maybeLabel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a label for the location described by its arguments.
|
||||
* Typically users will not want to call this directly, but instead
|
||||
|
||||
Reference in New Issue
Block a user