mirror of
https://github.com/github/codeql.git
synced 2025-12-17 09:13:20 +01:00
Kotlin: Refactoring
This commit is contained in:
@@ -8,10 +8,11 @@ import kotlin.system.exitProcess
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.path
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.path
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.packageFqName
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -23,7 +24,7 @@ class KotlinExtractorExtension(private val tests: List<String>) : IrGenerationEx
|
||||
trapDir.mkdirs()
|
||||
val srcDir = File(System.getenv("CODEQL_EXTRACTOR_JAVA_SOURCE_ARCHIVE_DIR").takeUnless { it.isNullOrEmpty() } ?: "kotlin-extractor/src")
|
||||
srcDir.mkdirs()
|
||||
moduleFragment.accept(KotlinExtractorVisitor(trapDir, srcDir), RootTrapWriter())
|
||||
moduleFragment.files.map { extractFile(trapDir, srcDir, it) }
|
||||
// We don't want the compiler to continue and generate class
|
||||
// files etc, so we just exit when we are finished extracting.
|
||||
exitProcess(0)
|
||||
@@ -34,41 +35,16 @@ fun extractorBug(msg: String) {
|
||||
println(msg)
|
||||
}
|
||||
|
||||
interface TrapWriter {
|
||||
fun writeTrap(trap: String)
|
||||
fun getLocation(startOffset: Int, endOffset: Int): Label<DbLocation_default>
|
||||
fun <T> getIdFor(label: String): Label<T>
|
||||
fun <T> getFreshId(): Label<T>
|
||||
}
|
||||
|
||||
class RootTrapWriter: TrapWriter {
|
||||
override fun writeTrap(trap: String) {
|
||||
extractorBug("Tried to write TRAP outside a file: $trap")
|
||||
}
|
||||
override fun getLocation(startOffset: Int, endOffset: Int): Label<DbLocation_default> {
|
||||
extractorBug("Asked for location, but not in a file")
|
||||
return Label(0)
|
||||
}
|
||||
override fun <T> getIdFor(label: String): Label<T> {
|
||||
extractorBug("Asked for ID for '$label' outside a file")
|
||||
return Label(0)
|
||||
}
|
||||
override fun <T> getFreshId(): Label<T> {
|
||||
extractorBug("Asked for fresh ID outside a file")
|
||||
return Label(0)
|
||||
}
|
||||
}
|
||||
|
||||
class FileTrapWriter(
|
||||
class TrapWriter (
|
||||
val fileLabel: String,
|
||||
val file: BufferedWriter,
|
||||
val fileEntry: IrFileEntry
|
||||
): TrapWriter {
|
||||
) {
|
||||
var nextId: Int = 100
|
||||
override fun writeTrap(trap: String) {
|
||||
fun writeTrap(trap: String) {
|
||||
file.write(trap)
|
||||
}
|
||||
override fun getLocation(startOffset: Int, endOffset: Int): Label<DbLocation_default> {
|
||||
fun getLocation(startOffset: Int, endOffset: Int): Label<DbLocation_default> {
|
||||
val startLine = fileEntry.getLineNumber(startOffset) + 1
|
||||
val startColumn = fileEntry.getColumnNumber(startOffset) + 1
|
||||
val endLine = fileEntry.getLineNumber(endOffset) + 1
|
||||
@@ -80,64 +56,77 @@ class FileTrapWriter(
|
||||
return id
|
||||
}
|
||||
val labelMapping: MutableMap<String, Label<*>> = mutableMapOf<String, Label<*>>()
|
||||
override fun <T> getIdFor(label: String): Label<T> {
|
||||
fun <T> getIdFor(label: String, initialise: (Label<T>) -> Unit = {}): Label<T> {
|
||||
val maybeId = labelMapping.get(label)
|
||||
if(maybeId == null) {
|
||||
val id: Label<T> = getFreshId()
|
||||
labelMapping.put(label, id)
|
||||
writeTrap("$id = $label\n")
|
||||
initialise(id)
|
||||
return id
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return maybeId as Label<T>
|
||||
}
|
||||
}
|
||||
override fun <T> getFreshId(): Label<T> {
|
||||
fun <T> getFreshId(): Label<T> {
|
||||
return Label(nextId++)
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinExtractorVisitor(val trapDir: File, val srcDir: File) : IrElementVisitor<Unit, TrapWriter> {
|
||||
override fun visitElement(element: IrElement, data: TrapWriter) {
|
||||
extractorBug("Unrecognised IrElement: " + element.javaClass)
|
||||
if(data is RootTrapWriter) {
|
||||
extractorBug("... and outside any file!")
|
||||
}
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
override fun visitClass(declaration: IrClass, data: TrapWriter) {
|
||||
val id: Label<DbClass> = data.getFreshId()
|
||||
val pkgId: Label<DbPackage> = data.getFreshId()
|
||||
val locId = data.getLocation(declaration.startOffset, declaration.endOffset)
|
||||
val pkg = declaration.packageFqName?.asString() ?: ""
|
||||
val cls = declaration.name.asString()
|
||||
data.writeTrap("$pkgId = @\"pkg;$pkg\"\n")
|
||||
data.writePackages(pkgId, pkg)
|
||||
data.writeTrap("$id = @\"class;$pkg.$cls\"\n")
|
||||
data.writeClasses(id, cls, pkgId, id)
|
||||
data.writeHasLocation(id, locId)
|
||||
declaration.acceptChildren(this, data)
|
||||
}
|
||||
override fun visitFile(declaration: IrFile, data: TrapWriter) {
|
||||
val filePath = declaration.path
|
||||
val file = File(filePath)
|
||||
val fileLabel = "@\"$filePath;sourcefile\""
|
||||
val basename = file.nameWithoutExtension
|
||||
val extension = file.extension
|
||||
val dest = Paths.get("$srcDir/${declaration.path}")
|
||||
val destDir = dest.getParent()
|
||||
Files.createDirectories(destDir)
|
||||
Files.copy(Paths.get(declaration.path), dest)
|
||||
fun extractFile(trapDir: File, srcDir: File, declaration: IrFile) {
|
||||
val filePath = declaration.path
|
||||
val file = File(filePath)
|
||||
val fileLabel = "@\"$filePath;sourcefile\""
|
||||
val basename = file.nameWithoutExtension
|
||||
val extension = file.extension
|
||||
val dest = Paths.get("$srcDir/${declaration.path}")
|
||||
val destDir = dest.getParent()
|
||||
Files.createDirectories(destDir)
|
||||
Files.copy(Paths.get(declaration.path), dest)
|
||||
|
||||
val trapFile = File("$trapDir/$filePath.trap")
|
||||
val trapFileDir = trapFile.getParentFile()
|
||||
trapFileDir.mkdirs()
|
||||
trapFile.bufferedWriter().use { trapFileBW ->
|
||||
val tw = FileTrapWriter(fileLabel, trapFileBW, declaration.fileEntry)
|
||||
val id: Label<DbFile> = tw.getIdFor(fileLabel)
|
||||
tw.writeTrap("$id = $fileLabel\n")
|
||||
tw.writeFiles(id, filePath, basename, extension, 0)
|
||||
declaration.acceptChildren(this, tw)
|
||||
}
|
||||
val trapFile = File("$trapDir/$filePath.trap")
|
||||
val trapFileDir = trapFile.getParentFile()
|
||||
trapFileDir.mkdirs()
|
||||
trapFile.bufferedWriter().use { trapFileBW ->
|
||||
val tw = TrapWriter(fileLabel, trapFileBW, declaration.fileEntry)
|
||||
val id: Label<DbFile> = tw.getIdFor(fileLabel)
|
||||
tw.writeFiles(id, filePath, basename, extension, 0)
|
||||
val fileExtractor = KotlinFileExtractor(tw)
|
||||
val pkg = declaration.fqName.asString()
|
||||
val pkgId = fileExtractor.extractPackage(pkg)
|
||||
tw.writeCupackage(id, pkgId)
|
||||
declaration.declarations.map { fileExtractor.extractDeclaration(it) }
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinFileExtractor(val tw: TrapWriter) {
|
||||
fun extractPackage(pkg: String): Label<DbPackage> {
|
||||
val pkgLabel = "@\"package;$pkg\""
|
||||
val id: Label<DbPackage> = tw.getIdFor(pkgLabel, {
|
||||
tw.writePackages(it, pkg)
|
||||
})
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractDeclaration(declaration: IrDeclaration) {
|
||||
when (declaration) {
|
||||
is IrClass -> extractClass(declaration)
|
||||
else -> extractorBug("Unrecognised IrDeclaration: " + declaration.javaClass)
|
||||
}
|
||||
}
|
||||
|
||||
fun extractClass(declaration: IrClass) {
|
||||
val id: Label<DbClass> = tw.getFreshId()
|
||||
val locId = tw.getLocation(declaration.startOffset, declaration.endOffset)
|
||||
val pkg = declaration.packageFqName?.asString() ?: ""
|
||||
val cls = declaration.name.asString()
|
||||
val qualClassName = if (pkg.isEmpty()) cls else "$pkg.$cls"
|
||||
val pkgId = extractPackage(pkg)
|
||||
tw.writeTrap("$id = @\"class;$qualClassName\"\n")
|
||||
tw.writeClasses(id, cls, pkgId, id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
declaration.declarations.map { extractDeclaration(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user