@@ -3,18 +3,26 @@ package com.github.codeql
33import com.github.codeql.utils.isExternalFileClassMember
44import com.semmle.extractor.java.OdasaOutput
55import com.semmle.util.data.StringDigestor
6+ import java.io.BufferedWriter
7+ import java.io.File
8+ import java.util.ArrayList
9+ import java.util.HashSet
610import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
711import org.jetbrains.kotlin.ir.IrElement
812import org.jetbrains.kotlin.ir.declarations.*
913import org.jetbrains.kotlin.ir.util.isFileClass
1014import org.jetbrains.kotlin.ir.util.packageFqName
11- import java.io.BufferedWriter
12- import java.io.File
13- import java.util.ArrayList
14- import java.util.HashSet
15- import java.util.zip.GZIPOutputStream
1615
17- class ExternalDeclExtractor (val logger : FileLogger , val compression : Compression , val invocationTrapFile : String , val sourceFilePath : String , val primitiveTypeMapping : PrimitiveTypeMapping , val pluginContext : IrPluginContext , val globalExtensionState : KotlinExtractorGlobalState , val diagnosticTrapWriter : DiagnosticTrapWriter ) {
16+ class ExternalDeclExtractor (
17+ val logger : FileLogger ,
18+ val compression : Compression ,
19+ val invocationTrapFile : String ,
20+ val sourceFilePath : String ,
21+ val primitiveTypeMapping : PrimitiveTypeMapping ,
22+ val pluginContext : IrPluginContext ,
23+ val globalExtensionState : KotlinExtractorGlobalState ,
24+ val diagnosticTrapWriter : DiagnosticTrapWriter
25+ ) {
1826
1927 val declBinaryNames = HashMap <IrDeclaration , String >()
2028 val externalDeclsDone = HashSet <Pair <String , String >>()
@@ -23,48 +31,72 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
2331 val propertySignature = " ;property"
2432 val fieldSignature = " ;field"
2533
26- val output = OdasaOutput (false , compression, logger).also {
27- it.setCurrentSourceFile(File (sourceFilePath))
28- }
34+ val output =
35+ OdasaOutput (false , compression, logger).also {
36+ it.setCurrentSourceFile(File (sourceFilePath))
37+ }
2938
3039 fun extractLater (d : IrDeclarationWithName , signature : String ): Boolean {
3140 if (d !is IrClass && ! isExternalFileClassMember(d)) {
32- logger.errorElement(" External declaration is neither a class, nor a top-level declaration" , d)
41+ logger.errorElement(
42+ " External declaration is neither a class, nor a top-level declaration" ,
43+ d
44+ )
3345 return false
3446 }
3547 val declBinaryName = declBinaryNames.getOrPut(d) { getIrElementBinaryName(d) }
3648 val ret = externalDeclsDone.add(Pair (declBinaryName, signature))
3749 if (ret) externalDeclWorkList.add(Pair (d, signature))
3850 return ret
3951 }
52+
4053 fun extractLater (c : IrClass ) = extractLater(c, " " )
4154
4255 fun writeStubTrapFile (e : IrElement , signature : String = "") {
4356 extractElement(e, signature, true ) { trapFileBW, _, _ ->
44- trapFileBW.write(" // Trap file stubbed because this declaration was extracted from source in $sourceFilePath \n " )
57+ trapFileBW.write(
58+ " // Trap file stubbed because this declaration was extracted from source in $sourceFilePath \n "
59+ )
4560 trapFileBW.write(" // Part of invocation $invocationTrapFile \n " )
4661 }
4762 }
4863
49- private fun extractElement (element : IrElement , possiblyLongSignature : String , fromSource : Boolean , extractorFn : (BufferedWriter , String , OdasaOutput .TrapFileManager ) -> Unit ) {
50- // In order to avoid excessively long signatures which can lead to trap file names longer than the filesystem
64+ private fun extractElement (
65+ element : IrElement ,
66+ possiblyLongSignature : String ,
67+ fromSource : Boolean ,
68+ extractorFn : (BufferedWriter , String , OdasaOutput .TrapFileManager ) -> Unit
69+ ) {
70+ // In order to avoid excessively long signatures which can lead to trap file names longer
71+ // than the filesystem
5172 // limit, we truncate and add a hash to preserve uniqueness if necessary.
52- val signature = if (possiblyLongSignature.length > 100 ) {
53- possiblyLongSignature.substring(0 , 92 ) + " #" + StringDigestor .digest(possiblyLongSignature).substring(0 , 8 )
54- } else { possiblyLongSignature }
73+ val signature =
74+ if (possiblyLongSignature.length > 100 ) {
75+ possiblyLongSignature.substring(0 , 92 ) +
76+ " #" +
77+ StringDigestor .digest(possiblyLongSignature).substring(0 , 8 )
78+ } else {
79+ possiblyLongSignature
80+ }
5581 output.getTrapLockerForDecl(element, signature, fromSource).useAC { locker ->
5682 locker.trapFileManager.useAC { manager ->
57- val shortName = when (element) {
58- is IrDeclarationWithName -> element.name.asString()
59- is IrFile -> element.name
60- else -> " (unknown name)"
61- }
83+ val shortName =
84+ when (element) {
85+ is IrDeclarationWithName -> element.name.asString()
86+ is IrFile -> element.name
87+ else -> " (unknown name)"
88+ }
6289 if (manager == null ) {
6390 logger.info(" Skipping extracting external decl $shortName " )
6491 } else {
6592 val trapFile = manager.file
6693 logger.info(" Will write TRAP file $trapFile " )
67- val trapTmpFile = File .createTempFile(" ${trapFile.nameWithoutExtension} ." , " .${trapFile.extension} .tmp" , trapFile.parentFile)
94+ val trapTmpFile =
95+ File .createTempFile(
96+ " ${trapFile.nameWithoutExtension} ." ,
97+ " .${trapFile.extension} .tmp" ,
98+ trapFile.parentFile
99+ )
68100 logger.debug(" Writing temporary TRAP file $trapTmpFile " )
69101 try {
70102 compression.bufferedWriter(trapTmpFile).use {
@@ -77,7 +109,10 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
77109 logger.info(" Finished writing TRAP file $trapFile " )
78110 } catch (e: Exception ) {
79111 manager.setHasError()
80- logger.error(" Failed to extract '$shortName '. Partial TRAP file location is $trapTmpFile " , e)
112+ logger.error(
113+ " Failed to extract '$shortName '. Partial TRAP file location is $trapTmpFile " ,
114+ e
115+ )
81116 }
82117 }
83118 }
@@ -90,43 +125,80 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
90125 externalDeclWorkList.clear()
91126 nextBatch.forEach { workPair ->
92127 val (irDecl, possiblyLongSignature) = workPair
93- extractElement(irDecl, possiblyLongSignature, false ) { trapFileBW, signature, manager ->
128+ extractElement(irDecl, possiblyLongSignature, false ) {
129+ trapFileBW,
130+ signature,
131+ manager ->
94132 val binaryPath = getIrDeclarationBinaryPath(irDecl)
95133 if (binaryPath == null ) {
96134 logger.errorElement(" Unable to get binary path" , irDecl)
97135 } else {
98136 // We want our comments to be the first thing in the file,
99137 // so start off with a PlainTrapWriter
100- val tw = PlainTrapWriter (logger.loggerBase, TrapLabelManager (), trapFileBW, diagnosticTrapWriter)
101- tw.writeComment(" Generated by the CodeQL Kotlin extractor for external dependencies" )
138+ val tw =
139+ PlainTrapWriter (
140+ logger.loggerBase,
141+ TrapLabelManager (),
142+ trapFileBW,
143+ diagnosticTrapWriter
144+ )
145+ tw.writeComment(
146+ " Generated by the CodeQL Kotlin extractor for external dependencies"
147+ )
102148 tw.writeComment(" Part of invocation $invocationTrapFile " )
103149 if (signature != possiblyLongSignature) {
104- tw.writeComment(" Function signature abbreviated; full signature is: $possiblyLongSignature " )
150+ tw.writeComment(
151+ " Function signature abbreviated; full signature is: $possiblyLongSignature "
152+ )
105153 }
106154 // Now elevate to a SourceFileTrapWriter, and populate the
107155 // file information if needed:
108156 val ftw = tw.makeFileTrapWriter(binaryPath, true )
109157
110- val fileExtractor = KotlinFileExtractor (logger, ftw, null , binaryPath, manager, this , primitiveTypeMapping, pluginContext, KotlinFileExtractor .DeclarationStack (), globalExtensionState)
158+ val fileExtractor =
159+ KotlinFileExtractor (
160+ logger,
161+ ftw,
162+ null ,
163+ binaryPath,
164+ manager,
165+ this ,
166+ primitiveTypeMapping,
167+ pluginContext,
168+ KotlinFileExtractor .DeclarationStack (),
169+ globalExtensionState
170+ )
111171
112172 if (irDecl is IrClass ) {
113- // Populate a location and compilation-unit package for the file. This is similar to
114- // the beginning of `KotlinFileExtractor.extractFileContents` but without an `IrFile`
173+ // Populate a location and compilation-unit package for the file. This
174+ // is similar to
175+ // the beginning of `KotlinFileExtractor.extractFileContents` but
176+ // without an `IrFile`
115177 // to start from.
116178 val pkg = irDecl.packageFqName?.asString() ? : " "
117179 val pkgId = fileExtractor.extractPackage(pkg)
118180 ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation())
119181 ftw.writeCupackage(ftw.fileId, pkgId)
120182
121- fileExtractor.extractClassSource(irDecl, extractDeclarations = ! irDecl.isFileClass, extractStaticInitializer = false , extractPrivateMembers = false , extractFunctionBodies = false )
183+ fileExtractor.extractClassSource(
184+ irDecl,
185+ extractDeclarations = ! irDecl.isFileClass,
186+ extractStaticInitializer = false ,
187+ extractPrivateMembers = false ,
188+ extractFunctionBodies = false
189+ )
122190 } else {
123- fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false , extractFunctionBodies = false , extractAnnotations = true )
191+ fileExtractor.extractDeclaration(
192+ irDecl,
193+ extractPrivateMembers = false ,
194+ extractFunctionBodies = false ,
195+ extractAnnotations = true
196+ )
124197 }
125198 }
126199 }
127200 }
128201 } while (externalDeclWorkList.isNotEmpty())
129202 output.writeTrapSet()
130203 }
131-
132204}
0 commit comments