Merge pull request #18134 from smowton/smowton/ke2/external-class-extraction

KE2: basic external class extraction
This commit is contained in:
Chris Smowton
2024-11-27 18:15:33 +00:00
committed by GitHub
14 changed files with 384 additions and 282 deletions

View File

@@ -23,13 +23,11 @@ import com.github.codeql.Logger;
//import static com.github.codeql.ClassNamesKt.getIrElementBinaryName;
//import static com.github.codeql.ClassNamesKt.getIrClassVirtualFile;
import org.jetbrains.kotlin.ir.IrElement;
import org.jetbrains.kotlin.ir.declarations.IrClass;
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol;
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.kotlin.ir.declarations.IrDeclaration;
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.ClassReader;
import org.jetbrains.org.objectweb.asm.Opcodes;
@@ -51,6 +49,8 @@ import com.semmle.util.trap.pathtransformers.PathTransformer;
import com.github.codeql.Compression;
import static com.github.codeql.ClassNamesKt.getSymbolBinaryName;
public class OdasaOutput {
private final File trapFolder;
private final File sourceArchiveFolder;
@@ -136,7 +136,7 @@ public class OdasaOutput {
currentSpecFileEntry.getTrapFolder(), PathTransformer.std().fileAsDatabaseString(file) + ".set");
}
public void addDependency(IrDeclaration sym, String signature) {
public void addDependency(KaSymbol sym, String signature) {
String path = trapFilePathForDecl(sym, signature);
trapDependenciesForSource.addDependency(path);
}
@@ -203,29 +203,28 @@ public class OdasaOutput {
PathTransformer.std().fileAsDatabaseString(file) + ".trap" + compression.getExtension());
}
private File getTrapFileForDecl(IrElement sym, String signature) {
private File getTrapFileForDecl(KaSymbol sym, String signature) {
if (currentSpecFileEntry == null)
return null;
return trapFileForDecl(sym, signature);
}
private File trapFileForDecl(IrElement sym, String signature) {
private File trapFileForDecl(KaSymbol sym, String signature) {
return FileUtil.fileRelativeTo(currentSpecFileEntry.getTrapFolder(),
trapFilePathForDecl(sym, signature));
}
private String trapFilePathForDecl(IrElement sym, String signature) {
// String binaryName = getIrElementBinaryName(sym);
private String trapFilePathForDecl(KaSymbol sym, String signature) {
String binaryName = getSymbolBinaryName(sym);
// TODO: Reinstate this?
// if (getTrackClassOrigins())
// classId += "-" + StringDigestor.digest(sym.getSourceFileId());
// String result = CLASSES_DIR + "/" +
// binaryName.replace('.', '/') +
// signature +
// ".members" +
// ".trap" + compression.getExtension();
// return result;
return null;
String result = CLASSES_DIR + "/" +
binaryName.replace('.', '/') +
signature +
".members" +
".trap" + compression.getExtension();
return result;
}
/*
@@ -248,7 +247,7 @@ public class OdasaOutput {
* signature.
*/
private TrapFileManager getMembersWriterForDecl(File trap, File trapFileBase, TrapClassVersion trapFileVersion,
IrElement sym, String signature) {
KaSymbol sym, String signature) {
// If the TRAP file already exists then we
// don't need to write it.
if (trap.exists()) {
@@ -288,7 +287,7 @@ public class OdasaOutput {
return trapWriter(trap, sym, signature);
}
private TrapFileManager trapWriter(File trapFile, IrElement sym, String signature) {
private TrapFileManager trapWriter(File trapFile, KaSymbol sym, String signature) {
if (!trapFile.getName().endsWith(".trap" + compression.getExtension()))
throw new CatastrophicError("OdasaOutput only supports writing to compressed trap files");
String relative = FileUtil.relativePath(trapFile, currentSpecFileEntry.getTrapFolder());
@@ -297,7 +296,7 @@ public class OdasaOutput {
return concurrentWriter(trapFile, relative, log, sym, signature);
}
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, IrElement sym,
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, KaSymbol sym,
String signature) {
if (trapFile.exists())
return null;
@@ -308,11 +307,11 @@ public class OdasaOutput {
private TrapDependencies trapDependenciesForClass;
private File trapFile;
private IrElement sym;
private KaSymbol sym;
private String signature;
private boolean hasError = false;
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, IrElement sym,
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, KaSymbol sym,
String signature) {
trapDependenciesForClass = new TrapDependencies(relative);
this.trapFile = trapFile;
@@ -324,11 +323,11 @@ public class OdasaOutput {
return trapFile;
}
public void addDependency(IrElement dep, String signature) {
public void addDependency(KaSymbol dep, String signature) {
trapDependenciesForClass.addDependency(trapFilePathForDecl(dep, signature));
}
public void addDependency(IrClass c) {
public void addDependency(KaClassSymbol c) {
addDependency(c, "");
}
@@ -374,7 +373,7 @@ public class OdasaOutput {
* {@link OdasaOutput#setCurrentSourceFile(File)}.
*/
public TrapLocker getTrapLockerForCurrentSourceFile() {
return new TrapLocker((IrClass) null, null, true);
return new TrapLocker((KaClassSymbol) null, null, true);
}
/**
@@ -427,12 +426,12 @@ public class OdasaOutput {
* @return a {@link TrapLocker} for the trap file corresponding to the given
* class symbol.
*/
public TrapLocker getTrapLockerForDecl(IrElement sym, String signature, boolean fromSource) {
public TrapLocker getTrapLockerForDecl(KaSymbol sym, String signature, boolean fromSource) {
return new TrapLocker(sym, signature, fromSource);
}
public class TrapLocker implements AutoCloseable {
private final IrElement sym;
private final KaSymbol sym;
private final File trapFile;
// trapFileBase is used when doing lockless TRAP file writing.
// It is trapFile without the #metadata.trap.gz suffix.
@@ -440,7 +439,7 @@ public class OdasaOutput {
private TrapClassVersion trapFileVersion = null;
private final String signature;
private TrapLocker(IrElement decl, String signature, boolean fromSource) {
private TrapLocker(KaSymbol decl, String signature, boolean fromSource) {
this.sym = decl;
this.signature = signature;
if (sym == null) {
@@ -675,7 +674,7 @@ public class OdasaOutput {
return vf.getTimeStamp();
}
private static VirtualFile getVirtualFileIfClass(IrElement e) {
private static VirtualFile getVirtualFileIfClass(KaSymbol e) {
// TODO:
return null;
// if (e instanceof IrClass)
@@ -684,10 +683,12 @@ public class OdasaOutput {
// return null;
}
private static TrapClassVersion fromSymbol(IrElement sym, Logger log) {
private static TrapClassVersion fromSymbol(KaSymbol sym, Logger log) {
VirtualFile vf = getVirtualFileIfClass(sym);
/* OLD: KE1
if (vf == null && sym instanceof IrDeclaration)
vf = getVirtualFileIfClass(((IrDeclaration) sym).getParent());
*/
if (vf == null)
return new TrapClassVersion(-1, 0, 0, null);

View File

@@ -1,34 +1,33 @@
package com.github.codeql
/*
OLD: KE1
import com.github.codeql.utils.isExternalFileClassMember
import com.semmle.extractor.java.OdasaOutput
import com.semmle.util.data.StringDigestor
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaNamedSymbol
import java.io.BufferedWriter
import java.io.File
import java.lang.Error
import java.util.ArrayList
import java.util.HashSet
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.isFileClass
import org.jetbrains.kotlin.ir.util.packageFqName
context (KaSession)
class ExternalDeclExtractor(
val logger: FileLogger,
val compression: Compression,
val invocationTrapFile: String,
val sourceFilePath: String,
/* OLD: KE1
val primitiveTypeMapping: PrimitiveTypeMapping,
val pluginContext: IrPluginContext,
val globalExtensionState: KotlinExtractorGlobalState,
*/
val diagnosticTrapWriter: DiagnosticTrapWriter
) {
val declBinaryNames = HashMap<IrDeclaration, String>()
val declBinaryNames = HashMap<KaSymbol, String>()
val externalDeclsDone = HashSet<Pair<String, String>>()
val externalDeclWorkList = ArrayList<Pair<IrDeclaration, String>>()
val externalDeclWorkList = ArrayList<Pair<KaSymbol, String>>()
val propertySignature = ";property"
val fieldSignature = ";field"
@@ -38,7 +37,8 @@ class ExternalDeclExtractor(
it.setCurrentSourceFile(File(sourceFilePath))
}
fun extractLater(d: IrDeclarationWithName, signature: String): Boolean {
fun extractLater(d: KaSymbol, signature: String): Boolean {
/* OLD: KE1
if (d !is IrClass && !isExternalFileClassMember(d)) {
logger.errorElement(
"External declaration is neither a class, nor a top-level declaration",
@@ -46,15 +46,16 @@ class ExternalDeclExtractor(
)
return false
}
val declBinaryName = declBinaryNames.getOrPut(d) { getIrElementBinaryName(d) }
*/
val declBinaryName = declBinaryNames.getOrPut(d) { getSymbolBinaryName(d) }
val ret = externalDeclsDone.add(Pair(declBinaryName, signature))
if (ret) externalDeclWorkList.add(Pair(d, signature))
return ret
}
fun extractLater(c: IrClass) = extractLater(c, "")
fun extractLater(c: KaClassSymbol) = extractLater(c, "")
fun writeStubTrapFile(e: IrElement, signature: String = "") {
fun writeStubTrapFile(e: KaSymbol, signature: String = "") {
extractElement(e, signature, true) { trapFileBW, _, _ ->
trapFileBW.write(
"// Trap file stubbed because this declaration was extracted from source in $sourceFilePath\n"
@@ -64,7 +65,7 @@ class ExternalDeclExtractor(
}
private fun extractElement(
element: IrElement,
element: KaSymbol,
possiblyLongSignature: String,
fromSource: Boolean,
extractorFn: (BufferedWriter, String, OdasaOutput.TrapFileManager) -> Unit
@@ -84,8 +85,8 @@ class ExternalDeclExtractor(
locker.trapFileManager.useAC { manager ->
val shortName =
when (element) {
is IrDeclarationWithName -> element.name.asString()
is IrFile -> element.name
is KaNamedSymbol -> element.name.asString()
is KaFileSymbol -> "(TODO file symbol name)"
else -> "(unknown name)"
}
if (manager == null) {
@@ -109,7 +110,7 @@ class ExternalDeclExtractor(
logger.error("Failed to rename $trapTmpFile to $trapFile")
}
logger.info("Finished writing TRAP file $trapFile")
} catch (e: Exception) {
} catch (e: Throwable) {
manager.setHasError()
logger.error(
"Failed to extract '$shortName'. Partial TRAP file location is $trapTmpFile",
@@ -126,14 +127,16 @@ class ExternalDeclExtractor(
val nextBatch = ArrayList(externalDeclWorkList)
externalDeclWorkList.clear()
nextBatch.forEach { workPair ->
val (irDecl, possiblyLongSignature) = workPair
extractElement(irDecl, possiblyLongSignature, false) {
val (sym, possiblyLongSignature) = workPair
extractElement(sym, possiblyLongSignature, false) {
trapFileBW,
signature,
manager ->
val binaryPath = getIrDeclarationBinaryPath(irDecl)
val binaryPath = getSymbolBinaryPath(sym)
if (binaryPath == null) {
logger.errorElement("Unable to get binary path", irDecl)
sym.psi?.also {
logger.errorElement("Unable to get binary path", it)
} ?: logger.error("Unable to get binary path")
} else {
// We want our comments to be the first thing in the file,
// so start off with a PlainTrapWriter
@@ -161,40 +164,46 @@ class ExternalDeclExtractor(
KotlinFileExtractor(
logger,
ftw,
this,
/* OLD: KE1
null,
binaryPath,
manager,
this,
primitiveTypeMapping,
pluginContext,
KotlinFileExtractor.DeclarationStack(),
globalExtensionState
*/
)
if (irDecl is IrClass) {
if (sym is KaClassSymbol) {
// Populate a location and compilation-unit package for the file. This
// is similar to
// the beginning of `KotlinFileExtractor.extractFileContents` but
// without an `IrFile`
// to start from.
val pkg = irDecl.packageFqName?.asString() ?: ""
val pkg = sym.classId?.packageFqName?.asString() ?: ""
val pkgId = fileExtractor.extractPackage(pkg)
ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation())
ftw.writeCupackage(ftw.fileId, pkgId)
fileExtractor.extractClassSource(
irDecl,
extractDeclarations = !irDecl.isFileClass,
sym,
extractDeclarations = /* OLD: KE1 !sym.isFileClass */true,
/* OLD: KE1
extractStaticInitializer = false,
extractPrivateMembers = false,
extractFunctionBodies = false
*/
)
} else {
fileExtractor.extractDeclaration(
irDecl,
sym as KaDeclarationSymbol,
/* OLD: KE1
extractPrivateMembers = false,
extractFunctionBodies = false,
extractAnnotations = true
*/
)
}
}
@@ -204,4 +213,3 @@ class ExternalDeclExtractor(
output.writeTrapSet()
}
}
*/

View File

@@ -149,7 +149,7 @@ OLD: KE1
OLD: KE1
val globalExtensionState = KotlinExtractorGlobalState()
*/
doAnalysis(compression, trapDir, srcDir, loggerBase, dtw, compilation, invocationExtractionProblems, kotlinArgs)
doAnalysis(compression, trapDir, srcDir, loggerBase, dtw, compilation, invocationExtractionProblems, kotlinArgs, invocationTrapFile)
loggerBase.printLimitedDiagnosticCounts(dtw)
/*
OLD: KE1
@@ -177,7 +177,8 @@ private fun doAnalysis(
dtw: DiagnosticTrapWriter,
compilation: Label<DbCompilation>,
invocationExtractionProblems: ExtractionProblems,
args: List<String>
args: List<String>,
invocationTrapFile: String
) {
lateinit var sourceModule: KaSourceModule
val k2args: K2JVMCompilerArguments = parseCommandLineArguments(args.toList())
@@ -266,8 +267,8 @@ private fun doAnalysis(
/*
OLD: KE1
fileExtractionProblems,
invocationTrapFile,
*/
invocationTrapFile,
fileDiagnosticTrapWriter,
loggerBase,
checkTrapIdentical,
@@ -290,11 +291,8 @@ private fun doAnalysis(
// continue trying to extract everything else even if we get a
// stack overflow or an assertion failure in one file.
} catch (e: Throwable) {
/*
OLD: KE1
logger.error("Extraction failed while extracting '${psiFile.virtualFilePath}'.", e)
fileExtractionProblems.setNonRecoverableProblem()
*/
loggerBase.error(dtw, "Extraction failed while extracting '${psiFile.virtualFilePath}'.", e)
}
} else {
System.out.println("Warning: Not a KtFile")
@@ -455,8 +453,8 @@ private fun doFile(
/*
OLD: KE1
fileExtractionProblems: FileExtractionProblems,
invocationTrapFile: String,
*/
*/
invocationTrapFile: String,
fileDiagnosticTrapWriter: FileTrapWriter,
loggerBase: LoggerBase,
checkTrapIdentical: Boolean,
@@ -510,31 +508,35 @@ private fun doFile(
// Now elevate to a SourceFileTrapWriter, and populate the
// file information
val sftw = tw.makeSourceFileTrapWriter(srcFile, true)
/*
OLD: KE1
val externalDeclExtractor =
ExternalDeclExtractor(
logger,
compression,
invocationTrapFile,
srcFilePath,
primitiveTypeMapping,
pluginContext,
globalExtensionState,
fileDiagnosticTrapWriter.getDiagnosticTrapWriter()
)
val linesOfCode = LinesOfCode(logger, sftw, srcFile)
*/
val externalDeclExtractor =
ExternalDeclExtractor(
logger,
compression,
invocationTrapFile,
srcFilePath,
/*
OLD: KE1
primitiveTypeMapping,
pluginContext,
globalExtensionState,
*/
fileDiagnosticTrapWriter.getDiagnosticTrapWriter()
)
/* OLD: KE1
val linesOfCode = LinesOfCode(logger, sftw, srcFile)
*/
val fileExtractor =
KotlinFileExtractor(
logger,
sftw,
externalDeclExtractor,
/*
OLD: KE1
linesOfCode,
srcFilePath,
null,
externalDeclExtractor,
primitiveTypeMapping,
pluginContext,
KotlinFileExtractor.DeclarationStack(),
@@ -543,9 +545,6 @@ private fun doFile(
)
fileExtractor.extractFileContents(srcFile, sftw.fileId)
/*
OLD: KE1
externalDeclExtractor.extractExternalClasses()
*/
externalDeclExtractor.extractExternalClasses()
}
}

View File

@@ -86,12 +86,12 @@ context (KaSession)
open class KotlinFileExtractor(
override val logger: FileLogger,
override val tw: FileTrapWriter,
externalClassExtractor: ExternalDeclExtractor,
/*
OLD: KE1
val linesOfCode: LinesOfCode?,
val filePath: String,
dependencyCollector: OdasaOutput.TrapFileManager?,
externalClassExtractor: ExternalDeclExtractor,
primitiveTypeMapping: PrimitiveTypeMapping,
pluginContext: IrPluginContext,
val declarationStack: DeclarationStack,
@@ -101,10 +101,10 @@ open class KotlinFileExtractor(
KotlinUsesExtractor(
logger,
tw,
externalClassExtractor,
/*
OLD: KE1
dependencyCollector,
externalClassExtractor,
primitiveTypeMapping,
pluginContext,
globalExtensionState
@@ -117,14 +117,11 @@ open class KotlinFileExtractor(
val metaAnnotationSupport = MetaAnnotationSupport(logger, pluginContext, this)
*/
inline fun <T> with(kind: String, element: KtElement, f: () -> T): T {
val name =
when (element) {
is KtFile -> element.virtualFilePath
is KtNamed -> element.getNameAsName()?.asString() ?: "<missing name>"
else -> "<no name>"
}
val loc = tw.getLocationString(element)
inline fun <T> with(kind: String, element: PsiElement, f: () -> T) = with(kind, PsiElementOrSymbol.of(element), f)
inline fun <T> with(kind: String, element: KaSymbol, f: () -> T) = with(kind, PsiElementOrSymbol.of(element), f)
inline fun <T> with(kind: String, element: PsiElementOrSymbol, f: () -> T): T {
val name = element.getName()
val loc = element.getLocationString(tw)
val context = logger.loggerState.extractorContextStack
context.push(ExtractorContext(kind, element, name, loc))
try {
@@ -299,7 +296,7 @@ open class KotlinFileExtractor(
extractAnnotations: Boolean
*/
) {
with("declaration", declaration.psiSafe() ?: TODO()) {
with("declaration", declaration) {
/*
OLD: KE1
if (!shouldExtractDecl(declaration, extractPrivateMembers)) return

View File

@@ -42,10 +42,11 @@ context (KaSession)
open class KotlinUsesExtractor(
open val logger: Logger,
open val tw: TrapWriter,
val externalClassExtractor: ExternalDeclExtractor,
/*
OLD: KE1
val dependencyCollector: OdasaOutput.TrapFileManager?,
val externalClassExtractor: ExternalDeclExtractor,
val primitiveTypeMapping: PrimitiveTypeMapping,
val pluginContext: IrPluginContext,
val globalExtensionState: KotlinExtractorGlobalState
@@ -317,12 +318,6 @@ open class KotlinUsesExtractor(
return UseClassInstanceResult(classTypeResult, extractClass)
}
private fun extractClassLaterIfExternal(c: IrClass) {
if (isExternalDeclaration(c)) {
extractExternalClassLater(c)
}
}
private fun extractExternalEnclosingClassLater(d: IrDeclaration) {
when (val parent = d.parent) {
is IrClass -> extractExternalClassLater(parent)
@@ -516,15 +511,6 @@ open class KotlinUsesExtractor(
} ?: f
}
private fun tryReplaceType(
cBeforeReplacement: IrClass,
argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?
): Pair<IrClass, List<IrTypeArgument>?> {
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
val p = tryReplaceParcelizeRawType(c)
return Pair(p?.first ?: c, p?.second ?: argsIncludingOuterClassesBeforeReplacement)
}
*/
/*
@@ -1313,58 +1299,6 @@ open class KotlinUsesExtractor(
data class ClassLabelResults(val classLabel: String /* TODO , val shortName: String */)
/*
OLD: KE1
fun getTypeParameterParentLabel(param: IrTypeParameter) =
param.parent.let {
when (it) {
is IrClass -> useClassSource(it)
is IrFunction ->
(if (this is KotlinFileExtractor)
this.declarationStack
.findOverriddenAttributes(it)
?.takeUnless {
// When extracting the `static fun f$default(...)` that accompanies
// `fun <T> f(val x: T? = defaultExpr, ...)`,
// `f$default` has no type parameters, and so there is no
// `f$default::T` to refer to.
// We have no good way to extract references to `T` in
// `defaultExpr`, so we just fall back on describing it
// in terms of `f::T`, even though that type variable ought to be
// out of scope here.
attribs ->
attribs.typeParameters?.isEmpty() == true
}
?.id
else null) ?: useFunction(it, noReplace = true)
else -> {
logger.error("Unexpected type parameter parent $it")
null
}
}
}
fun getTypeParameterLabel(param: IrTypeParameter): String {
// Use this instead of `useDeclarationParent` so we can use useFunction with noReplace =
// true,
// ensuring that e.g. a method-scoped type variable declared on kotlin.String.transform <R>
// gets
// a different name to the corresponding java.lang.String.transform <R>, even though
// useFunction
// will usually replace references to one function with the other.
val parentLabel = getTypeParameterParentLabel(param)
return "@\"typevar;{$parentLabel};${param.name}\""
}
private fun useTypeParameter(param: IrTypeParameter) =
TypeResult(
tw.getLabelFor<DbTypevariable>(getTypeParameterLabel(param)),
useType(eraseTypeParameter(param)).javaResult.signature,
param.name.asString()
)
*/
private fun extractModifier(m: String): Label<DbModifier> {
val modifierLabel = "@\"modifier;$m\""
val id: Label<DbModifier> = tw.getLabelFor(modifierLabel, { tw.writeModifiers(it, m) })

View File

@@ -304,27 +304,24 @@ abstract class TrapWriter(
}
}
/*
OLD: KE1
/**
* Gets a FileTrapWriter like this one (using the same label manager, writer etc), but using the
* given `filePath` for locations.
*/
fun makeFileTrapWriter(filePath: String, populateFileTables: Boolean) =
FileTrapWriter(
basicLogger,
lm,
bw,
this.getDiagnosticTrapWriter(),
filePath,
populateFileTables
)
/**
* Gets a FileTrapWriter like this one (using the same label manager, writer etc), but using the
* given `filePath` for locations.
*/
fun makeFileTrapWriter(filePath: String, populateFileTables: Boolean) =
FileTrapWriter(
basicLogger,
lm,
bw,
this.getDiagnosticTrapWriter(),
filePath,
populateFileTables
)
/**
* Gets a FileTrapWriter like this one (using the same label manager, writer etc), but using the
* given `IrFile` for locations.
*/
*/
/**
* Gets a FileTrapWriter like this one (using the same label manager, writer etc), but using the
* given `IrFile` for locations.
*/
fun makeSourceFileTrapWriter(file: KtFile, populateFileTables: Boolean) =
SourceFileTrapWriter(
basicLogger,

View File

@@ -6,6 +6,7 @@ import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.psi.KtElement
context(KaSession)
@OptIn(KaExperimentalApi::class)
@@ -19,7 +20,7 @@ fun KotlinFileExtractor.extractClassSource(
extractFunctionBodies: Boolean
*/
): Label<out DbClassorinterface> {
with("class source", c.psiSafe() ?: TODO()) {
with("class source", c) {
// OLD: KE1: DeclarationStackAdjuster(c).use {
val id = useClassSource(c)
val pkg = c.classId?.packageFqName?.asString() ?: ""
@@ -40,8 +41,8 @@ fun KotlinFileExtractor.extractClassSource(
kind != KaClassKind.CLASS &&
kind != KaClassKind.OBJECT //&&
//OLD KE1: kind != ClassKind.ENUM_ENTRY
) {
logger.warnElement("Unrecognised class kind $kind", c.psiSafe() ?: TODO())
) else {
logger.warnElement("Unrecognised class kind $kind", c)
}
/*
@@ -56,7 +57,7 @@ fun KotlinFileExtractor.extractClassSource(
}
}
val locId = tw.getLocation(c.psiSafe() ?: TODO())
val locId = PsiElementOrSymbol.of(c).getLocation(tw)
tw.writeHasLocation(id, locId)
// OLD: KE1
@@ -73,7 +74,7 @@ fun KotlinFileExtractor.extractClassSource(
if (getter == null) {
logger.warnElement(
"Expected an annotation property to have a getter",
it.psiSafe() ?: TODO()
it
)
} else {
extractFunction(
@@ -187,12 +188,10 @@ fun KotlinFileExtractor.extractClassSource(
// `args` can be null to describe a raw generic type.
// For non-generic types it will be zero-length list.
*/
context(KaSession)
private fun KotlinUsesExtractor.getClassLabel(
c: KaClassSymbol,
/*
OLD: KE1
argsIncludingOuterClasses: List<IrTypeArgument>?
*/
argsIncludingOuterClasses: List<Nothing>?
): ClassLabelResults {
val unquotedLabel = getUnquotedClassLabel(c /* TODO , argsIncludingOuterClasses */)
return ClassLabelResults("@\"class;${unquotedLabel.classLabel}\"" /* TODO , unquotedLabel.shortName */)
@@ -201,30 +200,67 @@ private fun KotlinUsesExtractor.getClassLabel(
context(KaSession)
fun KotlinUsesExtractor.useClassSource(c: KaClassSymbol): Label<out DbClassorinterface> {
// For source classes, the label doesn't include any type arguments
val id = addClassLabel(c)
val id = addClassLabel(c, listOf())
return id
}
/**
* Return a replacement class name and type arguments for cBeforeReplacement<argsIncludingOuterClassesBeforeReplacement>
*
* These could include replacing Android synthetic classes or Parcelize raw types that shouldn't appear in the database
* as they appear to the Kotlin compiler.
*
* TODO: verify how these sorts of classes appear via the analysis API
*/
private fun tryReplaceType(
cBeforeReplacement: KaClassSymbol,
argsIncludingOuterClassesBeforeReplacement: List<Nothing>?
): Pair<KaClassSymbol, List<Nothing>?> {
return Pair(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
/*
OLD: KE1
val c = tryReplaceAndroidSyntheticClass(cBeforeReplacement)
val p = tryReplaceParcelizeRawType(c)
return Pair(p?.first ?: c, p?.second ?: argsIncludingOuterClassesBeforeReplacement)
*/
}
private fun isExternalDeclaration(d: KaSymbol): Boolean {
return d.origin == KaSymbolOrigin.LIBRARY || d.origin == KaSymbolOrigin.JAVA_LIBRARY
}
private fun KotlinUsesExtractor.extractExternalClassLater(c: KaClassSymbol) {
/* OLD: KE1
dependencyCollector?.addDependency(c)
*/
externalClassExtractor.extractLater(c)
}
private fun KotlinUsesExtractor.extractClassLaterIfExternal(c: KaClassSymbol) {
if (isExternalDeclaration(c)) {
extractExternalClassLater(c)
}
}
// `typeArgs` can be null to describe a raw generic type.
// For non-generic types it will be zero-length list.
// TODO: Should this be private?
context(KaSession)
fun KotlinUsesExtractor.addClassLabel(
c: KaClassSymbol, // TODO cBeforeReplacement: IrClass,
cBeforeReplacement: KaClassSymbol, // TODO cBeforeReplacement: IrClass,
argsIncludingOuterClassesBeforeReplacement: List<Nothing>?,
/*
OLD: KE1
argsIncludingOuterClassesBeforeReplacement: List<IrTypeArgument>?,
inReceiverContext: Boolean = false
*/
): Label<out DbClassorinterface> {
/*
OLD: KE1
val replaced =
tryReplaceType(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
val replacedClass = replaced.first
val replacedArgsIncludingOuterClasses = replaced.second
val replaced =
tryReplaceType(cBeforeReplacement, argsIncludingOuterClassesBeforeReplacement)
val replacedClass = replaced.first
val replacedArgsIncludingOuterClasses = replaced.second
*/
val classLabelResult = getClassLabel(c /* TODO replacedClass, replacedArgsIncludingOuterClasses */)
val classLabelResult = getClassLabel(replacedClass, replacedArgsIncludingOuterClasses)
/*
OLD: KE1
@@ -237,16 +273,8 @@ fun KotlinUsesExtractor.addClassLabel(
OLD: KE1
instanceSeenBefore = false
extractClassLaterIfExternal(replacedClass)
*/
// TODO: This shouldn't be done here, but keeping it simple for now
val classId = c.classId
if (classId == null) {
TODO() // this is a local class
} else {
val pkgId = extractPackage(classId.packageFqName.asString())
tw.writeClasses_or_interfaces(it, classId.relativeClassName.asString(), pkgId, it)
}
extractClassLaterIfExternal(replacedClass)
}
/*
@@ -297,6 +325,7 @@ OLD: KE1
* it will be zero-length list.
*/
*/
context(KaSession)
private fun KotlinUsesExtractor.getUnquotedClassLabel(
c: KaClassSymbol,
/*
@@ -309,25 +338,32 @@ private fun KotlinUsesExtractor.getUnquotedClassLabel(
TODO() // This is a local class
}
val pkg = classId.packageFqName.asString()
val cls = classId.relativeClassName.asString()
val cls = classId.shortClassName.asString()
val label =
/*
OLD: KE1
if (c.isAnonymousObject) "{${useAnonymousClass(c).javaResult.id}}"
else
when (val parent = c.parent) {
is IrClass -> {
"${getUnquotedClassLabel(parent, listOf()).classLabel}\$$cls"
}
is IrFunction -> {
"{${useFunction<DbMethod>(parent)}}.$cls"
}
is IrField -> {
"{${useField(parent)}}.$cls"
}
else -> {
*/
if (pkg.isEmpty()) cls else "$pkg.$cls"
/* OLD: KE1
if (c.isAnonymousObject) "{${useAnonymousClass(c).javaResult.id}}"
else
*/
when (val parent = c.containingSymbol) {
is KaClassSymbol -> {
"${getUnquotedClassLabel(parent).classLabel}\$$cls"
}
is KaFunctionSymbol -> {
"{${useFunction<DbMethod>(parent)}}.$cls"
}
is KaPropertySymbol -> {
TODO()
/* OLD: KE1
"{${useField(parent)}}.$cls"
*/
}
else -> {
if (pkg.isEmpty()) cls else "$pkg.$cls"
}
}
/*
OLD: KE1
}

View File

@@ -166,6 +166,7 @@ OLD: KE1
}
*/
context(KaSession)
fun KotlinFileExtractor.extractConstantInteger(
text: String,
t: KaType,
@@ -1576,6 +1577,7 @@ private fun KotlinFileExtractor.extractVariableAccess(
}
}
context(KaSession)
private fun KotlinFileExtractor.extractVariableAccess(
variable: Label<out DbVariable>?,
type: KaType,

View File

@@ -409,7 +409,7 @@ private fun KotlinFileExtractor.forceExtractFunction(
overriddenAttributes: OverriddenFunctionAttributes? = null
*/
): Label<out DbCallable> {
with("function", f.psiSafe() ?: TODO()) {
with("function", f) {
/*
OLD: KE1
DeclarationStackAdjuster(f, overriddenAttributes).use {
@@ -508,8 +508,9 @@ OLD: KE1
} ?: adjustedReturnType
*/
val functionSyntax = f.psi as? KtDeclarationWithBody
val locId =
val locId = functionSyntax?.let {
tw.getLocation(functionSyntax ?: TODO())
} ?: tw.getWholeFileLocation()
/*
OLD: KE1
overriddenAttributes?.sourceLoc
@@ -640,6 +641,7 @@ OLD: KE1
}
}
context(KaSession)
fun KotlinFileExtractor.extractValueParameter(
id: Label<out DbParam>,
t: KaType,
@@ -672,6 +674,7 @@ fun KotlinFileExtractor.extractValueParameter(
}
// TODO: Can this be inlined?
context(KaSession)
private fun KotlinFileExtractor.extractMethod(
id: Label<out DbMethod>,
/*
@@ -724,6 +727,16 @@ private fun KotlinFileExtractor.extractMethod(
*/
}
context(KaSession)
fun <T : DbCallable> KotlinUsesExtractor.useFunction(
f: KaFunctionSymbol,
/*
OLD: KE1
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
noReplace: Boolean = false
*/
): Label<out T> = useFunction(f, useDeclarationParentOf(f, true)!! /* TODO */)
context(KaSession)
fun <T : DbCallable> KotlinUsesExtractor.useFunction(
f: KaFunctionSymbol,

View File

@@ -216,6 +216,7 @@ private val nullableAnyArrayType: KaType
* Adds a function named `invoke` with the specified parameter types and return type to the
* class identified by `parentId`.
*/
context(KaSession)
private fun KotlinFileExtractor.addFunctionInvoke(
methodId: Label<DbMethod>,
parameterTypes: List<KaType>,
@@ -237,6 +238,7 @@ private fun KotlinFileExtractor.addFunctionInvoke(
* Extracts a function with the given name, parameter types, return type, containing type, and
* location.
*/
context(KaSession)
private fun KotlinFileExtractor.addFunctionManual(
methodId: Label<DbMethod>,
name: String,

View File

@@ -1,15 +1,19 @@
package com.github.codeql
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.analysis.api.types.KaFlexibleType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeParameterType
context(KaSession)
private fun KotlinUsesExtractor.useClassType(
c: KaClassType
): TypeResults {
// TODO: this cast is unsafe; .symbol is actually a KaClassLikeSymbol
val classId = addClassLabel(c.symbol as KaClassSymbol)
val classId = addClassLabel(c.symbol as KaClassSymbol, listOf<Nothing>())
val javaResult = TypeResult(classId /* , TODO, TODO */)
val kotlinTypeId =
tw.getLabelFor<DbKt_class_type>("@\"kt_class;{$classId}\"") {
@@ -19,6 +23,60 @@ private fun KotlinUsesExtractor.useClassType(
return TypeResults(javaResult, kotlinResult)
}
context(KaSession)
fun KotlinUsesExtractor.getTypeParameterParentLabel(param: KaTypeParameterType) =
param.symbol.containingSymbol?.let {
when (it) {
is KaClassSymbol -> useClassSource(it)
is KaFunctionSymbol ->
/* OLD: KE1
(if (this is KotlinFileExtractor)
this.declarationStack
.findOverriddenAttributes(it)
?.takeUnless {
// When extracting the `static fun f$default(...)` that accompanies
// `fun <T> f(val x: T? = defaultExpr, ...)`,
// `f$default` has no type parameters, and so there is no
// `f$default::T` to refer to.
// We have no good way to extract references to `T` in
// `defaultExpr`, so we just fall back on describing it
// in terms of `f::T`, even though that type variable ought to be
// out of scope here.
attribs ->
attribs.typeParameters?.isEmpty() == true
}
?.id
else null) ?:
*/
useFunction(it, useDeclarationParentOf(it, true) ?: TODO() /* OLD: KE1 noReplace = true */)
else -> {
logger.error("Unexpected type parameter parent $it")
null
}
}
}
context(KaSession)
fun KotlinUsesExtractor.getTypeParameterLabel(param: KaTypeParameterType): String {
// Use this instead of `useDeclarationParent` so we can use useFunction with noReplace = true,
// ensuring that e.g. a method-scoped type variable declared on kotlin.String.transform<R> gets
// a different name to the corresponding java.lang.String.transform<R>, even though
// useFunction will usually replace references to one function with the other.
val parentLabel = getTypeParameterParentLabel(param)
return "@\"typevar;{$parentLabel};${param.name}\""
}
context(KaSession)
private fun KotlinUsesExtractor.useTypeParameterType(param: KaTypeParameterType) =
TypeResult(
tw.getLabelFor<DbTypevariable>(getTypeParameterLabel(param)),
/* OLD: KE1
useType(eraseTypeParameter(param)).javaResult.signature,
param.name.asString()
*/
)
context(KaSession)
fun KotlinUsesExtractor.useType(t: KaType?, context: TypeContext = TypeContext.OTHER): TypeResults {
val tr = when (t) {
null -> {
@@ -27,6 +85,7 @@ fun KotlinUsesExtractor.useType(t: KaType?, context: TypeContext = TypeContext.O
}
is KaClassType -> useClassType(t)
is KaFlexibleType -> useType(t.lowerBound) // TODO: take a more reasoned choice here
is KaTypeParameterType -> TypeResults(useTypeParameterType(t), extractErrorType().kotlinResult /* TODO */)
else -> TODO()
}
val javaResult = tr.javaResult
@@ -34,7 +93,7 @@ fun KotlinUsesExtractor.useType(t: KaType?, context: TypeContext = TypeContext.O
val abbreviation = t.abbreviatedType
val kotlinResultAlias = if (abbreviation == null) kotlinResultBase else {
// TODO: this cast is unsafe; .symbol is actually a KaClassLikeSymbol
val classId = addClassLabel(abbreviation.symbol as KaClassSymbol)
val classId = addClassLabel(abbreviation.symbol as KaClassSymbol, listOf<Nothing>() /* TODO */)
val kotlinBaseTypeId = kotlinResultBase.id
val kotlinAliasTypeId =
tw.getLabelFor<DbKt_type_alias>("@\"kt_type_alias;{$classId};{$kotlinBaseTypeId}\"") {

View File

@@ -1,7 +1,5 @@
package com.github.codeql
/*
OLD: KE1
// Functions copied from stdlib/jdk7/src/kotlin/AutoCloseable.kt, which is not available within
// kotlinc,
// but allows the `.use` pattern to be applied to JDK7 AutoCloseables:
@@ -47,4 +45,3 @@ fun AutoCloseable?.closeFinallyAC(cause: Throwable?) =
cause.addSuppressed(closeException)
}
}
*/

View File

@@ -1,5 +1,13 @@
package com.github.codeql
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaNamedClassSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaNamedSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*
/*
@@ -19,15 +27,18 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
*/
// Adapted from Kotlin's interpreter/Utils.kt function 'internalName'
// Translates class names into their JLS section 13.1 binary name,
// and declarations within them into the parent class' JLS 13.1 name as
// specified above, followed by a `$` separator and then the short name
// for `that`.
private fun getName(d: IrDeclarationWithName) =
private fun getName(d: KaNamedSymbol) =
d.name.identifier
/* OLD: KE1
(d as? IrAnnotationContainer)?.let { getJvmName(it) } ?: d.name.asString()
*/
*/
fun getFileClassName(f: KtFile): String =
null /* OLD: KE1: getJvmName(f) */
@@ -36,27 +47,31 @@ fun getFileClassName(f: KtFile): String =
.replaceFirst(Regex("""\.kt$"""), "")
.replaceFirstChar { it.uppercase() }) + "Kt")
/*
OLD: KE1
fun getIrElementBinaryName(that: IrElement): String {
if (that is IrFile) {
private fun getBinaryName(cid: ClassId): String =
(cid.outerClassId?.let { ocid -> "${getBinaryName(ocid)}${'$'}" } ?: "${cid.packageFqName}.") + cid.shortClassName
fun getSymbolBinaryName(that: KaSymbol): String {
if (that is KaFileSymbol) {
return "TODO"
/* OLD: KE1
val shortName = getFileClassName(that)
val pkg = that.packageFqName.asString()
return if (pkg.isEmpty()) shortName else "$pkg.$shortName"
*/
}
/* OLD: KE1
if (that !is IrDeclaration) {
return "(unknown-name)"
}
*/
val shortName =
when (that) {
is IrDeclarationWithName -> getName(that)
else -> "(unknown-name)"
}
val internalName =
(that as? KaNamedClassSymbol)?.classId?.let { getBinaryName(it) }
?: "(unknown-binary-name)"
/* OLD: KE1
if (that !is KaClassSymbol) {
val internalName = StringBuilder(shortName)
if (that !is IrClass) {
val parent = that.parent
if (parent is IrFile) {
// Note we'll fall through and do the IrPackageFragment case as well, since IrFile <:
@@ -64,22 +79,14 @@ fun getIrElementBinaryName(that: IrElement): String {
internalName.insert(0, getFileClassName(parent) + "$")
}
}
*/
generateSequence(that.parent) { (it as? IrDeclaration)?.parent }
.forEach {
when (it) {
is IrClass -> internalName.insert(0, getName(it) + "$")
is IrPackageFragment ->
it.packageFqName
.asString()
.takeIf { fqName -> fqName.isNotEmpty() }
?.let { fqName -> internalName.insert(0, "$fqName.") }
}
}
return internalName.toString()
return internalName
}
fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? {
fun getIrClassVirtualFile(c: KaClassSymbol): VirtualFile? {
return c.psi?.containingFile?.virtualFile
/* OLD: KE1
val cSource = irClass.source
// Don't emit a location for multi-file classes until we're sure we can cope with different
// declarations
@@ -113,10 +120,11 @@ fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? {
}
}
return null
*/
}
private fun getRawIrClassBinaryPath(irClass: IrClass) =
getIrClassVirtualFile(irClass)?.let {
private fun getRawClassSymbolBinaryPath(c: KaClassSymbol) =
getIrClassVirtualFile(c)?.let {
val path = it.path
if (it.fileSystem.protocol == StandardFileSystems.JRT_PROTOCOL)
// For JRT files, which we assume to be the JDK, hide the containing JAR path to match the
@@ -125,16 +133,18 @@ private fun getRawIrClassBinaryPath(irClass: IrClass) =
else path
}
fun getIrClassBinaryPath(irClass: IrClass): String {
return getRawIrClassBinaryPath(irClass)
fun getClassSymbolBinaryPath(c: KaClassSymbol): String {
return getRawClassSymbolBinaryPath(c)
// Otherwise, make up a fake location:
?: getUnknownBinaryLocation(getIrElementBinaryName(irClass))
?: getUnknownBinaryLocation(getSymbolBinaryName(c))
}
fun getIrDeclarationBinaryPath(d: IrDeclaration): String? {
if (d is IrClass) {
return getIrClassBinaryPath(d)
fun getSymbolBinaryPath(d: KaSymbol): String? {
if (d is KaClassSymbol) {
return getClassSymbolBinaryPath(d)
}
/*
OLD: KE1
val parentClass = d.parentClassOrNull
if (parentClass != null) {
return getIrClassBinaryPath(parentClass)
@@ -146,6 +156,7 @@ fun getIrDeclarationBinaryPath(d: IrDeclaration): String? {
return getUnknownBinaryLocation(fqName.asString())
}
}
*/
return null
}
@@ -153,6 +164,7 @@ private fun getUnknownBinaryLocation(s: String): String {
return "/!unknown-binary-location/${s.replace(".", "/")}.class"
}
/* OLD: KE1
fun getJavaEquivalentClassId(c: IrClass) =
c.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it) }
*/

View File

@@ -1,6 +1,12 @@
package com.github.codeql
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaNamedSymbol
import org.jetbrains.kotlin.analysis.api.symbols.psiSafe
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamed
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
@@ -99,9 +105,38 @@ class LogMessage(private val kind: String, private val message: String) {
}
}
sealed class PsiElementOrSymbol {
abstract fun getLocationString(ftw: FileTrapWriter): String
abstract fun getLocation(ftw: FileTrapWriter): Label<DbLocation>
abstract fun getName(): String
companion object {
fun of(e: PsiElement) = PsiElementWrapper(e)
fun of(e: KaSymbol) = e.psiSafe<KtElement>()?.let { of(it) } ?: SymbolWrapper(e)
}
}
data class PsiElementWrapper(val e: PsiElement) : PsiElementOrSymbol() {
override fun getLocationString(ftw: FileTrapWriter) = ftw.getLocationString(e)
override fun getLocation(ftw: FileTrapWriter) = ftw.getLocation(e)
override fun getName() = when (e) {
is KtFile -> e.virtualFilePath
is KtNamed -> e.nameAsName?.asString() ?: "<missing name>"
else -> "<no name>"
}
}
data class SymbolWrapper(val e: KaSymbol) : PsiElementOrSymbol() {
override fun getLocationString(ftw: FileTrapWriter) = "file://${ftw.filePath}"
override fun getLocation(ftw: FileTrapWriter) = ftw.getWholeFileLocation()
override fun getName() = when (e) {
is KaNamedSymbol -> e.name.asString()
else -> "<no name>"
}
}
data class ExtractorContext(
val kind: String,
val element: PsiElement,
val element: PsiElementOrSymbol,
val name: String,
val loc: String
)
@@ -286,6 +321,10 @@ class LoggerBase(val diagnosticCounter: DiagnosticCounter) : BasicLogger {
error(dtw, msg, extraInfo, null)
}
fun error(dtw: DiagnosticTrapWriter, msg: String, exn: Throwable) {
error(dtw, msg, exn.stackTraceToString())
}
fun error(dtw: DiagnosticTrapWriter, msg: String, extraInfo: String?, loggerState: LoggerState?) {
if (verbosity >= 1) {
diagnostic(dtw, Severity.Error, msg, extraInfo, loggerState)
@@ -385,7 +424,7 @@ open class Logger(val loggerBase: LoggerBase, val dtw: DiagnosticTrapWriter) : B
}
fun error(msg: String, exn: Throwable) {
error(msg, exn.stackTraceToString())
loggerBase.error(dtw, msg, exn)
}
}
@@ -404,9 +443,9 @@ class FileLogger(loggerBase: LoggerBase, val ftw: FileTrapWriter, fileNumber: In
loggerBase.warn(dtw, msg, extraInfo, loggerState)
}
fun warnElement(msg: String, element: PsiElement/* TODO , exn: Throwable? = null */) {
val locationString = ftw.getLocationString(element)
val mkLocationId = { ftw.getLocation(element) }
fun warnElement(msg: String, element: PsiElementOrSymbol /* TODO , exn: Throwable? = null */) {
val locationString = element.getLocationString(ftw)
val mkLocationId = { element.getLocation(ftw) }
loggerBase.diagnostic(
ftw.getDiagnosticTrapWriter(),
Severity.Warn,
@@ -418,13 +457,16 @@ class FileLogger(loggerBase: LoggerBase, val ftw: FileTrapWriter, fileNumber: In
)
}
fun warnElement(msg: String, element: PsiElement /* TODO , exn: Throwable? = null */) = warnElement(msg, PsiElementOrSymbol.of(element))
fun warnElement(msg: String, element: KaSymbol /* TODO , exn: Throwable? = null */) = warnElement(msg, PsiElementOrSymbol.of(element))
override fun error(dtw: DiagnosticTrapWriter, msg: String, extraInfo: String?) {
loggerBase.error(dtw, msg, extraInfo, loggerState)
}
fun errorElement(msg: String, element: PsiElement /* TODO , exn: Throwable? = null */) {
val locationString = ftw.getLocationString(element)
val mkLocationId = { ftw.getLocation(element) }
fun errorElement(msg: String, element: PsiElementOrSymbol /* TODO , exn: Throwable? = null */) {
val locationString = element.getLocationString(ftw)
val mkLocationId = { element.getLocation(ftw) }
loggerBase.diagnostic(
ftw.getDiagnosticTrapWriter(),
Severity.Error,
@@ -435,4 +477,7 @@ class FileLogger(loggerBase: LoggerBase, val ftw: FileTrapWriter, fileNumber: In
mkLocationId
)
}
fun errorElement(msg: String, element: PsiElement /* TODO , exn: Throwable? = null */) = errorElement(msg, PsiElementOrSymbol.of(element))
fun errorElement(msg: String, element: KaSymbol /* TODO , exn: Throwable? = null */) = errorElement(msg, PsiElementOrSymbol.of(element))
}