@@ -8,10 +8,11 @@ import kotlin.system.exitProcess
88import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
99import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
1010import org.jetbrains.kotlin.ir.IrElement
11+ import org.jetbrains.kotlin.ir.declarations.path
1112import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
1213import org.jetbrains.kotlin.ir.declarations.IrClass
14+ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
1315import org.jetbrains.kotlin.ir.declarations.IrFile
14- import org.jetbrains.kotlin.ir.declarations.path
1516import org.jetbrains.kotlin.ir.util.dump
1617import org.jetbrains.kotlin.ir.util.packageFqName
1718import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -23,7 +24,7 @@ class KotlinExtractorExtension(private val tests: List<String>) : IrGenerationEx
2324 trapDir.mkdirs()
2425 val srcDir = File (System .getenv(" CODEQL_EXTRACTOR_JAVA_SOURCE_ARCHIVE_DIR" ).takeUnless { it.isNullOrEmpty() } ? : " kotlin-extractor/src" )
2526 srcDir.mkdirs()
26- moduleFragment.accept( KotlinExtractorVisitor ( trapDir, srcDir), RootTrapWriter ())
27+ moduleFragment.files.map { extractFile( trapDir, srcDir, it) }
2728 // We don't want the compiler to continue and generate class
2829 // files etc, so we just exit when we are finished extracting.
2930 exitProcess(0 )
@@ -34,41 +35,16 @@ fun extractorBug(msg: String) {
3435 println (msg)
3536}
3637
37- interface TrapWriter {
38- fun writeTrap (trap : String )
39- fun getLocation (startOffset : Int , endOffset : Int ): Label <DbLocation_default >
40- fun <T > getIdFor (label : String ): Label <T >
41- fun <T > getFreshId (): Label <T >
42- }
43-
44- class RootTrapWriter : TrapWriter {
45- override fun writeTrap (trap : String ) {
46- extractorBug(" Tried to write TRAP outside a file: $trap " )
47- }
48- override fun getLocation (startOffset : Int , endOffset : Int ): Label <DbLocation_default > {
49- extractorBug(" Asked for location, but not in a file" )
50- return Label (0 )
51- }
52- override fun <T > getIdFor (label : String ): Label <T > {
53- extractorBug(" Asked for ID for '$label ' outside a file" )
54- return Label (0 )
55- }
56- override fun <T > getFreshId (): Label <T > {
57- extractorBug(" Asked for fresh ID outside a file" )
58- return Label (0 )
59- }
60- }
61-
62- class FileTrapWriter (
38+ class TrapWriter (
6339 val fileLabel : String ,
6440 val file : BufferedWriter ,
6541 val fileEntry : IrFileEntry
66- ): TrapWriter {
42+ ) {
6743 var nextId: Int = 100
68- override fun writeTrap (trap : String ) {
44+ fun writeTrap (trap : String ) {
6945 file.write(trap)
7046 }
71- override fun getLocation (startOffset : Int , endOffset : Int ): Label <DbLocation_default > {
47+ fun getLocation (startOffset : Int , endOffset : Int ): Label <DbLocation_default > {
7248 val startLine = fileEntry.getLineNumber(startOffset) + 1
7349 val startColumn = fileEntry.getColumnNumber(startOffset) + 1
7450 val endLine = fileEntry.getLineNumber(endOffset) + 1
@@ -80,64 +56,77 @@ class FileTrapWriter(
8056 return id
8157 }
8258 val labelMapping: MutableMap <String , Label <* >> = mutableMapOf<String , Label <* >>()
83- override fun <T > getIdFor (label : String ): Label <T > {
59+ fun <T > getIdFor (label : String , initialise : ( Label < T >) -> Unit = {} ): Label <T > {
8460 val maybeId = labelMapping.get(label)
8561 if (maybeId == null ) {
8662 val id: Label <T > = getFreshId()
8763 labelMapping.put(label, id)
64+ writeTrap(" $id = $label \n " )
65+ initialise(id)
8866 return id
8967 } else {
9068 @Suppress(" UNCHECKED_CAST" )
9169 return maybeId as Label <T >
9270 }
9371 }
94- override fun <T > getFreshId (): Label <T > {
72+ fun <T > getFreshId (): Label <T > {
9573 return Label (nextId++ )
9674 }
9775}
9876
99- class KotlinExtractorVisitor (val trapDir : File , val srcDir : File ) : IrElementVisitor<Unit, TrapWriter> {
100- override fun visitElement (element : IrElement , data : TrapWriter ) {
101- extractorBug(" Unrecognised IrElement: " + element.javaClass)
102- if (data is RootTrapWriter ) {
103- extractorBug(" ... and outside any file!" )
104- }
105- element.acceptChildren(this , data)
77+ fun extractFile (trapDir : File , srcDir : File , declaration : IrFile ) {
78+ val filePath = declaration.path
79+ val file = File (filePath)
80+ val fileLabel = " @\" $filePath ;sourcefile\" "
81+ val basename = file.nameWithoutExtension
82+ val extension = file.extension
83+ val dest = Paths .get(" $srcDir /${declaration.path} " )
84+ val destDir = dest.getParent()
85+ Files .createDirectories(destDir)
86+ Files .copy(Paths .get(declaration.path), dest)
87+
88+ val trapFile = File (" $trapDir /$filePath .trap" )
89+ val trapFileDir = trapFile.getParentFile()
90+ trapFileDir.mkdirs()
91+ trapFile.bufferedWriter().use { trapFileBW ->
92+ val tw = TrapWriter (fileLabel, trapFileBW, declaration.fileEntry)
93+ val id: Label <DbFile > = tw.getIdFor(fileLabel)
94+ tw.writeFiles(id, filePath, basename, extension, 0 )
95+ val fileExtractor = KotlinFileExtractor (tw)
96+ val pkg = declaration.fqName.asString()
97+ val pkgId = fileExtractor.extractPackage(pkg)
98+ tw.writeCupackage(id, pkgId)
99+ declaration.declarations.map { fileExtractor.extractDeclaration(it) }
106100 }
107- override fun visitClass (declaration : IrClass , data : TrapWriter ) {
108- val id: Label <DbClass > = data.getFreshId()
109- val pkgId: Label <DbPackage > = data.getFreshId()
110- val locId = data.getLocation(declaration.startOffset, declaration.endOffset)
111- val pkg = declaration.packageFqName?.asString() ? : " "
112- val cls = declaration.name.asString()
113- data.writeTrap(" $pkgId = @\" pkg;$pkg \"\n " )
114- data.writePackages(pkgId, pkg)
115- data.writeTrap(" $id = @\" class;$pkg .$cls \"\n " )
116- data.writeClasses(id, cls, pkgId, id)
117- data.writeHasLocation(id, locId)
118- declaration.acceptChildren(this , data)
101+ }
102+
103+ class KotlinFileExtractor (val tw : TrapWriter ) {
104+ fun extractPackage (pkg : String ): Label <DbPackage > {
105+ val pkgLabel = " @\" package;$pkg \" "
106+ val id: Label <DbPackage > = tw.getIdFor(pkgLabel, {
107+ tw.writePackages(it, pkg)
108+ })
109+ return id
119110 }
120- override fun visitFile (declaration : IrFile , data : TrapWriter ) {
121- val filePath = declaration.path
122- val file = File (filePath)
123- val fileLabel = " @\" $filePath ;sourcefile\" "
124- val basename = file.nameWithoutExtension
125- val extension = file.extension
126- val dest = Paths .get(" $srcDir /${declaration.path} " )
127- val destDir = dest.getParent()
128- Files .createDirectories(destDir)
129- Files .copy(Paths .get(declaration.path), dest)
130111
131- val trapFile = File (" $trapDir /$filePath .trap" )
132- val trapFileDir = trapFile.getParentFile()
133- trapFileDir.mkdirs()
134- trapFile.bufferedWriter().use { trapFileBW ->
135- val tw = FileTrapWriter (fileLabel, trapFileBW, declaration.fileEntry)
136- val id: Label <DbFile > = tw.getIdFor(fileLabel)
137- tw.writeTrap(" $id = $fileLabel \n " )
138- tw.writeFiles(id, filePath, basename, extension, 0 )
139- declaration.acceptChildren(this , tw)
112+ fun extractDeclaration (declaration : IrDeclaration ) {
113+ when (declaration) {
114+ is IrClass -> extractClass(declaration)
115+ else -> extractorBug(" Unrecognised IrDeclaration: " + declaration.javaClass)
140116 }
141117 }
118+
119+ fun extractClass (declaration : IrClass ) {
120+ val id: Label <DbClass > = tw.getFreshId()
121+ val locId = tw.getLocation(declaration.startOffset, declaration.endOffset)
122+ val pkg = declaration.packageFqName?.asString() ? : " "
123+ val cls = declaration.name.asString()
124+ val qualClassName = if (pkg.isEmpty()) cls else " $pkg .$cls "
125+ val pkgId = extractPackage(pkg)
126+ tw.writeTrap(" $id = @\" class;$qualClassName \"\n " )
127+ tw.writeClasses(id, cls, pkgId, id)
128+ tw.writeHasLocation(id, locId)
129+ declaration.declarations.map { extractDeclaration(it) }
130+ }
142131}
143132
0 commit comments