mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Kotlin: Start documenting TrapWriter
This commit is contained in:
@@ -10,53 +10,103 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
|
||||
import com.semmle.extractor.java.PopulateFile
|
||||
|
||||
/**
|
||||
* Each `.trap` file has a `TrapLabelManager` while we are writing it.
|
||||
* It provides fresh TRAP label names, and maintains a mapping from keys
|
||||
* (`@"..."`) to labels.
|
||||
*/
|
||||
class TrapLabelManager {
|
||||
public var nextId: Int = 100
|
||||
/** The next integer to use as a label name. */
|
||||
private var nextInt: Int = 100
|
||||
|
||||
/** Returns a fresh label. */
|
||||
fun <T> getFreshLabel(): Label<T> {
|
||||
return IntLabel(nextId++)
|
||||
return IntLabel(nextInt++)
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping from a key (`@"..."`) to the label defined to be that
|
||||
* key, if any.
|
||||
*/
|
||||
val labelMapping: MutableMap<String, Label<*>> = mutableMapOf<String, Label<*>>()
|
||||
}
|
||||
|
||||
/**
|
||||
* A `TrapWriter` is used to write TRAP to a particular TRAP file.
|
||||
* There may be multiple `TrapWriter`s for the same file, as different
|
||||
* instances will have different additional state, but they must all
|
||||
* share the same `TrapLabelManager` and `BufferedWriter`.
|
||||
*/
|
||||
open class TrapWriter (val lm: TrapLabelManager, val bw: BufferedWriter) {
|
||||
fun <T> getExistingLabelFor(label: String): Label<T>? {
|
||||
/**
|
||||
* 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
|
||||
* `getLabelFor` instead, which allows non-existent labels to be
|
||||
* initialised.
|
||||
*/
|
||||
fun <T> getExistingLabelFor(key: String): Label<T>? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return lm.labelMapping.get(label) as Label<T>?
|
||||
return lm.labelMapping.get(key) as Label<T>?
|
||||
}
|
||||
@JvmOverloads
|
||||
fun <T> getLabelFor(label: String, initialise: (Label<T>) -> Unit = {}): Label<T> {
|
||||
val maybeId: Label<T>? = getExistingLabelFor(label)
|
||||
if(maybeId == null) {
|
||||
val id: Label<T> = lm.getFreshLabel()
|
||||
lm.labelMapping.put(label, id)
|
||||
writeTrap("$id = $label\n")
|
||||
initialise(id)
|
||||
return id
|
||||
/**
|
||||
* Returns the label for the given key, if one exists.
|
||||
* Otherwise, a fresh label is bound to that key, `initialise`
|
||||
* is run on it, and it is returned.
|
||||
*/
|
||||
@JvmOverloads // Needed so Java can call a method with an optional argument
|
||||
fun <T> getLabelFor(key: String, initialise: (Label<T>) -> Unit = {}): Label<T> {
|
||||
val maybeLabel: Label<T>? = getExistingLabelFor(key)
|
||||
if(maybeLabel == null) {
|
||||
val label: Label<T> = lm.getFreshLabel()
|
||||
lm.labelMapping.put(key, label)
|
||||
writeTrap("$label = $key\n")
|
||||
initialise(label)
|
||||
return label
|
||||
} else {
|
||||
return maybeId
|
||||
return maybeLabel
|
||||
}
|
||||
}
|
||||
val variableLabelMapping: MutableMap<IrVariable, Label<out DbLocalvar>> = mutableMapOf<IrVariable, Label<out DbLocalvar>>()
|
||||
/**
|
||||
* 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 maybeId = variableLabelMapping.get(v)
|
||||
if(maybeId == null) {
|
||||
val id = lm.getFreshLabel<DbLocalvar>()
|
||||
variableLabelMapping.put(v, id)
|
||||
writeTrap("$id = *\n")
|
||||
return id
|
||||
val maybeLabel = variableLabelMapping.get(v)
|
||||
if(maybeLabel == null) {
|
||||
val label = lm.getFreshLabel<DbLocalvar>()
|
||||
variableLabelMapping.put(v, label)
|
||||
writeTrap("$label = *\n")
|
||||
return label
|
||||
} else {
|
||||
return maybeId
|
||||
return maybeLabel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a label for the location described by its arguments.
|
||||
* Typically users will not want to call this directly, but instead
|
||||
* use `unknownLocation`, or overloads of this defined by subclasses.
|
||||
*/
|
||||
fun getLocation(fileId: Label<DbFile>, startLine: Int, startColumn: Int, endLine: Int, endColumn: Int): Label<DbLocation> {
|
||||
return getLabelFor("@\"loc,{$fileId},$startLine,$startColumn,$endLine,$endColumn\"") {
|
||||
writeLocations_default(it, fileId, startLine, startColumn, endLine, endColumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The label for the 'unknown' file ID.
|
||||
* Users will want to use `unknownLocation` instead.
|
||||
* This is lazy, as we don't want to define it in a TRAP file unless
|
||||
* the TRAP file actually contains something in the 'unknown' file.
|
||||
*/
|
||||
protected val unknownFileId: Label<DbFile> by lazy {
|
||||
val unknownFileLabel = "@\";sourcefile\""
|
||||
getLabelFor(unknownFileLabel, {
|
||||
@@ -64,16 +114,34 @@ open class TrapWriter (val lm: TrapLabelManager, val bw: BufferedWriter) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The label for the 'unknown' location.
|
||||
* This is lazy, as we don't want to define it in a TRAP file unless
|
||||
* the TRAP file actually contains something with an 'unknown'
|
||||
* location.
|
||||
*/
|
||||
val unknownLocation: Label<DbLocation> by lazy {
|
||||
getLocation(unknownFileId, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a raw string into the TRAP file. Users should call one of
|
||||
* the wrapper functions instead.
|
||||
*/
|
||||
fun writeTrap(trap: String) {
|
||||
bw.write(trap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a comment into the TRAP file.
|
||||
*/
|
||||
fun writeComment(comment: String) {
|
||||
writeTrap("// ${comment.replace("\n", "\n// ")}\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the TRAP file.
|
||||
*/
|
||||
fun flush() {
|
||||
bw.flush()
|
||||
}
|
||||
@@ -86,20 +154,6 @@ open class TrapWriter (val lm: TrapLabelManager, val bw: BufferedWriter) {
|
||||
FileTrapWriter(lm, bw, filePath, fileEntry, populateFileTables)
|
||||
}
|
||||
|
||||
class SourceFileTrapWriter (
|
||||
lm: TrapLabelManager,
|
||||
bw: BufferedWriter,
|
||||
irFile: IrFile) :
|
||||
FileTrapWriter(lm, bw, irFile.path, irFile.fileEntry) {
|
||||
}
|
||||
|
||||
class ClassFileTrapWriter (
|
||||
lm: TrapLabelManager,
|
||||
bw: BufferedWriter,
|
||||
filePath: String) :
|
||||
FileTrapWriter(lm, bw, filePath, null) {
|
||||
}
|
||||
|
||||
open class FileTrapWriter (
|
||||
lm: TrapLabelManager,
|
||||
bw: BufferedWriter,
|
||||
@@ -156,8 +210,22 @@ open class FileTrapWriter (
|
||||
}
|
||||
}
|
||||
fun <T> getFreshIdLabel(): Label<T> {
|
||||
val label = IntLabel<T>(lm.nextId++)
|
||||
val label: Label<T> = lm.getFreshLabel()
|
||||
writeTrap("$label = *\n")
|
||||
return label
|
||||
}
|
||||
}
|
||||
|
||||
class SourceFileTrapWriter (
|
||||
lm: TrapLabelManager,
|
||||
bw: BufferedWriter,
|
||||
irFile: IrFile) :
|
||||
FileTrapWriter(lm, bw, irFile.path, irFile.fileEntry) {
|
||||
}
|
||||
|
||||
class ClassFileTrapWriter (
|
||||
lm: TrapLabelManager,
|
||||
bw: BufferedWriter,
|
||||
filePath: String) :
|
||||
FileTrapWriter(lm, bw, filePath, null) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user