Kotlin: Start documenting TrapWriter

This commit is contained in:
Ian Lynagh
2021-11-22 17:28:37 +00:00
parent afabe652c1
commit 83ac77dccc

View File

@@ -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) {
}