Fix generating cls stubs when is metadata using type tables (KT-23345)

Affected cases:
 - return type for suspend lambda
 - aliased type in type alias declaration
 - using type alias instead of aliased type in declarations

 #KT-23345 Fixed
This commit is contained in:
Nikolay Krasko
2018-03-20 12:51:31 +03:00
parent 875e0a64e7
commit 117890dba8
5 changed files with 48 additions and 12 deletions
@@ -28,7 +28,7 @@ object KotlinStubVersions {
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
private const val BINARY_STUB_VERSION = 64
private const val BINARY_STUB_VERSION = 66
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
// Increasing this version will lead to reindexing of all classfiles.
@@ -35,3 +35,5 @@ val DO_NOTHING_2: (Any?, Any?) -> Unit = { _, _ -> }
val DO_NOTHING_3: (Any?, Any?, Any?) -> Unit = { _, _, _ -> }
fun <T> doNothing(): (T) -> Unit = DO_NOTHING
fun doNothing() {}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
import org.jetbrains.kotlin.utils.doNothing
import java.util.*
// TODO: see DescriptorRendererOptions.excludedTypeAnnotationClasses for decompiler
@@ -47,7 +48,11 @@ private val ANNOTATIONS_NOT_LOADED_FOR_TYPES = setOf(KotlinBuiltIns.FQ_NAMES.par
class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
fun createTypeReferenceStub(parent: StubElement<out PsiElement>, type: Type, additionalAnnotations: () -> List<ClassIdWithTarget> = { emptyList() }) {
if (type.hasAbbreviatedType()) return createTypeReferenceStub(parent, type.abbreviatedType, additionalAnnotations)
val abbreviatedType = type.abbreviatedType(c.typeTable)
if (abbreviatedType != null) {
return createTypeReferenceStub(parent, abbreviatedType, additionalAnnotations)
}
val typeReference = KotlinPlaceHolderStubImpl<KtTypeReference>(parent, KtStubElementTypes.TYPE_REFERENCE)
val annotations = c.components.annotationLoader.loadTypeAnnotations(type, c.nameResolver).filterNot {
@@ -64,6 +69,9 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
createTypeParameterStub(typeReference, type, c.typeParameters[type.typeParameter], allAnnotations)
type.hasTypeParameterName() ->
createTypeParameterStub(typeReference, type, c.nameResolver.getName(type.typeParameterName), allAnnotations)
else -> {
doNothing()
}
}
}
@@ -208,7 +216,8 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
createTypeReferenceStub(functionType, returnType)
}
else {
createTypeReferenceStub(functionType, suspendParameterType.getArgument(0).type)
val continuationArgumentType = suspendParameterType.getArgument(0).type(c.typeTable)!!
createTypeReferenceStub(functionType, continuationArgumentType)
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.stubs.impl.KotlinTypeAliasStubImpl
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.metadata.deserialization.underlyingType
fun createTypeAliasStub(
parent: StubElement<out PsiElement>,
@@ -57,5 +58,6 @@ fun createTypeAliasStub(
createAnnotationStubs(typeAliasProto.annotationList.map { context.nameResolver.getClassId(it.id) }, modifierList)
}
typeStubBuilder.createTypeReferenceStub(typeAlias, typeAliasProto.underlyingType)
val typeAliasUnderlyingType = typeAliasProto.underlyingType(context.typeTable)
typeStubBuilder.createTypeReferenceStub(typeAlias, typeAliasUnderlyingType)
}
@@ -45,11 +45,23 @@ abstract class AbstractClsStubBuilderTest : LightCodeInsightFixtureTestCase() {
null
}
val classFile = getClassFileToDecompile(sourcePath, jvmFileName)
val txtFilePath = File("$sourcePath/${lastSegment(sourcePath)}.txt")
testClsStubsForFile(classFile, txtFilePath)
testWithEnabledStringTable(sourcePath, jvmFileName, txtFilePath)
testWithDisabledStringTable(sourcePath, jvmFileName, txtFilePath)
}
private fun testWithEnabledStringTable(sourcePath: String, classFileName: String?, txtFile: File?) {
doTest(sourcePath, true, classFileName, txtFile)
}
private fun testWithDisabledStringTable(sourcePath: String, classFileName: String?, txtFile: File?) {
doTest(sourcePath, false, classFileName, txtFile)
}
protected fun doTest(sourcePath: String, useStringTable: Boolean, classFileName: String?, txtFile: File?) {
val classFile = getClassFileToDecompile(sourcePath, useStringTable, classFileName)
testClsStubsForFile(classFile, txtFile)
}
protected fun testClsStubsForFile(classFile: VirtualFile, txtFile: File?) {
@@ -64,9 +76,16 @@ abstract class AbstractClsStubBuilderTest : LightCodeInsightFixtureTestCase() {
}
}
private fun getClassFileToDecompile(sourcePath: String, classFileName: String?): VirtualFile {
private fun getClassFileToDecompile(sourcePath: String, isUseStringTable: Boolean, classFileName: String?): VirtualFile {
val outDir = KotlinTestUtils.tmpDir("libForStubTest-" + sourcePath)
MockLibraryUtil.compileKotlin(sourcePath, outDir, extraOptions = listOf("-Xallow-kotlin-package"))
val extraOptions = ArrayList<String>()
extraOptions.add("-Xallow-kotlin-package")
if (isUseStringTable) {
extraOptions.add("-Xuse-type-table")
}
MockLibraryUtil.compileKotlin(sourcePath, outDir, extraOptions = extraOptions)
val root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(outDir)!!
return root.findClassFileByName(classFileName ?: lastSegment(sourcePath))
@@ -84,9 +103,13 @@ fun StubElement<out PsiElement>.serializeToString(): String {
fun VirtualFile.findClassFileByName(className: String): VirtualFile {
val files = LinkedHashSet<VirtualFile>()
VfsUtilCore.iterateChildrenRecursively(
this,
{ virtualFile -> virtualFile.isDirectory || virtualFile.name == "$className.class" },
{ virtualFile -> if (!virtualFile.isDirectory) files.addIfNotNull(virtualFile); true })
this,
{ virtualFile ->
virtualFile.isDirectory || virtualFile.name == "$className.class"
},
{ virtualFile ->
if (!virtualFile.isDirectory) files.addIfNotNull(virtualFile); true
})
return files.single()
}