@@ -3,18 +3,26 @@ package com.github.codeql
3
3
import com.github.codeql.utils.isExternalFileClassMember
4
4
import com.semmle.extractor.java.OdasaOutput
5
5
import 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
6
10
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
7
11
import org.jetbrains.kotlin.ir.IrElement
8
12
import org.jetbrains.kotlin.ir.declarations.*
9
13
import org.jetbrains.kotlin.ir.util.isFileClass
10
14
import 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
16
15
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
+ ) {
18
26
19
27
val declBinaryNames = HashMap <IrDeclaration , String >()
20
28
val externalDeclsDone = HashSet <Pair <String , String >>()
@@ -23,48 +31,72 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
23
31
val propertySignature = " ;property"
24
32
val fieldSignature = " ;field"
25
33
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
+ }
29
38
30
39
fun extractLater (d : IrDeclarationWithName , signature : String ): Boolean {
31
40
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
+ )
33
45
return false
34
46
}
35
47
val declBinaryName = declBinaryNames.getOrPut(d) { getIrElementBinaryName(d) }
36
48
val ret = externalDeclsDone.add(Pair (declBinaryName, signature))
37
49
if (ret) externalDeclWorkList.add(Pair (d, signature))
38
50
return ret
39
51
}
52
+
40
53
fun extractLater (c : IrClass ) = extractLater(c, " " )
41
54
42
55
fun writeStubTrapFile (e : IrElement , signature : String = "") {
43
56
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
+ )
45
60
trapFileBW.write(" // Part of invocation $invocationTrapFile \n " )
46
61
}
47
62
}
48
63
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
51
72
// 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
+ }
55
81
output.getTrapLockerForDecl(element, signature, fromSource).useAC { locker ->
56
82
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
+ }
62
89
if (manager == null ) {
63
90
logger.info(" Skipping extracting external decl $shortName " )
64
91
} else {
65
92
val trapFile = manager.file
66
93
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
+ )
68
100
logger.debug(" Writing temporary TRAP file $trapTmpFile " )
69
101
try {
70
102
compression.bufferedWriter(trapTmpFile).use {
@@ -77,7 +109,10 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
77
109
logger.info(" Finished writing TRAP file $trapFile " )
78
110
} catch (e: Exception ) {
79
111
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
+ )
81
116
}
82
117
}
83
118
}
@@ -90,43 +125,80 @@ class ExternalDeclExtractor(val logger: FileLogger, val compression: Compression
90
125
externalDeclWorkList.clear()
91
126
nextBatch.forEach { workPair ->
92
127
val (irDecl, possiblyLongSignature) = workPair
93
- extractElement(irDecl, possiblyLongSignature, false ) { trapFileBW, signature, manager ->
128
+ extractElement(irDecl, possiblyLongSignature, false ) {
129
+ trapFileBW,
130
+ signature,
131
+ manager ->
94
132
val binaryPath = getIrDeclarationBinaryPath(irDecl)
95
133
if (binaryPath == null ) {
96
134
logger.errorElement(" Unable to get binary path" , irDecl)
97
135
} else {
98
136
// We want our comments to be the first thing in the file,
99
137
// 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
+ )
102
148
tw.writeComment(" Part of invocation $invocationTrapFile " )
103
149
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
+ )
105
153
}
106
154
// Now elevate to a SourceFileTrapWriter, and populate the
107
155
// file information if needed:
108
156
val ftw = tw.makeFileTrapWriter(binaryPath, true )
109
157
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
+ )
111
171
112
172
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`
115
177
// to start from.
116
178
val pkg = irDecl.packageFqName?.asString() ? : " "
117
179
val pkgId = fileExtractor.extractPackage(pkg)
118
180
ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation())
119
181
ftw.writeCupackage(ftw.fileId, pkgId)
120
182
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
+ )
122
190
} 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
+ )
124
197
}
125
198
}
126
199
}
127
200
}
128
201
} while (externalDeclWorkList.isNotEmpty())
129
202
output.writeTrapSet()
130
203
}
131
-
132
204
}
0 commit comments