From d1dfcfaca10b2b6cf4c557acd020e75d31586eb8 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 21 Oct 2016 16:50:14 +0300 Subject: [PATCH] Fix stub-psi mismatch exception on restoring annotation for nullable types (cherry picked from commit 1aa37f11258dde289a9f7cb700294a038168fbdc) Conflicts: compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt --- .../kotlin/psi/stubs/KotlinStubVersions.kt | 2 +- .../stubBuilder/TypeClsStubBuilder.kt | 35 ++-- .../AnnotationsOnNullableTypes.kt | 27 +++ .../AnnotationsOnNullableTypes.txt | 168 ++++++++++++++++++ idea/testData/stubs/DynamicType.expected | 28 +++ idea/testData/stubs/DynamicType.kt | 8 +- .../stubBuilder/AbstractClsStubBuilderTest.kt | 2 +- .../ClsStubBuilderTestGenerated.java | 6 + 8 files changed, 258 insertions(+), 18 deletions(-) create mode 100644 idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.kt create mode 100644 idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt index a8ba4bb7dd4..799db9ca2d6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt @@ -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 = 53 + private const val BINARY_STUB_VERSION = 54 // 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. diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt index 9dfdf1a41cf..8d3be4c8c14 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt @@ -55,28 +55,31 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { isTopLevelClass && it.asSingleFqName() in ANNOTATIONS_NOT_LOADED_FOR_TYPES } - val effectiveParent = - if (type.nullable) KotlinPlaceHolderStubImpl(typeReference, KtStubElementTypes.NULLABLE_TYPE) - else typeReference - - fun createTypeParameterStub(name: Name) { - createTypeAnnotationStubs(effectiveParent, annotations) - createStubForTypeName(ClassId.topLevel(FqName.topLevel(name)), effectiveParent) - } - when { - type.hasClassName() || type.hasTypeAliasName() -> createClassReferenceTypeStub(effectiveParent, type, annotations) - type.hasTypeParameter() -> createTypeParameterStub(c.typeParameters[type.typeParameter]) - type.hasTypeParameterName() -> createTypeParameterStub(c.nameResolver.getName(type.typeParameterName)) + type.hasClassName() || type.hasTypeAliasName() -> + createClassReferenceTypeStub(typeReference, type, annotations) + type.hasTypeParameter() -> + createTypeParameterStub(typeReference, type, c.typeParameters[type.typeParameter], annotations) + type.hasTypeParameterName() -> + createTypeParameterStub(typeReference, type, c.nameResolver.getName(type.typeParameterName), annotations) } } + private fun nullableTypeParent(parent: KotlinStubBaseImpl<*>, type: Type): KotlinStubBaseImpl<*> = + if (type.nullable) KotlinPlaceHolderStubImpl(parent, KtStubElementTypes.NULLABLE_TYPE) + else parent + + private fun createTypeParameterStub(parent: KotlinStubBaseImpl<*>, type: Type, name: Name, annotations: List) { + createTypeAnnotationStubs(parent, annotations) + createStubForTypeName(ClassId.topLevel(FqName.topLevel(name)), nullableTypeParent(parent, type)) + } + private fun createClassReferenceTypeStub(parent: KotlinStubBaseImpl<*>, type: Type, annotations: List) { if (type.hasFlexibleTypeCapabilitiesId()) { val id = c.nameResolver.getString(type.flexibleTypeCapabilitiesId) if (id == DynamicTypeDeserializer.id) { - KotlinPlaceHolderStubImpl(parent, KtStubElementTypes.DYNAMIC_TYPE) + KotlinPlaceHolderStubImpl(nullableTypeParent(parent, type), KtStubElementTypes.DYNAMIC_TYPE) return } } @@ -92,13 +95,15 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { val extension = annotations.any { annotation -> annotation.asSingleFqName() == KotlinBuiltIns.FQ_NAMES.extensionFunctionType } - createFunctionTypeStub(parent, type, extension) + createFunctionTypeStub(nullableTypeParent(parent, type), type, extension) return } + createTypeAnnotationStubs(parent, annotations) + val outerTypeChain = generateSequence(type) { it.outerType(c.typeTable) }.toList() - createStubForTypeName(classId, parent) { + createStubForTypeName(classId, nullableTypeParent(parent, type)) { userTypeStub, index -> outerTypeChain.getOrNull(index)?.let { createTypeArgumentListStub(userTypeStub, it.argumentList) } } diff --git a/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.kt b/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.kt new file mode 100644 index 00000000000..1c9a47ae28e --- /dev/null +++ b/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.kt @@ -0,0 +1,27 @@ +public class AnnotationsOnNullableTypes { + fun B<@A C?>.receiverArgument() {} + + fun parameter(a: @A C?) {} + + fun parameterArgument(a: B<@A C?>) {} + + fun returnValue(): @A C? = null + + fun returnTypeParameterValue(): @A T? = null + + fun returnArgument(): B<@A C?> = null!! + + val lambdaType: @A() (() -> C)? = null // TODO: Annotation is lost in stubs + + val lambdaParameter: (@A C?) -> C = null!! + + val lambdaReturnValue: () -> @A C? = null!! + + val lambdaReceiver: @A C.() -> C = null!! // TODO: Annotation is lost in stubs +} + +@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) +annotation class A + +interface B +interface C \ No newline at end of file diff --git a/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.txt b/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.txt new file mode 100644 index 00000000000..3982a334135 --- /dev/null +++ b/idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/AnnotationsOnNullableTypes.txt @@ -0,0 +1,168 @@ +PsiJetFileStubImpl[package=] + PACKAGE_DIRECTIVE + IMPORT_LIST + CLASS[fqName=AnnotationsOnNullableTypes, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=AnnotationsOnNullableTypes, superNames=[]] + MODIFIER_LIST[public final] + PRIMARY_CONSTRUCTOR + MODIFIER_LIST[public] + VALUE_PARAMETER_LIST + CLASS_BODY + PROPERTY[fqName=AnnotationsOnNullableTypes.lambdaParameter, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=lambdaParameter] + MODIFIER_LIST[public final] + TYPE_REFERENCE + FUNCTION_TYPE + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=null] + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + PROPERTY[fqName=AnnotationsOnNullableTypes.lambdaReceiver, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=lambdaReceiver] + MODIFIER_LIST[public final] + TYPE_REFERENCE + FUNCTION_TYPE + FUNCTION_TYPE_RECEIVER + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + VALUE_PARAMETER_LIST + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + PROPERTY[fqName=AnnotationsOnNullableTypes.lambdaReturnValue, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=lambdaReturnValue] + MODIFIER_LIST[public final] + TYPE_REFERENCE + FUNCTION_TYPE + VALUE_PARAMETER_LIST + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + PROPERTY[fqName=AnnotationsOnNullableTypes.lambdaType, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=lambdaType] + MODIFIER_LIST[public final] + TYPE_REFERENCE + NULLABLE_TYPE + FUNCTION_TYPE + VALUE_PARAMETER_LIST + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + FUN[fqName=AnnotationsOnNullableTypes.parameter, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, name=parameter] + MODIFIER_LIST[public final] + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=a] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] + FUN[fqName=AnnotationsOnNullableTypes.parameterArgument, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, name=parameterArgument] + MODIFIER_LIST[public final] + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=a] + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=B] + TYPE_ARGUMENT_LIST + TYPE_PROJECTION[projectionKind=NONE] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] + FUN[fqName=AnnotationsOnNullableTypes.returnArgument, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, name=returnArgument] + MODIFIER_LIST[public final] + VALUE_PARAMETER_LIST + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=B] + TYPE_ARGUMENT_LIST + TYPE_PROJECTION[projectionKind=NONE] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + FUN[fqName=AnnotationsOnNullableTypes.returnTypeParameterValue, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=false, isTopLevel=false, name=returnTypeParameterValue] + MODIFIER_LIST[public final] + TYPE_PARAMETER_LIST + TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T] + VALUE_PARAMETER_LIST + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=T] + FUN[fqName=AnnotationsOnNullableTypes.returnValue, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, name=returnValue] + MODIFIER_LIST[public final] + VALUE_PARAMETER_LIST + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + FUN[fqName=AnnotationsOnNullableTypes.receiverArgument, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=true, isTopLevel=false, name=receiverArgument] + MODIFIER_LIST[public final] + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=B] + TYPE_ARGUMENT_LIST + TYPE_PROJECTION[projectionKind=NONE] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=C] + VALUE_PARAMETER_LIST + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] diff --git a/idea/testData/stubs/DynamicType.expected b/idea/testData/stubs/DynamicType.expected index 886d9583ac9..50d3c69be13 100644 --- a/idea/testData/stubs/DynamicType.expected +++ b/idea/testData/stubs/DynamicType.expected @@ -4,3 +4,31 @@ PsiJetFileStubImpl[package=] PROPERTY[fqName=foo, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=foo] TYPE_REFERENCE DYNAMIC_TYPE + PROPERTY[fqName=foo_nullable, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=foo_nullable] + TYPE_REFERENCE + NULLABLE_TYPE + DYNAMIC_TYPE + PROPERTY[fqName=foo_a, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=foo_a] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + DYNAMIC_TYPE + PROPERTY[fqName=foo_nullable_a, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=foo_nullable_a] + TYPE_REFERENCE + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + DYNAMIC_TYPE + CLASS[fqName=A, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=A, superNames=[]] + MODIFIER_LIST[annotation] + ANNOTATION_ENTRY[hasValueArguments=true, shortName=Target] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=Target] diff --git a/idea/testData/stubs/DynamicType.kt b/idea/testData/stubs/DynamicType.kt index 3b7ed01a479..5897121deac 100644 --- a/idea/testData/stubs/DynamicType.kt +++ b/idea/testData/stubs/DynamicType.kt @@ -1 +1,7 @@ -val foo: dynamic \ No newline at end of file +val foo: dynamic +val foo_nullable: dynamic? +val foo_a: @A dynamic +val foo_nullable_a: @A dynamic? + +@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) +annotation class A \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt index 2fce1393040..daf051febf5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt @@ -73,7 +73,7 @@ fun VirtualFile.findClassFileByName(className: String): VirtualFile { val files = LinkedHashSet() VfsUtilCore.iterateChildrenRecursively( this, - { virtualFile -> virtualFile.isDirectory || virtualFile.name.equals("$className.class") }, + { virtualFile -> virtualFile.isDirectory || virtualFile.name == "$className.class" }, { virtualFile -> if (!virtualFile.isDirectory) files.addIfNotNull(virtualFile); true }) return files.single() diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java index 0d40356e7d9..2b9e5714126 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java @@ -53,6 +53,12 @@ public class ClsStubBuilderTestGenerated extends AbstractClsStubBuilderTest { doTest(fileName); } + @TestMetadata("AnnotationsOnNullableTypes") + public void testAnnotationsOnNullableTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/AnnotationsOnNullableTypes/"); + doTest(fileName); + } + @TestMetadata("ClassMembers") public void testClassMembers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/ClassMembers/");