From d87b13931dd83226c2cfd99ba0d3e4ec4ee8aea7 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 22 Jan 2016 14:25:14 +0300 Subject: [PATCH] Create special type for missing dependencies when resolving annotations #KT-10748 Fixed --- ...otationWithArgumentsMissingDependencies.kt | 12 +++++++++ ...tationWithArgumentsMissingDependencies.txt | 11 ++++++++ .../platformTypes/noAnnotationInClassPath.kt | 17 +++++++++++++ .../platformTypes/noAnnotationInClassPath.txt | 22 ++++++++++++++++ .../tests/regressions/kt1639-JFrame.txt | 6 ++--- .../checkers/DiagnosticsTestGenerated.java | 12 +++++++++ .../AbstractJvmRuntimeDescriptorLoaderTest.kt | 2 +- .../LazyJavaAnnotationDescriptor.kt | 21 +++++++++++++--- .../descriptors/impl/ClassDescriptorImpl.java | 16 ++++++++++-- .../impl/EmptyPackageFragmentDesciptor.kt | 25 +++++++++++++++++++ .../kotlin/idea/core/KotlinIndicesHelper.kt | 2 +- 11 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt create mode 100644 compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.kt create mode 100644 compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/EmptyPackageFragmentDesciptor.kt diff --git a/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.kt b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.kt new file mode 100644 index 00000000000..90f3fc6ea16 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.kt @@ -0,0 +1,12 @@ +// FILE: A.java +@missing.Ann(x = "") +public class A { + @missing.Ann(1) + public String foo() {} +} + +// FILE: main.kt + +fun main() { + A().foo().length +} diff --git a/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt new file mode 100644 index 00000000000..fa432313f28 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt @@ -0,0 +1,11 @@ +package + +public fun main(): kotlin.Unit + +@[Missing annotation class: missing.Ann]() public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @[Missing annotation class: missing.Ann]() public open fun foo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.kt b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.kt new file mode 100644 index 00000000000..9d7e4b8a14d --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.kt @@ -0,0 +1,17 @@ +// FILE: A.java + +// It's supposed that there is no JSR-305 annotation in classpath +public interface A { + public boolean foo(@javax.annotation.Nullable T y) {} +} + +// FILE: B.java + +public class B { + public static void bar(A y) {} +} + +// FILE: main.kt +fun test() { + B.bar() { it.hashCode() > 0 } +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt new file mode 100644 index 00000000000..ebb70227eed --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt @@ -0,0 +1,22 @@ +package + +public /*synthesized*/ fun A(/*0*/ function: (T!) -> kotlin.Boolean): A +public fun test(): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(/*0*/ @[Missing annotation class: javax.annotation.Nullable]() y: T?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun bar(/*0*/ y: ((kotlin.String?) -> kotlin.Boolean)!): kotlin.Unit + public open fun bar(/*0*/ y: A!): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.txt b/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.txt index 6522a169d2a..0835aa43840 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.txt +++ b/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.txt @@ -293,10 +293,10 @@ package test { invisible_fake final override /*1*/ /*fake_override*/ fun getFocusTraversalKeys_NoIDCheck(/*0*/ p0: kotlin.Int): kotlin.collections.(Mutable)Set<(raw) kotlin.Any?>! public open override /*1*/ /*fake_override*/ fun getFocusTraversalPolicy(): [ERROR : Unresolved java classifier: FocusTraversalPolicy]! public open override /*1*/ /*fake_override*/ fun getFocusableWindowState(): kotlin.Boolean - @[ERROR : java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun getFont(): [ERROR : Unresolved java classifier: Font]! + @[Missing annotation class: java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun getFont(): [ERROR : Unresolved java classifier: Font]! public open override /*1*/ /*fake_override*/ fun getFontMetrics(/*0*/ p0: [ERROR : Unresolved java classifier: Font]!): [ERROR : Unresolved java classifier: FontMetrics]! invisible_fake final override /*1*/ /*fake_override*/ fun getFont_NoClientCode(): [ERROR : Unresolved java classifier: Font]! - @[ERROR : java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun getForeground(): [ERROR : Unresolved java classifier: Color]! + @[Missing annotation class: java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun getForeground(): [ERROR : Unresolved java classifier: Color]! public open override /*1*/ /*fake_override*/ fun getGlassPane(): java.awt.Component! public open override /*1*/ /*fake_override*/ fun getGraphics(): [ERROR : Unresolved java classifier: Graphics]! public open override /*1*/ /*fake_override*/ fun getGraphicsConfiguration(): [ERROR : Unresolved java classifier: GraphicsConfiguration]! @@ -450,7 +450,7 @@ package test { public open override /*1*/ /*fake_override*/ fun isUndecorated(): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun isValid(): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun isValidateRoot(): kotlin.Boolean - @[ERROR : java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun isVisible(): kotlin.Boolean + @[Missing annotation class: java.beans.Transient]() public open override /*1*/ /*fake_override*/ fun isVisible(): kotlin.Boolean invisible_fake final override /*1*/ /*fake_override*/ fun isVisible_NoClientCode(): kotlin.Boolean @kotlin.Deprecated(message = "Deprecated in Java") public open override /*1*/ /*fake_override*/ fun keyDown(/*0*/ p0: [ERROR : Unresolved java classifier: Event]!, /*1*/ p1: kotlin.Int): kotlin.Boolean @kotlin.Deprecated(message = "Deprecated in Java") public open override /*1*/ /*fake_override*/ fun keyUp(/*0*/ p0: [ERROR : Unresolved java classifier: Event]!, /*1*/ p1: kotlin.Int): kotlin.Boolean diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index f3a1405035b..4fa40c644b5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9684,6 +9684,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("annotationWithArgumentsMissingDependencies.kt") + public void testAnnotationWithArgumentsMissingDependencies() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.kt"); + doTest(fileName); + } + @TestMetadata("arrayOfStarParametrized.kt") public void testArrayOfStarParametrized() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/arrayOfStarParametrized.kt"); @@ -11937,6 +11943,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("noAnnotationInClassPath.kt") + public void testNoAnnotationInClassPath() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.kt"); + doTest(fileName); + } + @TestMetadata("nullableTypeArgument.kt") public void testNullableTypeArgument() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/nullableTypeArgument.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt index b06b98c5449..eda34feb5ef 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt @@ -93,7 +93,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() { /* checkPropertyAccessors = */ true, /* includeMethodsOfKotlinAny = */ false, // Skip Java annotation constructors because order of their parameters is not retained at runtime - { descriptor -> !descriptor.isJavaAnnotationConstructor() }, + { descriptor -> !descriptor!!.isJavaAnnotationConstructor() }, errorTypesForbidden(), renderer ) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index 2263fadf6c4..79d6ffefc71 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -16,9 +16,11 @@ package org.jetbrains.kotlin.load.java.lazy.descriptors -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME import org.jetbrains.kotlin.load.java.JvmAnnotationNames.isSpecialAnnotation @@ -34,6 +36,7 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.utils.keysToMapExceptNulls @@ -56,7 +59,7 @@ class LazyJavaAnnotationDescriptor( val fqName = fqName() ?: return@createLazyValue ErrorUtils.createErrorType("No fqName: $javaAnnotation") val annotationClass = JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(fqName) ?: javaAnnotation.resolve()?.let { javaClass -> c.components.moduleClassResolver.resolveClass(javaClass) } - annotationClass?.getDefaultType() ?: ErrorUtils.createErrorType(fqName.asString()) + annotationClass?.defaultType ?: createTypeForMissingDependencies(fqName) } private val source = c.components.sourceElementFactory.source(javaAnnotation) @@ -156,4 +159,16 @@ class LazyJavaAnnotationDescriptor( override fun toString(): String { return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderAnnotation(this) } + + private fun createTypeForMissingDependencies(fqName: FqName) = + ErrorUtils.createErrorTypeWithCustomConstructor( + "[Missing annotation class: $fqName]", + ClassDescriptorImpl( + EmptyPackageFragmentDescriptor(c.module, fqName.parent()), fqName.shortName(), Modality.FINAL, + ClassKind.ANNOTATION_CLASS, listOf(c.module.builtIns.anyType), SourceElement.NO_SOURCE, + "[Missing annotation class: $fqName]" + ).apply { + initialize(MemberScope.Empty, emptySet(), null) + }.typeConstructor + ) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ClassDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ClassDescriptorImpl.java index aa8ad78f44f..3760b80cfca 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ClassDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ClassDescriptorImpl.java @@ -50,13 +50,25 @@ public class ClassDescriptorImpl extends ClassDescriptorBase { @NotNull ClassKind kind, @NotNull Collection supertypes, @NotNull SourceElement source + ) { + this(containingDeclaration, name, modality, kind, supertypes, source, name.asString()); + } + + public ClassDescriptorImpl( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull Name name, + @NotNull Modality modality, + @NotNull ClassKind kind, + @NotNull Collection supertypes, + @NotNull SourceElement source, + @NotNull String debugName ) { super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, name, source); this.modality = modality; this.kind = kind; - this.typeConstructor = TypeConstructorImpl.createForClass(this, Annotations.Companion.getEMPTY(), false, getName().asString(), - Collections.emptyList(), supertypes); + this.typeConstructor = TypeConstructorImpl.createForClass(this, Annotations.Companion.getEMPTY(), false, debugName, + Collections.emptyList(), supertypes); } public final void initialize( diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/EmptyPackageFragmentDesciptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/EmptyPackageFragmentDesciptor.kt new file mode 100644 index 00000000000..6d4f8fb8739 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/EmptyPackageFragmentDesciptor.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.descriptors.impl + +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.scopes.MemberScope + +class EmptyPackageFragmentDescriptor(module: ModuleDescriptor, fqName: FqName) : PackageFragmentDescriptorImpl(module, fqName) { + override fun getMemberScope() = MemberScope.Empty +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index e37a749e41a..3f89a73ca1a 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -215,7 +215,7 @@ class KotlinIndicesHelper( } // Note: Can't search with psi element as analyzer could be built over temp files - return ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(moduleDescriptor, classFQName) { kindFilter(it.kind) } + return ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(moduleDescriptor, classFQName) { kindFilter(it!!.kind) } .filter(descriptorFilter) }