Merge pull request #11510 from smowton/smowton/fix/kotlin-populate-source-class-files

Kotlin: stub trap .class files when extracting a class from Kotlin source
This commit is contained in:
Chris Smowton
2022-12-07 14:33:42 +00:00
committed by GitHub
19 changed files with 230 additions and 231 deletions

View File

@@ -19,9 +19,10 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.github.codeql.Logger;
import static com.github.codeql.ClassNamesKt.getIrDeclBinaryName;
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 com.intellij.openapi.vfs.VirtualFile;
@@ -212,20 +213,19 @@ public class OdasaOutput {
PathTransformer.std().fileAsDatabaseString(file) + ".trap.gz");
}
private File getTrapFileForDecl(IrDeclaration sym, String signature) {
private File getTrapFileForDecl(IrElement sym, String signature) {
if (currentSpecFileEntry == null)
return null;
return trapFileForDecl(sym, signature);
}
private File trapFileForDecl(IrDeclaration sym, String signature) {
private File trapFileForDecl(IrElement sym, String signature) {
return FileUtil.fileRelativeTo(currentSpecFileEntry.getTrapFolder(),
trapFilePathForDecl(sym, signature));
}
private String trapFilePathForDecl(IrDeclaration sym, String signature) {
String binaryName = getIrDeclBinaryName(sym);
String binaryNameWithSignature = binaryName + signature;
private String trapFilePathForDecl(IrElement sym, String signature) {
String binaryName = getIrElementBinaryName(sym);
// TODO: Reinstate this?
//if (getTrackClassOrigins())
// classId += "-" + StringDigestor.digest(sym.getSourceFileId());
@@ -241,7 +241,7 @@ public class OdasaOutput {
* Deletion of existing trap files.
*/
private void deleteTrapFileAndDependencies(IrDeclaration sym, String signature) {
private void deleteTrapFileAndDependencies(IrElement sym, String signature) {
File trap = trapFileForDecl(sym, signature);
if (trap.exists()) {
trap.delete();
@@ -269,7 +269,7 @@ public class OdasaOutput {
* Any unique suffix needed to distinguish `sym` from other declarations with the same name.
* For functions for example, this means its parameter signature.
*/
private TrapFileManager getMembersWriterForDecl(File trap, File trapFileBase, TrapClassVersion trapFileVersion, IrDeclaration sym, String signature) {
private TrapFileManager getMembersWriterForDecl(File trap, File trapFileBase, TrapClassVersion trapFileVersion, IrElement sym, String signature) {
if (use_trap_locking) {
TrapClassVersion currVersion = TrapClassVersion.fromSymbol(sym, log);
String shortName = sym instanceof IrDeclarationWithName ? ((IrDeclarationWithName)sym).getName().asString() : "(name unknown)";
@@ -326,7 +326,7 @@ public class OdasaOutput {
return trapWriter(trap, sym, signature);
}
private TrapFileManager trapWriter(File trapFile, IrDeclaration sym, String signature) {
private TrapFileManager trapWriter(File trapFile, IrElement sym, String signature) {
if (!trapFile.getName().endsWith(".trap.gz"))
throw new CatastrophicError("OdasaOutput only supports writing to compressed trap files");
String relative = FileUtil.relativePath(trapFile, currentSpecFileEntry.getTrapFolder());
@@ -335,7 +335,7 @@ public class OdasaOutput {
return concurrentWriter(trapFile, relative, log, sym, signature);
}
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, IrDeclaration sym, String signature) {
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, IrElement sym, String signature) {
if (trapFile.exists())
return null;
return new TrapFileManager(trapFile, relative, true, log, sym, signature);
@@ -345,11 +345,11 @@ public class OdasaOutput {
private TrapDependencies trapDependenciesForClass;
private File trapFile;
private IrDeclaration sym;
private IrElement sym;
private String signature;
private boolean hasError = false;
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, IrDeclaration sym, String signature) {
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, IrElement sym, String signature) {
trapDependenciesForClass = new TrapDependencies(relative);
this.trapFile = trapFile;
this.sym = sym;
@@ -360,7 +360,7 @@ public class OdasaOutput {
return trapFile;
}
public void addDependency(IrDeclaration dep, String signature) {
public void addDependency(IrElement dep, String signature) {
trapDependenciesForClass.addDependency(trapFilePathForDecl(dep, signature));
}
@@ -422,7 +422,7 @@ public class OdasaOutput {
* previously set by a call to {@link OdasaOutput#setCurrentSourceFile(File)}.
*/
public TrapLocker getTrapLockerForCurrentSourceFile() {
return new TrapLocker((IrClass)null, null);
return new TrapLocker((IrClass)null, null, true);
}
/**
@@ -460,19 +460,19 @@ public class OdasaOutput {
*
* @return a {@link TrapLocker} for the trap file corresponding to the given class symbol.
*/
public TrapLocker getTrapLockerForDecl(IrDeclaration sym, String signature) {
return new TrapLocker(sym, signature);
public TrapLocker getTrapLockerForDecl(IrElement sym, String signature, boolean fromSource) {
return new TrapLocker(sym, signature, fromSource);
}
public class TrapLocker implements AutoCloseable {
private final IrDeclaration sym;
private final IrElement sym;
private final File trapFile;
// trapFileBase is used when doing lockless TRAP file writing.
// It is trapFile without the #metadata.trap.gz suffix.
private File trapFileBase = null;
private TrapClassVersion trapFileVersion = null;
private final String signature;
private TrapLocker(IrDeclaration decl, String signature) {
private TrapLocker(IrElement decl, String signature, boolean fromSource) {
this.sym = decl;
this.signature = signature;
if (sym==null) {
@@ -485,7 +485,10 @@ public class OdasaOutput {
} else {
// We encode the metadata into the filename, so that the
// TRAP filenames for different metadatas don't overlap.
trapFileVersion = TrapClassVersion.fromSymbol(sym, log);
if (fromSource)
trapFileVersion = new TrapClassVersion(0, 0, 0, "kotlin");
else
trapFileVersion = TrapClassVersion.fromSymbol(sym, log);
String baseName = normalTrapFile.getName().replace(".trap.gz", "");
// If a class has lots of inner classes, then we get lots of files
// in a single directory. This makes our directory listings later slow.
@@ -717,11 +720,18 @@ public class OdasaOutput {
return vf.getTimeStamp();
}
private static TrapClassVersion fromSymbol(IrDeclaration sym, Logger log) {
VirtualFile vf = sym instanceof IrClass ? getIrClassVirtualFile((IrClass)sym) :
sym.getParent() instanceof IrClass ? getIrClassVirtualFile((IrClass)sym.getParent()) :
null;
if(vf == null)
private static VirtualFile getVirtualFileIfClass(IrElement e) {
if (e instanceof IrClass)
return getIrClassVirtualFile((IrClass)e);
else
return null;
}
private static TrapClassVersion fromSymbol(IrElement sym, Logger log) {
VirtualFile vf = getVirtualFileIfClass(sym);
if (vf == null && sym instanceof IrDeclaration)
vf = getVirtualFileIfClass(((IrDeclaration)sym).getParent());
if (vf == null)
return new TrapClassVersion(-1, 0, 0, null);
final int[] versionStore = new int[1];

View File

@@ -1,16 +1,14 @@
package com.github.codeql
import com.github.codeql.utils.isExternalDeclaration
import com.github.codeql.utils.isExternalFileClassMember
import com.semmle.extractor.java.OdasaOutput
import com.semmle.util.data.StringDigestor
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.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.isFileClass
import org.jetbrains.kotlin.ir.util.packageFqName
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.name.FqName
import java.io.BufferedWriter
import java.io.File
import java.util.ArrayList
import java.util.HashSet
@@ -25,87 +23,103 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
val propertySignature = ";property"
val fieldSignature = ";field"
val output = OdasaOutput(false, logger).also {
it.setCurrentSourceFile(File(sourceFilePath))
}
fun extractLater(d: IrDeclarationWithName, signature: String): Boolean {
if (d !is IrClass && !isExternalFileClassMember(d)) {
logger.errorElement("External declaration is neither a class, nor a top-level declaration", d)
return false
}
val declBinaryName = declBinaryNames.getOrPut(d) { getIrDeclBinaryName(d) }
val declBinaryName = declBinaryNames.getOrPut(d) { getIrElementBinaryName(d) }
val ret = externalDeclsDone.add(Pair(declBinaryName, signature))
if (ret) externalDeclWorkList.add(Pair(d, signature))
return ret
}
fun extractLater(c: IrClass) = extractLater(c, "")
fun writeStubTrapFile(e: IrElement, signature: String = "") {
extractElement(e, signature, true) { trapFileBW, _, _ ->
trapFileBW.write("// Trap file stubbed because this declaration was extracted from source in $sourceFilePath\n")
trapFileBW.write("// Part of invocation $invocationTrapFile\n")
}
}
private fun extractElement(element: IrElement, possiblyLongSignature: String, fromSource: Boolean, extractorFn: (BufferedWriter, String, OdasaOutput.TrapFileManager) -> Unit) {
// In order to avoid excessively long signatures which can lead to trap file names longer than the filesystem
// limit, we truncate and add a hash to preserve uniqueness if necessary.
val signature = if (possiblyLongSignature.length > 100) {
possiblyLongSignature.substring(0, 92) + "#" + StringDigestor.digest(possiblyLongSignature).substring(0, 8)
} else { possiblyLongSignature }
output.getTrapLockerForDecl(element, signature, fromSource).useAC { locker ->
locker.trapFileManager.useAC { manager ->
val shortName = when(element) {
is IrDeclarationWithName -> element.name.asString()
is IrFile -> element.name
else -> "(unknown name)"
}
if (manager == null) {
logger.info("Skipping extracting external decl $shortName")
} else {
val trapFile = manager.file
val trapTmpFile = File.createTempFile("${trapFile.nameWithoutExtension}.", ".${trapFile.extension}.tmp", trapFile.parentFile)
try {
GZIPOutputStream(trapTmpFile.outputStream()).bufferedWriter().use {
extractorFn(it, signature, manager)
}
if (!trapTmpFile.renameTo(trapFile)) {
logger.error("Failed to rename $trapTmpFile to $trapFile")
}
} catch (e: Exception) {
manager.setHasError()
logger.error("Failed to extract '$shortName'. Partial TRAP file location is $trapTmpFile", e)
}
}
}
}
}
fun extractExternalClasses() {
val output = OdasaOutput(false, logger)
output.setCurrentSourceFile(File(sourceFilePath))
do {
val nextBatch = ArrayList(externalDeclWorkList)
externalDeclWorkList.clear()
nextBatch.forEach { workPair ->
val (irDecl, possiblyLongSignature) = workPair
// In order to avoid excessively long signatures which can lead to trap file names longer than the filesystem
// limit, we truncate and add a hash to preserve uniqueness if necessary.
val signature = if (possiblyLongSignature.length > 100) {
possiblyLongSignature.substring(0, 92) + "#" + StringDigestor.digest(possiblyLongSignature).substring(0, 8)
} else { possiblyLongSignature }
output.getTrapLockerForDecl(irDecl, signature).useAC { locker ->
locker.trapFileManager.useAC { manager ->
val shortName = when(irDecl) {
is IrDeclarationWithName -> irDecl.name.asString()
else -> "(unknown name)"
extractElement(irDecl, possiblyLongSignature, false) { trapFileBW, signature, manager ->
val containingClass = getContainingClassOrSelf(irDecl)
if (containingClass == null) {
logger.errorElement("Unable to get containing class", irDecl)
} else {
val binaryPath = getIrClassBinaryPath(containingClass)
// We want our comments to be the first thing in the file,
// so start off with a mere TrapWriter
val tw = TrapWriter(logger.loggerBase, TrapLabelManager(), trapFileBW, diagnosticTrapWriter)
tw.writeComment("Generated by the CodeQL Kotlin extractor for external dependencies")
tw.writeComment("Part of invocation $invocationTrapFile")
if (signature != possiblyLongSignature) {
tw.writeComment("Function signature abbreviated; full signature is: $possiblyLongSignature")
}
if(manager == null) {
logger.info("Skipping extracting external decl $shortName")
// Now elevate to a SourceFileTrapWriter, and populate the
// file information if needed:
val ftw = tw.makeFileTrapWriter(binaryPath, true)
val fileExtractor = KotlinFileExtractor(logger, ftw, null, binaryPath, manager, this, primitiveTypeMapping, pluginContext, KotlinFileExtractor.DeclarationStack(), globalExtensionState)
if (irDecl is IrClass) {
// 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 pkgId = fileExtractor.extractPackage(pkg)
ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation())
ftw.writeCupackage(ftw.fileId, pkgId)
fileExtractor.extractClassSource(irDecl, extractDeclarations = !irDecl.isFileClass, extractStaticInitializer = false, extractPrivateMembers = false, extractFunctionBodies = false)
} else {
val trapFile = manager.file
val trapTmpFile = File.createTempFile("${trapFile.nameWithoutExtension}.", ".${trapFile.extension}.tmp", trapFile.parentFile)
val containingClass = getContainingClassOrSelf(irDecl)
if (containingClass == null) {
logger.errorElement("Unable to get containing class", irDecl)
return
}
val binaryPath = getIrClassBinaryPath(containingClass)
try {
GZIPOutputStream(trapTmpFile.outputStream()).bufferedWriter().use { trapFileBW ->
// We want our comments to be the first thing in the file,
// so start off with a mere TrapWriter
val tw = TrapWriter(logger.loggerBase, TrapLabelManager(), trapFileBW, diagnosticTrapWriter)
tw.writeComment("Generated by the CodeQL Kotlin extractor for external dependencies")
tw.writeComment("Part of invocation $invocationTrapFile")
if (signature != possiblyLongSignature) {
tw.writeComment("Function signature abbreviated; full signature is: $possiblyLongSignature")
}
// Now elevate to a SourceFileTrapWriter, and populate the
// file information if needed:
val ftw = tw.makeFileTrapWriter(binaryPath, true)
val fileExtractor = KotlinFileExtractor(logger, ftw, null, binaryPath, manager, this, primitiveTypeMapping, pluginContext, KotlinFileExtractor.DeclarationStack(), globalExtensionState)
if (irDecl is IrClass) {
// 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 pkgId = fileExtractor.extractPackage(pkg)
ftw.writeHasLocation(ftw.fileId, ftw.getWholeFileLocation())
ftw.writeCupackage(ftw.fileId, pkgId)
fileExtractor.extractClassSource(irDecl, extractDeclarations = !irDecl.isFileClass, extractStaticInitializer = false, extractPrivateMembers = false, extractFunctionBodies = false)
} else {
fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false, extractFunctionBodies = false)
}
}
if (!trapTmpFile.renameTo(trapFile)) {
logger.error("Failed to rename $trapTmpFile to $trapFile")
}
} catch (e: Exception) {
manager.setHasError()
logger.error("Failed to extract '$shortName'. Partial TRAP file location is $trapTmpFile", e)
}
fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false, extractFunctionBodies = false)
}
}
}

View File

@@ -90,7 +90,12 @@ open class KotlinFileExtractor(
}
}
file.declarations.forEach { extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true) }
file.declarations.forEach {
extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true)
if (it is IrProperty || it is IrField || it is IrFunction) {
externalClassExtractor.writeStubTrapFile(it, getTrapFileSignature(it))
}
}
extractStaticInitializer(file, { extractFileClass(file) })
CommentExtractor(this, file, tw.fileId).extract()
@@ -99,6 +104,8 @@ open class KotlinFileExtractor(
}
linesOfCode?.linesOfCodeInFile(id)
externalClassExtractor.writeStubTrapFile(file)
}
}
@@ -507,6 +514,9 @@ open class KotlinFileExtractor(
addModifiers(instance.id, "public", "static", "final")
tw.writeClass_object(id.cast<DbClass>(), instance.id)
}
if (c.isObject) {
addModifiers(id, "static")
}
if (extractFunctionBodies && needsObinitFunction(c)) {
extractObinitFunction(c, id)
}
@@ -516,6 +526,9 @@ open class KotlinFileExtractor(
linesOfCode?.linesOfCodeInDeclaration(c, id)
if (extractFunctionBodies && !c.isAnonymousObject && !c.isLocal)
externalClassExtractor.writeStubTrapFile(c)
return id
}
}
@@ -1249,13 +1262,13 @@ open class KotlinFileExtractor(
DeclarationStackAdjuster(f).use {
val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(".", "$$") } ?: ""
val extractType = if (isAnnotationClassField(f)) kClassToJavaClass(f.type) else f.type
return extractField(useField(f), "${f.name.asString()}$fNameSuffix", extractType, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
return extractField(useField(f), "${f.name.asString()}$fNameSuffix", extractType, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal, isDirectlyExposedCompanionObjectField(f))
}
}
}
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean, isFinal: Boolean): Label<out DbField> {
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean, isFinal: Boolean, isStatic: Boolean): Label<out DbField> {
val t = useType(type)
tw.writeFields(id, name, t.javaResult.id, parentId, id)
tw.writeFieldsKotlinType(id, t.kotlinResult.id)
@@ -1265,6 +1278,9 @@ open class KotlinFileExtractor(
if (isFinal) {
addModifiers(id, "final")
}
if (isStatic) {
addModifiers(id, "static")
}
if (!isExternalDeclaration) {
val fieldDeclarationId = tw.getFreshIdLabel<DbFielddecl>()
@@ -4196,12 +4212,12 @@ open class KotlinFileExtractor(
val firstAssignmentStmtIdx = 1
if (dispatchReceiverInfo != null) {
extractField(dispatchReceiverInfo.field, "<dispatchReceiver>", dispatchReceiverInfo.type, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
extractField(dispatchReceiverInfo.field, "<dispatchReceiver>", dispatchReceiverInfo.type, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true, isStatic = false)
extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiverInfo.type, dispatchReceiverInfo.field, 0 + dispatchReceiverInfo.indexOffset, firstAssignmentStmtIdx + dispatchReceiverInfo.indexOffset)
}
if (extensionReceiverInfo != null) {
extractField(extensionReceiverInfo.field, "<extensionReceiver>", extensionReceiverInfo.type, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
extractField(extensionReceiverInfo.field, "<extensionReceiver>", extensionReceiverInfo.type, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true, isStatic = false)
extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiverInfo.type, extensionReceiverInfo.field, 0 + extensionReceiverInfo.indexOffset, firstAssignmentStmtIdx + extensionReceiverInfo.indexOffset)
}
}
@@ -5269,7 +5285,7 @@ open class KotlinFileExtractor(
// add field
val fieldId = tw.getFreshIdLabel<DbField>()
extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, isExternalDeclaration = false, isFinal = true)
extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, isExternalDeclaration = false, isFinal = true, isStatic = false)
// adjust constructor
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)

View File

@@ -67,15 +67,12 @@ open class KotlinUsesExtractor(
TypeResult(fakeKotlinType(), "", "")
)
@OptIn(kotlin.ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5
fun extractFileClass(f: IrFile): Label<out DbClass> {
val fileName = f.fileEntry.name
val pkg = f.fqName.asString()
val defaultName = fileName.replaceFirst(Regex(""".*[/\\]"""), "").replaceFirst(Regex("""\.kt$"""), "").replaceFirstChar({ it.uppercase() }) + "Kt"
var jvmName = getJvmName(f) ?: defaultName
val jvmName = getFileClassName(f)
val qualClassName = if (pkg.isEmpty()) jvmName else "$pkg.$jvmName"
val label = "@\"class;$qualClassName\""
val id: Label<DbClass> = tw.getLabelFor(label, {
val id: Label<DbClass> = tw.getLabelFor(label) {
val fileId = tw.mkFileId(f.path, false)
val locId = tw.getWholeFileLocation(fileId)
val pkgId = extractPackage(pkg)
@@ -84,7 +81,7 @@ open class KotlinUsesExtractor(
tw.writeHasLocation(it, locId)
addModifiers(it, "public", "final")
})
}
return id
}
@@ -258,10 +255,26 @@ open class KotlinUsesExtractor(
private fun propertySignature(p: IrProperty) =
((p.getter ?: p.setter)?.extensionReceiverParameter?.let { useType(erase(it.type)).javaResult.signature } ?: "")
fun getTrapFileSignature(d: IrDeclaration) =
when(d) {
is IrFunction ->
// Note we erase the parameter types before calling useType even though the signature should be the same
// in order to prevent an infinite loop through useTypeParameter -> useDeclarationParent -> useFunction
// -> extractFunctionLaterIfExternalFileMember, which would result for `fun <T> f(t: T) { ... }` for example.
(listOfNotNull(d.extensionReceiverParameter) + d.valueParameters)
.map { useType(erase(it.type)).javaResult.signature }
.joinToString(separator = ",", prefix = "(", postfix = ")")
is IrProperty -> propertySignature(d) + externalClassExtractor.propertySignature
is IrField -> (d.correspondingPropertySymbol?.let { propertySignature(it.owner) } ?: "") + externalClassExtractor.fieldSignature
else -> "unknown signature".also {
logger.warn("Trap file signature requested for unexpected element $d")
}
}
private fun extractPropertyLaterIfExternalFileMember(p: IrProperty) {
if (isExternalFileClassMember(p)) {
extractExternalClassLater(p.parentAsClass)
val signature = propertySignature(p) + externalClassExtractor.propertySignature
val signature = getTrapFileSignature(p)
dependencyCollector?.addDependency(p, signature)
externalClassExtractor.extractLater(p, signature)
}
@@ -270,7 +283,7 @@ open class KotlinUsesExtractor(
private fun extractFieldLaterIfExternalFileMember(f: IrField) {
if (isExternalFileClassMember(f)) {
extractExternalClassLater(f.parentAsClass)
val signature = (f.correspondingPropertySymbol?.let { propertySignature(it.owner) } ?: "") + externalClassExtractor.fieldSignature
val signature = getTrapFileSignature(f)
dependencyCollector?.addDependency(f, signature)
externalClassExtractor.extractLater(f, signature)
}
@@ -285,18 +298,7 @@ open class KotlinUsesExtractor(
// getters and setters are extracted alongside it
return
}
// Note we erase the parameter types before calling useType even though the signature should be the same
// in order to prevent an infinite loop through useTypeParameter -> useDeclarationParent -> useFunction
// -> extractFunctionLaterIfExternalFileMember, which would result for `fun <T> f(t: T) { ... }` for example.
val ext = f.extensionReceiverParameter
val parameters = if (ext != null) {
listOf(ext) + f.valueParameters
} else {
f.valueParameters
}
val paramSigs = parameters.map { useType(erase(it.type)).javaResult.signature }
val signature = paramSigs.joinToString(separator = ",", prefix = "(", postfix = ")")
val signature = getTrapFileSignature(f)
dependencyCollector?.addDependency(f, signature)
externalClassExtractor.extractLater(f, signature)
}
@@ -1647,7 +1649,7 @@ open class KotlinUsesExtractor(
fun useValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>?): Label<out DbParam> =
tw.getLabelFor(getValueParameterLabel(vp, parent))
private fun isDirectlyExposedCompanionObjectField(f: IrField) =
private fun isDirectlyExposableCompanionObjectField(f: IrField) =
f.hasAnnotation(FqName("kotlin.jvm.JvmField")) ||
f.correspondingPropertySymbol?.owner?.let {
it.isConst || it.isLateinit
@@ -1655,12 +1657,14 @@ open class KotlinUsesExtractor(
fun getFieldParent(f: IrField) =
f.parentClassOrNull?.let {
if (it.isCompanion && isDirectlyExposedCompanionObjectField(f))
if (it.isCompanion && isDirectlyExposableCompanionObjectField(f))
it.parent
else
null
} ?: f.parent
fun isDirectlyExposedCompanionObjectField(f: IrField) = getFieldParent(f) != f.parent
// Gets a field's corresponding property's extension receiver type, if any
fun getExtensionReceiverType(f: IrField) =
f.correspondingPropertySymbol?.owner?.let {

View File

@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.parentClassOrNull
@@ -21,20 +22,46 @@ import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
// for `that`.
private fun getName(d: IrDeclarationWithName) = (d as? IrAnnotationContainer)?.let { getJvmName(it) } ?: d.name.asString()
fun getIrDeclBinaryName(that: IrDeclaration): String {
val shortName = when(that) {
is IrDeclarationWithName -> getName(that)
else -> "(unknown-name)"
}
val internalName = StringBuilder(shortName);
generateSequence(that.parent) { (it as? IrDeclaration)?.parent }
.forEach {
when (it) {
is IrClass -> internalName.insert(0, getName(it) + "$")
is IrPackageFragment -> it.fqName.asString().takeIf { fqName -> fqName.isNotEmpty() }?.let { fqName -> internalName.insert(0, "$fqName.") }
}
}
return internalName.toString()
@OptIn(ExperimentalStdlibApi::class) // Annotation required by kotlin versions < 1.5
fun getFileClassName(f: IrFile) =
getJvmName(f) ?:
((f.fileEntry.name.replaceFirst(Regex(""".*[/\\]"""), "")
.replaceFirst(Regex("""\.kt$"""), "")
.replaceFirstChar { it.uppercase() }) + "Kt")
fun getIrElementBinaryName(that: IrElement): String {
if (that is IrFile) {
val shortName = getFileClassName(that)
val pkg = that.fqName.asString()
return if (pkg.isEmpty()) shortName else "$pkg.$shortName"
}
if (that !is IrDeclaration) {
return "(unknown-name)"
}
val shortName = when(that) {
is IrDeclarationWithName -> getName(that)
else -> "(unknown-name)"
}
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 <: IrPackageFragment
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.fqName.asString().takeIf { fqName -> fqName.isNotEmpty() }?.let { fqName -> internalName.insert(0, "$fqName.") }
}
}
return internalName.toString()
}
fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? {
@@ -81,7 +108,7 @@ private fun getRawIrClassBinaryPath(irClass: IrClass) =
fun getIrClassBinaryPath(irClass: IrClass): String {
return getRawIrClassBinaryPath(irClass)
// Otherwise, make up a fake location:
?: "/!unknown-binary-location/${getIrDeclBinaryName(irClass).replace(".", "/")}.class"
?: "/!unknown-binary-location/${getIrElementBinaryName(irClass).replace(".", "/")}.class"
}
fun getContainingClassOrSelf(decl: IrDeclaration): IrClass? {

View File

@@ -1,3 +1,4 @@
| J.java:1:14:1:14 | J |
| build/J.class:0:0:0:0 | J<String> |
| file:///!unknown-binary-location/J.class:0:0:0:0 | J<> |
| file:///!unknown-binary-location/J.class:0:0:0:0 | J<Integer> |

View File

@@ -16,9 +16,3 @@ class X {
annotation class Ann(
val p: Int,
@get:JvmName("w") val q: Int)
// Diagnostic Matches: Incomplete annotation: @kotlin.jvm.JvmName(name="changeY")
// Diagnostic Matches: Incomplete annotation: @kotlin.jvm.JvmName(name="getX_prop")
// Diagnostic Matches: Incomplete annotation: @kotlin.jvm.JvmName(name="method")
// Diagnostic Matches: Incomplete annotation: @kotlin.jvm.JvmName(name="y")
// Diagnostic Matches: Unknown location for kotlin.jvm.JvmName

View File

@@ -110,6 +110,3 @@ public class TakesArrayList {
fun inInArrayComparableAny(c: Comparable<Array<in Array<in Any>>>) { }
}
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.NotNull
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.NotNull

View File

@@ -30,6 +30,3 @@ fun foo() {
fun String.baz(p1: String): String { return "Baz" }
"someString".baz("bazParam")
}
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.NotNull
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.NotNull

View File

@@ -5,7 +5,6 @@ classLocations
| main.A<Object> | file:///!unknown-binary-location/main/A.class:0:0:0:0 | file:///!unknown-binary-location/main/A.class:0:0:0:0 |
| main.A<String> | A.class:0:0:0:0 | A.class:0:0:0:0 |
| main.A<String> | file:///!unknown-binary-location/main/A.class:0:0:0:0 | file:///!unknown-binary-location/main/A.class:0:0:0:0 |
| main.B | generics-location.testproj/test.class.files/main/B.class:0:0:0:0 | generics-location.testproj/test.class.files/main/B.class:0:0:0:0 |
| main.B | generics.kt:3:1:11:1 | generics.kt:3:1:11:1 |
| main.B<Integer> | generics-location.testproj/test.class.files/main/B.class:0:0:0:0 | generics-location.testproj/test.class.files/main/B.class:0:0:0:0 |
| main.B<Object> | file:///!unknown-binary-location/main/B.class:0:0:0:0 | file:///!unknown-binary-location/main/B.class:0:0:0:0 |

View File

@@ -1,4 +1,5 @@
| TestClassA.kt:2:1:3:1 | TestClassA |
| TestClassA.kt:2:1:3:1 | TestClassA<> |
| TestClassAUser.kt:0:0:0:0 | TestClassAUserKt |
| TestClassAUser.kt:15:1:15:24 | TestClassAUser |
| file:///!unknown-binary-location/TestClassA.class:0:0:0:0 | TestClassA<TestClassAUser> |

View File

@@ -11,9 +11,13 @@ public class Java {
return super.fn0(x);
}
/*
// Java interop disabled as it currently doesn't work (no symbol fn1(int, Completion<...>) gets created)
// TODO: re-enable this test once a correct function signature is extracted
@Override
public Object fn1(int x, Continuation<? super String> $completion) {
return super.fn1(x, $completion);
}
*/
}
}

View File

@@ -13,8 +13,3 @@ class Dkotlin : Base() {
override fun fn0(x: Int): String = super.fn0(x)
override suspend fun fn1(x: Int): String = super.fn1(x)
}
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.NotNull
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.Nullable
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.NotNull
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.Nullable

View File

@@ -1,7 +1,6 @@
methods
| Java.java:4:7:4:13 | javaFun | javaFun() |
| Java.java:10:17:10:19 | fn0 | fn0(int) |
| Java.java:15:17:15:19 | fn1 | fn1(int,kotlin.coroutines.Continuation) |
| Kotlin.kt:2:2:4:2 | kotlinFun | kotlinFun() |
| Kotlin.kt:8:10:8:38 | fn0 | fn0(int) |
| Kotlin.kt:9:18:9:46 | fn1 | fn1(int) |
@@ -9,15 +8,12 @@ methods
| Kotlin.kt:14:22:14:59 | fn1 | fn1(int) |
overrides
| Java.java:10:17:10:19 | fn0 | Kotlin.kt:8:10:8:38 | fn0 |
| Java.java:15:17:15:19 | fn1 | java_and_kotlin.testproj/test.class.files/Base.class:0:0:0:0 | fn1 |
| Kotlin.kt:13:14:13:51 | fn0 | Kotlin.kt:8:10:8:38 | fn0 |
| Kotlin.kt:14:22:14:59 | fn1 | Kotlin.kt:9:18:9:46 | fn1 |
signature_mismatch
| Kotlin.kt:9:18:9:46 | fn1 | fn1(int) |
| java_and_kotlin.testproj/test.class.files/Base.class:0:0:0:0 | fn1 | fn1(int,kotlin.coroutines.Continuation) |
#select
| Java.java:5:3:5:26 | kotlinFun(...) | Kotlin.kt:2:2:4:2 | kotlinFun |
| Java.java:11:11:11:22 | fn0(...) | Kotlin.kt:8:10:8:38 | fn0 |
| Java.java:16:11:16:35 | fn1(...) | java_and_kotlin.testproj/test.class.files/Base.class:0:0:0:0 | fn1 |
| Kotlin.kt:13:40:13:51 | fn0(...) | Kotlin.kt:8:10:8:38 | fn0 |
| Kotlin.kt:14:48:14:59 | fn1(...) | Kotlin.kt:9:18:9:46 | fn1 |

View File

@@ -3,14 +3,10 @@ isInternal
| Kotlin.kt:2:11:3:2 | kotlinFun$main |
| Kotlin.kt:6:10:6:36 | topLevelKotlinFun |
modifiers_methods
| file://:0:0:0:0 | final | Kotlin.kt:2:11:3:2 | kotlinFun$main |
| file://:0:0:0:0 | final | Kotlin.kt:6:10:6:36 | topLevelKotlinFun |
| file://:0:0:0:0 | internal | Kotlin.kt:2:11:3:2 | kotlinFun$main |
| file://:0:0:0:0 | internal | Kotlin.kt:6:10:6:36 | topLevelKotlinFun |
| file://:0:0:0:0 | static | Kotlin.kt:6:10:6:36 | topLevelKotlinFun |
#select
| Kotlin.kt:2:11:3:2 | kotlinFun$main | final |
| Kotlin.kt:2:11:3:2 | kotlinFun$main | internal |
| Kotlin.kt:6:10:6:36 | topLevelKotlinFun | final |
| Kotlin.kt:6:10:6:36 | topLevelKotlinFun | internal |
| Kotlin.kt:6:10:6:36 | topLevelKotlinFun | static |

View File

@@ -85,12 +85,3 @@ public class TestDefaultParameterReference {
}
}
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.NotNull
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.NotNull
// Diagnostic Matches: Completion failure for type: kotlin.jvm.JvmOverloads
// Diagnostic Matches: Completion failure for type: kotlin.jvm.JvmStatic
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.Nullable
// Diagnostic Matches: Unknown location for kotlin.jvm.JvmOverloads
// Diagnostic Matches: Unknown location for kotlin.jvm.JvmStatic
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.Nullable

View File

@@ -4,8 +4,3 @@ public class A {
fun <T> genericFunctionWithOverloads(x: T? = null, y: List<T>? = null, z: T? = null): T? = z
}
// Diagnostic Matches: Completion failure for type: kotlin.jvm.JvmOverloads
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.Nullable
// Diagnostic Matches: Unknown location for kotlin.jvm.JvmOverloads
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.Nullable

View File

@@ -141,11 +141,11 @@ test.kt:
# 65| 0: [MethodAccess] getPropWithStaticGetter(...)
# 65| -1: [TypeAccess] NonCompanion
# 9| 2: [Class] HasCompanion
# 9| 2: [Constructor] HasCompanion
# 9| 1: [Constructor] HasCompanion
# 9| 5: [BlockStmt] { ... }
# 9| 0: [SuperConstructorInvocationStmt] super(...)
# 9| 1: [BlockStmt] { ... }
# 11| 3: [Class] Companion
# 11| 2: [Class] Companion
# 11| 1: [Constructor] Companion
# 11| 5: [BlockStmt] { ... }
# 11| 0: [SuperConstructorInvocationStmt] super(...)
@@ -157,11 +157,9 @@ test.kt:
# 17| 0: [KtInitializerAssignExpr] ...=...
# 17| 0: [VarAccess] nonStaticProp
# 13| 2: [Method] staticMethod
#-----| 1: (Annotations)
# 13| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 13| 0: [Parameter] s
#-----| -1: (Annotations)
# 13| 0: [TypeAccess] String
# 13| 5: [BlockStmt] { ... }
# 13| 0: [ReturnStmt] return ...
@@ -169,11 +167,9 @@ test.kt:
# 13| -1: [ThisAccess] this
# 13| 0: [VarAccess] s
# 14| 3: [Method] nonStaticMethod
#-----| 1: (Annotations)
# 14| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 14| 0: [Parameter] s
#-----| -1: (Annotations)
# 14| 0: [TypeAccess] String
# 14| 5: [BlockStmt] { ... }
# 14| 0: [ReturnStmt] return ...
@@ -184,7 +180,6 @@ test.kt:
# 16| -1: [TypeAccess] String
# 16| 0: [StringLiteral] "a"
# 16| 5: [Method] getStaticProp
#-----| 1: (Annotations)
# 16| 3: [TypeAccess] String
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ReturnStmt] return ...
@@ -194,7 +189,6 @@ test.kt:
# 16| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 16| 0: [Parameter] <set-?>
#-----| -1: (Annotations)
# 16| 0: [TypeAccess] String
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ExprStmt] <Expr>;
@@ -206,7 +200,6 @@ test.kt:
# 17| -1: [TypeAccess] String
# 17| 0: [StringLiteral] "b"
# 17| 8: [Method] getNonStaticProp
#-----| 1: (Annotations)
# 17| 3: [TypeAccess] String
# 17| 5: [BlockStmt] { ... }
# 17| 0: [ReturnStmt] return ...
@@ -216,7 +209,6 @@ test.kt:
# 17| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 17| 0: [Parameter] <set-?>
#-----| -1: (Annotations)
# 17| 0: [TypeAccess] String
# 17| 5: [BlockStmt] { ... }
# 17| 0: [ExprStmt] <Expr>;
@@ -225,7 +217,6 @@ test.kt:
# 17| -1: [ThisAccess] this
# 17| 1: [VarAccess] <set-?>
# 20| 10: [Method] getPropWithStaticGetter
#-----| 1: (Annotations)
# 20| 3: [TypeAccess] String
# 20| 5: [BlockStmt] { ... }
# 20| 0: [ReturnStmt] return ...
@@ -235,7 +226,6 @@ test.kt:
# 21| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 21| 0: [Parameter] s
#-----| -1: (Annotations)
# 21| 0: [TypeAccess] String
# 21| 5: [BlockStmt] { ... }
# 21| 0: [ExprStmt] <Expr>;
@@ -243,30 +233,25 @@ test.kt:
# 21| -1: [ThisAccess] this
# 21| 0: [VarAccess] s
# 24| 12: [Method] getPropWithStaticSetter
#-----| 1: (Annotations)
# 24| 3: [TypeAccess] String
# 24| 5: [BlockStmt] { ... }
# 24| 0: [ReturnStmt] return ...
# 24| 0: [MethodAccess] getPropWithStaticGetter(...)
# 24| -1: [ThisAccess] this
# 25| 13: [Method] setPropWithStaticSetter
#-----| 1: (Annotations)
# 25| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 25| 0: [Parameter] s
#-----| -1: (Annotations)
# 25| 0: [TypeAccess] String
# 25| 5: [BlockStmt] { ... }
# 25| 0: [ExprStmt] <Expr>;
# 25| 0: [MethodAccess] setPropWithStaticGetter(...)
# 25| -1: [ThisAccess] this
# 25| 0: [VarAccess] s
# 13| 4: [Method] staticMethod
#-----| 1: (Annotations)
# 13| 3: [Method] staticMethod
# 13| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 13| 0: [Parameter] s
#-----| -1: (Annotations)
# 13| 0: [TypeAccess] String
# 13| 5: [BlockStmt] { ... }
# 13| 0: [ReturnStmt] return ...
@@ -274,19 +259,17 @@ test.kt:
# 13| -1: [VarAccess] HasCompanion.Companion
# 13| -1: [TypeAccess] HasCompanion
# 13| 0: [VarAccess] s
# 16| 5: [Method] getStaticProp
#-----| 1: (Annotations)
# 16| 4: [Method] getStaticProp
# 16| 3: [TypeAccess] String
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ReturnStmt] return ...
# 16| 0: [MethodAccess] getStaticProp(...)
# 16| -1: [VarAccess] HasCompanion.Companion
# 16| -1: [TypeAccess] HasCompanion
# 16| 6: [Method] setStaticProp
# 16| 5: [Method] setStaticProp
# 16| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 16| 0: [Parameter] <set-?>
#-----| -1: (Annotations)
# 16| 0: [TypeAccess] String
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ReturnStmt] return ...
@@ -294,20 +277,17 @@ test.kt:
# 16| -1: [VarAccess] HasCompanion.Companion
# 16| -1: [TypeAccess] HasCompanion
# 16| 0: [VarAccess] <set-?>
# 20| 7: [Method] getPropWithStaticGetter
#-----| 1: (Annotations)
# 20| 6: [Method] getPropWithStaticGetter
# 20| 3: [TypeAccess] String
# 20| 5: [BlockStmt] { ... }
# 20| 0: [ReturnStmt] return ...
# 20| 0: [MethodAccess] getPropWithStaticGetter(...)
# 20| -1: [VarAccess] HasCompanion.Companion
# 20| -1: [TypeAccess] HasCompanion
# 25| 8: [Method] setPropWithStaticSetter
#-----| 1: (Annotations)
# 25| 7: [Method] setPropWithStaticSetter
# 25| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 25| 0: [Parameter] s
#-----| -1: (Annotations)
# 25| 0: [TypeAccess] String
# 25| 5: [BlockStmt] { ... }
# 25| 0: [ReturnStmt] return ...
@@ -316,7 +296,7 @@ test.kt:
# 25| -1: [TypeAccess] HasCompanion
# 25| 0: [VarAccess] s
# 31| 3: [Class] NonCompanion
# 31| 2: [Constructor] NonCompanion
# 31| 1: [Constructor] NonCompanion
# 31| 5: [BlockStmt] { ... }
# 31| 0: [SuperConstructorInvocationStmt] super(...)
# 31| 1: [BlockStmt] { ... }
@@ -326,12 +306,10 @@ test.kt:
# 37| 1: [ExprStmt] <Expr>;
# 37| 0: [KtInitializerAssignExpr] ...=...
# 37| 0: [VarAccess] nonStaticProp
# 33| 3: [Method] staticMethod
#-----| 1: (Annotations)
# 33| 2: [Method] staticMethod
# 33| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 33| 0: [Parameter] s
#-----| -1: (Annotations)
# 33| 0: [TypeAccess] String
# 33| 5: [BlockStmt] { ... }
# 33| 0: [ReturnStmt] return ...
@@ -339,34 +317,30 @@ test.kt:
# 33| -1: [VarAccess] NonCompanion.INSTANCE
# 33| -1: [TypeAccess] NonCompanion
# 33| 0: [VarAccess] s
# 34| 4: [Method] nonStaticMethod
#-----| 1: (Annotations)
# 34| 3: [Method] nonStaticMethod
# 34| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 34| 0: [Parameter] s
#-----| -1: (Annotations)
# 34| 0: [TypeAccess] String
# 34| 5: [BlockStmt] { ... }
# 34| 0: [ReturnStmt] return ...
# 34| 0: [MethodAccess] staticMethod(...)
# 34| -1: [TypeAccess] NonCompanion
# 34| 0: [VarAccess] s
# 36| 5: [FieldDeclaration] String staticProp;
# 36| 4: [FieldDeclaration] String staticProp;
# 36| -1: [TypeAccess] String
# 36| 0: [StringLiteral] "a"
# 36| 6: [Method] getStaticProp
#-----| 1: (Annotations)
# 36| 5: [Method] getStaticProp
# 36| 3: [TypeAccess] String
# 36| 5: [BlockStmt] { ... }
# 36| 0: [ReturnStmt] return ...
# 36| 0: [VarAccess] NonCompanion.INSTANCE.staticProp
# 36| -1: [VarAccess] NonCompanion.INSTANCE
# 36| -1: [TypeAccess] NonCompanion
# 36| 7: [Method] setStaticProp
# 36| 6: [Method] setStaticProp
# 36| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 36| 0: [Parameter] <set-?>
#-----| -1: (Annotations)
# 36| 0: [TypeAccess] String
# 36| 5: [BlockStmt] { ... }
# 36| 0: [ExprStmt] <Expr>;
@@ -375,21 +349,19 @@ test.kt:
# 36| -1: [VarAccess] NonCompanion.INSTANCE
# 36| -1: [TypeAccess] NonCompanion
# 36| 1: [VarAccess] <set-?>
# 37| 8: [FieldDeclaration] String nonStaticProp;
# 37| 7: [FieldDeclaration] String nonStaticProp;
# 37| -1: [TypeAccess] String
# 37| 0: [StringLiteral] "b"
# 37| 9: [Method] getNonStaticProp
#-----| 1: (Annotations)
# 37| 8: [Method] getNonStaticProp
# 37| 3: [TypeAccess] String
# 37| 5: [BlockStmt] { ... }
# 37| 0: [ReturnStmt] return ...
# 37| 0: [VarAccess] this.nonStaticProp
# 37| -1: [ThisAccess] this
# 37| 10: [Method] setNonStaticProp
# 37| 9: [Method] setNonStaticProp
# 37| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 37| 0: [Parameter] <set-?>
#-----| -1: (Annotations)
# 37| 0: [TypeAccess] String
# 37| 5: [BlockStmt] { ... }
# 37| 0: [ExprStmt] <Expr>;
@@ -397,38 +369,33 @@ test.kt:
# 37| 0: [VarAccess] this.nonStaticProp
# 37| -1: [ThisAccess] this
# 37| 1: [VarAccess] <set-?>
# 40| 11: [Method] getPropWithStaticGetter
#-----| 1: (Annotations)
# 40| 10: [Method] getPropWithStaticGetter
# 40| 3: [TypeAccess] String
# 40| 5: [BlockStmt] { ... }
# 40| 0: [ReturnStmt] return ...
# 40| 0: [MethodAccess] getPropWithStaticSetter(...)
# 40| -1: [VarAccess] NonCompanion.INSTANCE
# 40| -1: [TypeAccess] NonCompanion
# 41| 12: [Method] setPropWithStaticGetter
# 41| 11: [Method] setPropWithStaticGetter
# 41| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 41| 0: [Parameter] s
#-----| -1: (Annotations)
# 41| 0: [TypeAccess] String
# 41| 5: [BlockStmt] { ... }
# 41| 0: [ExprStmt] <Expr>;
# 41| 0: [MethodAccess] setPropWithStaticSetter(...)
# 41| -1: [TypeAccess] NonCompanion
# 41| 0: [VarAccess] s
# 44| 13: [Method] getPropWithStaticSetter
#-----| 1: (Annotations)
# 44| 12: [Method] getPropWithStaticSetter
# 44| 3: [TypeAccess] String
# 44| 5: [BlockStmt] { ... }
# 44| 0: [ReturnStmt] return ...
# 44| 0: [MethodAccess] getPropWithStaticGetter(...)
# 44| -1: [TypeAccess] NonCompanion
# 45| 14: [Method] setPropWithStaticSetter
#-----| 1: (Annotations)
# 45| 13: [Method] setPropWithStaticSetter
# 45| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 45| 0: [Parameter] s
#-----| -1: (Annotations)
# 45| 0: [TypeAccess] String
# 45| 5: [BlockStmt] { ... }
# 45| 0: [ExprStmt] <Expr>;

View File

@@ -65,8 +65,3 @@ fun externalUser() {
NonCompanion.propWithStaticSetter = NonCompanion.propWithStaticGetter
}
// Diagnostic Matches: Completion failure for type: kotlin.jvm.JvmStatic
// Diagnostic Matches: Completion failure for type: org.jetbrains.annotations.NotNull
// Diagnostic Matches: Unknown location for kotlin.jvm.JvmStatic
// Diagnostic Matches: Unknown location for org.jetbrains.annotations.NotNull