FIC: support fun interfaces in stub builder
This commit is contained in:
@@ -28,7 +28,7 @@ object KotlinStubVersions {
|
|||||||
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
|
// 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).
|
// 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).
|
// 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 = 70
|
private const val BINARY_STUB_VERSION = 71
|
||||||
|
|
||||||
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
|
// 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.
|
// Increasing this version will lead to reindexing of all classfiles.
|
||||||
|
|||||||
+4
-3
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi.stubs.elements;
|
|||||||
import com.intellij.psi.stubs.StubElement;
|
import com.intellij.psi.stubs.StubElement;
|
||||||
import com.intellij.psi.stubs.StubInputStream;
|
import com.intellij.psi.stubs.StubInputStream;
|
||||||
import com.intellij.psi.stubs.StubOutputStream;
|
import com.intellij.psi.stubs.StubOutputStream;
|
||||||
|
import com.intellij.util.io.DataInputOutputUtil;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.psi.KtModifierList;
|
import org.jetbrains.kotlin.psi.KtModifierList;
|
||||||
@@ -41,14 +42,14 @@ public class KtModifierListElementType<T extends KtModifierList> extends KtStubE
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(@NotNull KotlinModifierListStub stub, @NotNull StubOutputStream dataStream) throws IOException {
|
public void serialize(@NotNull KotlinModifierListStub stub, @NotNull StubOutputStream dataStream) throws IOException {
|
||||||
int mask = ((KotlinModifierListStubImpl) stub).getMask();
|
long mask = ((KotlinModifierListStubImpl) stub).getMask();
|
||||||
dataStream.writeVarInt(mask);
|
DataInputOutputUtil.writeLONG(dataStream, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public KotlinModifierListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
|
public KotlinModifierListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
|
||||||
int mask = dataStream.readVarInt();
|
long mask = DataInputOutputUtil.readLONG(dataStream);
|
||||||
return new KotlinModifierListStubImpl(parentStub, mask, this);
|
return new KotlinModifierListStubImpl(parentStub, mask, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -25,14 +25,14 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtModifierListElementType;
|
|||||||
|
|
||||||
public class KotlinModifierListStubImpl extends KotlinStubBaseImpl<KtDeclarationModifierList> implements KotlinModifierListStub {
|
public class KotlinModifierListStubImpl extends KotlinStubBaseImpl<KtDeclarationModifierList> implements KotlinModifierListStub {
|
||||||
|
|
||||||
private final int mask;
|
private final long mask;
|
||||||
|
|
||||||
public KotlinModifierListStubImpl(StubElement parent, int mask, @NotNull KtModifierListElementType<?> elementType) {
|
public KotlinModifierListStubImpl(StubElement parent, long mask, @NotNull KtModifierListElementType<?> elementType) {
|
||||||
super(parent, elementType);
|
super(parent, elementType);
|
||||||
this.mask = mask;
|
this.mask = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMask() {
|
public long getMask() {
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,32 +23,32 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
|||||||
|
|
||||||
object ModifierMaskUtils {
|
object ModifierMaskUtils {
|
||||||
init {
|
init {
|
||||||
assert(MODIFIER_KEYWORDS_ARRAY.size <= 32) { "Current implementation depends on the ability to represent modifier list as bit mask" }
|
assert(MODIFIER_KEYWORDS_ARRAY.size <= 64) { "Current implementation depends on the ability to represent modifier list as bit mask" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun computeMaskFromModifierList(modifierList: KtModifierList): Int = computeMask { modifierList.hasModifier(it) }
|
fun computeMaskFromModifierList(modifierList: KtModifierList): Long = computeMask { modifierList.hasModifier(it) }
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun computeMask(hasModifier: (KtModifierKeywordToken) -> Boolean): Int {
|
fun computeMask(hasModifier: (KtModifierKeywordToken) -> Boolean): Long {
|
||||||
var mask = 0
|
var mask = 0L
|
||||||
for ((index, modifierKeywordToken) in MODIFIER_KEYWORDS_ARRAY.withIndex()) {
|
for ((index, modifierKeywordToken) in MODIFIER_KEYWORDS_ARRAY.withIndex()) {
|
||||||
if (hasModifier(modifierKeywordToken)) {
|
if (hasModifier(modifierKeywordToken)) {
|
||||||
mask = mask or (1 shl index)
|
mask = mask or (1L shl index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mask
|
return mask
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun maskHasModifier(mask: Int, modifierToken: KtModifierKeywordToken): Boolean {
|
fun maskHasModifier(mask: Long, modifierToken: KtModifierKeywordToken): Boolean {
|
||||||
val index = MODIFIER_KEYWORDS_ARRAY.indexOf(modifierToken)
|
val index = MODIFIER_KEYWORDS_ARRAY.indexOf(modifierToken)
|
||||||
assert(index >= 0) { "All JetModifierKeywordTokens should be present in MODIFIER_KEYWORDS_ARRAY" }
|
assert(index >= 0) { "All JetModifierKeywordTokens should be present in MODIFIER_KEYWORDS_ARRAY" }
|
||||||
return (mask and (1 shl index)) != 0
|
return (mask and (1L shl index)) != 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun maskToString(mask: Int): String {
|
fun maskToString(mask: Long): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
sb.append("[")
|
sb.append("[")
|
||||||
var first = true
|
var first = true
|
||||||
|
|||||||
+7
@@ -104,6 +104,9 @@ private class ClassClsStubBuilder(
|
|||||||
relevantFlags.add(MODALITY)
|
relevantFlags.add(MODALITY)
|
||||||
relevantFlags.add(INLINE_CLASS)
|
relevantFlags.add(INLINE_CLASS)
|
||||||
}
|
}
|
||||||
|
if (isInterface()) {
|
||||||
|
relevantFlags.add(FUN_INTERFACE)
|
||||||
|
}
|
||||||
val additionalModifiers = when (classKind) {
|
val additionalModifiers = when (classKind) {
|
||||||
ProtoBuf.Class.Kind.ENUM_CLASS -> listOf(KtTokens.ENUM_KEYWORD)
|
ProtoBuf.Class.Kind.ENUM_CLASS -> listOf(KtTokens.ENUM_KEYWORD)
|
||||||
ProtoBuf.Class.Kind.COMPANION_OBJECT -> listOf(KtTokens.COMPANION_KEYWORD)
|
ProtoBuf.Class.Kind.COMPANION_OBJECT -> listOf(KtTokens.COMPANION_KEYWORD)
|
||||||
@@ -227,6 +230,10 @@ private class ClassClsStubBuilder(
|
|||||||
classKind == ProtoBuf.Class.Kind.ANNOTATION_CLASS
|
classKind == ProtoBuf.Class.Kind.ANNOTATION_CLASS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isInterface(): Boolean {
|
||||||
|
return classKind == ProtoBuf.Class.Kind.INTERFACE
|
||||||
|
}
|
||||||
|
|
||||||
private fun createInnerAndNestedClasses(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
|
private fun createInnerAndNestedClasses(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
|
||||||
classProto.nestedClassNameList.forEach { id ->
|
classProto.nestedClassNameList.forEach { id ->
|
||||||
val nestedClassName = c.nameResolver.getName(id)
|
val nestedClassName = c.nameResolver.getName(id)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.decompiler.stubBuilder.flags
|
package org.jetbrains.kotlin.idea.decompiler.stubBuilder.flags
|
||||||
|
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
@@ -51,6 +52,7 @@ val EXTERNAL_PROPERTY = createBooleanFlagToModifier(Flags.IS_EXTERNAL_PROPERTY,
|
|||||||
val EXTERNAL_CLASS = createBooleanFlagToModifier(Flags.IS_EXTERNAL_CLASS, KtTokens.EXTERNAL_KEYWORD)
|
val EXTERNAL_CLASS = createBooleanFlagToModifier(Flags.IS_EXTERNAL_CLASS, KtTokens.EXTERNAL_KEYWORD)
|
||||||
val INLINE = createBooleanFlagToModifier(Flags.IS_INLINE, KtTokens.INLINE_KEYWORD)
|
val INLINE = createBooleanFlagToModifier(Flags.IS_INLINE, KtTokens.INLINE_KEYWORD)
|
||||||
val INLINE_CLASS = createBooleanFlagToModifier(Flags.IS_INLINE_CLASS, KtTokens.INLINE_KEYWORD)
|
val INLINE_CLASS = createBooleanFlagToModifier(Flags.IS_INLINE_CLASS, KtTokens.INLINE_KEYWORD)
|
||||||
|
val FUN_INTERFACE = createBooleanFlagToModifier(Flags.IS_FUN_INTERFACE, KtTokens.FUN_KEYWORD)
|
||||||
val TAILREC = createBooleanFlagToModifier(Flags.IS_TAILREC, KtTokens.TAILREC_KEYWORD)
|
val TAILREC = createBooleanFlagToModifier(Flags.IS_TAILREC, KtTokens.TAILREC_KEYWORD)
|
||||||
val SUSPEND = createBooleanFlagToModifier(Flags.IS_SUSPEND, KtTokens.SUSPEND_KEYWORD)
|
val SUSPEND = createBooleanFlagToModifier(Flags.IS_SUSPEND, KtTokens.SUSPEND_KEYWORD)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// IntelliJ API Decompiler stub source generated from a class file
|
||||||
|
// Implementation of methods is not available
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
public final class FunInterfaceDeclaration public constructor() {
|
||||||
|
public fun interface GenericKRunnable<T, R> {
|
||||||
|
public abstract fun invoke(t: T): R
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun interface KRunnable {
|
||||||
|
public abstract fun invoke(): kotlin.Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class FunInterfaceDeclaration {
|
||||||
|
@Suppress("UNSUPPORTED_FEATURE")
|
||||||
|
fun interface KRunnable {
|
||||||
|
fun invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNSUPPORTED_FEATURE")
|
||||||
|
fun interface GenericKRunnable<T, R> {
|
||||||
|
fun invoke(t: T): R
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class FunInterfaceDeclaration {
|
||||||
|
@Suppress("UNSUPPORTED_FEATURE")
|
||||||
|
fun interface KRunnable {
|
||||||
|
fun invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNSUPPORTED_FEATURE")
|
||||||
|
fun interface GenericKRunnable<T, R> {
|
||||||
|
fun invoke(t: T): R
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
PsiJetFileStubImpl[package=test]
|
||||||
|
PACKAGE_DIRECTIVE
|
||||||
|
REFERENCE_EXPRESSION[referencedName=test]
|
||||||
|
IMPORT_LIST
|
||||||
|
CLASS[fqName=test.FunInterfaceDeclaration, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=FunInterfaceDeclaration, superNames=[]]
|
||||||
|
MODIFIER_LIST[public final]
|
||||||
|
PRIMARY_CONSTRUCTOR
|
||||||
|
MODIFIER_LIST[public]
|
||||||
|
VALUE_PARAMETER_LIST
|
||||||
|
CLASS_BODY
|
||||||
|
CLASS[fqName=test.FunInterfaceDeclaration.GenericKRunnable, isEnumEntry=false, isInterface=true, isLocal=false, isTopLevel=false, name=GenericKRunnable, superNames=[]]
|
||||||
|
MODIFIER_LIST[public fun]
|
||||||
|
TYPE_PARAMETER_LIST
|
||||||
|
TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T]
|
||||||
|
TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=R]
|
||||||
|
CLASS_BODY
|
||||||
|
FUN[fqName=test.FunInterfaceDeclaration.GenericKRunnable.invoke, hasBlockBody=true, hasBody=false, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, mayHaveContract=false, name=invoke]
|
||||||
|
MODIFIER_LIST[abstract public]
|
||||||
|
VALUE_PARAMETER_LIST
|
||||||
|
VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=t]
|
||||||
|
TYPE_REFERENCE
|
||||||
|
USER_TYPE
|
||||||
|
REFERENCE_EXPRESSION[referencedName=T]
|
||||||
|
TYPE_REFERENCE
|
||||||
|
USER_TYPE
|
||||||
|
REFERENCE_EXPRESSION[referencedName=R]
|
||||||
|
CLASS[fqName=test.FunInterfaceDeclaration.KRunnable, isEnumEntry=false, isInterface=true, isLocal=false, isTopLevel=false, name=KRunnable, superNames=[]]
|
||||||
|
MODIFIER_LIST[public fun]
|
||||||
|
CLASS_BODY
|
||||||
|
FUN[fqName=test.FunInterfaceDeclaration.KRunnable.invoke, hasBlockBody=true, hasBody=false, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, mayHaveContract=false, name=invoke]
|
||||||
|
MODIFIER_LIST[abstract public]
|
||||||
|
VALUE_PARAMETER_LIST
|
||||||
|
TYPE_REFERENCE
|
||||||
|
USER_TYPE
|
||||||
|
USER_TYPE
|
||||||
|
REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
REFERENCE_EXPRESSION[referencedName=Unit]
|
||||||
Generated
+5
@@ -118,6 +118,11 @@ public class ClsStubBuilderTestGenerated extends AbstractClsStubBuilderTest {
|
|||||||
runTest("idea/testData/decompiler/stubBuilder/FlexibleTypes/");
|
runTest("idea/testData/decompiler/stubBuilder/FlexibleTypes/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FunInterfaceDeclaration")
|
||||||
|
public void testFunInterfaceDeclaration() throws Exception {
|
||||||
|
runTest("idea/testData/decompiler/stubBuilder/FunInterfaceDeclaration/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InheritingClasses")
|
@TestMetadata("InheritingClasses")
|
||||||
public void testInheritingClasses() throws Exception {
|
public void testInheritingClasses() throws Exception {
|
||||||
runTest("idea/testData/decompiler/stubBuilder/InheritingClasses/");
|
runTest("idea/testData/decompiler/stubBuilder/InheritingClasses/");
|
||||||
|
|||||||
+18
@@ -79,6 +79,11 @@ public class CommonDecompiledTextFromJsMetadataTestGenerated extends AbstractCom
|
|||||||
runTest("idea/testData/decompiler/decompiledText/Enum/");
|
runTest("idea/testData/decompiler/decompiledText/Enum/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FunInterfaceDeclaration")
|
||||||
|
public void testFunInterfaceDeclaration() throws Exception {
|
||||||
|
runTest("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("FunctionTypes")
|
@TestMetadata("FunctionTypes")
|
||||||
public void testFunctionTypes() throws Exception {
|
public void testFunctionTypes() throws Exception {
|
||||||
runTest("idea/testData/decompiler/decompiledText/FunctionTypes/");
|
runTest("idea/testData/decompiler/decompiledText/FunctionTypes/");
|
||||||
@@ -277,6 +282,19 @@ public class CommonDecompiledTextFromJsMetadataTestGenerated extends AbstractCom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FunInterfaceDeclaration extends AbstractCommonDecompiledTextFromJsMetadataTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFunInterfaceDeclaration() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/decompiler/decompiledText/FunctionTypes")
|
@TestMetadata("idea/testData/decompiler/decompiledText/FunctionTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+18
@@ -83,6 +83,11 @@ public class CommonDecompiledTextTestGenerated extends AbstractCommonDecompiledT
|
|||||||
runTest("idea/testData/decompiler/decompiledText/FlexibleTypes/");
|
runTest("idea/testData/decompiler/decompiledText/FlexibleTypes/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FunInterfaceDeclaration")
|
||||||
|
public void testFunInterfaceDeclaration() throws Exception {
|
||||||
|
runTest("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("FunctionTypes")
|
@TestMetadata("FunctionTypes")
|
||||||
public void testFunctionTypes() throws Exception {
|
public void testFunctionTypes() throws Exception {
|
||||||
runTest("idea/testData/decompiler/decompiledText/FunctionTypes/");
|
runTest("idea/testData/decompiler/decompiledText/FunctionTypes/");
|
||||||
@@ -281,6 +286,19 @@ public class CommonDecompiledTextTestGenerated extends AbstractCommonDecompiledT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FunInterfaceDeclaration extends AbstractCommonDecompiledTextTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFunInterfaceDeclaration() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/decompiler/decompiledText/FunInterfaceDeclaration"), Pattern.compile("^([^\\.]+)$"), null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/decompiler/decompiledText/FunctionTypes")
|
@TestMetadata("idea/testData/decompiler/decompiledText/FunctionTypes")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user