diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt index 9ce1fc2ee39..f0ffad9fd7d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtReferenceExpression @@ -42,7 +43,7 @@ interface ClassifierUsageChecker { return } - val target = trace.bindingContext.get(BindingContext.REFERENCE_TARGET, expression) as? ClassifierDescriptor ?: return + val target = getReferencedClassifier(expression) ?: return for (checker in checkers) { checker.check(target, trace, expression) @@ -56,12 +57,26 @@ interface ClassifierUsageChecker { } } + private fun getReferencedClassifier(expression: KtReferenceExpression): ClassifierDescriptor? { + val target = trace.get(BindingContext.REFERENCE_TARGET, expression) as? ClassifierDescriptor + if (target != null) return target + + // "Comparable" in "import java.lang.Comparable" references both a class and a SAM constructor and prevents + // REFERENCE_TARGET from being recorded in favor of AMBIGUOUS_REFERENCE_TARGET. But we must still run checkers + // to report if there's something wrong with the class. We characterize this case below by the following properties: + // 1) Exactly one of the references is a classifier + // 2) All references refer to the same source element, i.e. their source is the same + val targets = trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression) ?: return null + if (targets.groupBy { (it as? DeclarationDescriptorWithSource)?.source }.size != 1) return null + return targets.filterIsInstance().singleOrNull() + } + /** * @return true iff [expression] references the companion of a class Foo via the name Foo, e.g. in `Foo.bar()` */ private fun isReferenceToCompanionViaOuterClass(expression: KtReferenceExpression, target: ClassifierDescriptor?): Boolean { return DescriptorUtils.isCompanionObject(target) && - trace.bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression] != null + trace.get(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression) != null } } diff --git a/compiler/testData/diagnostics/tests/deprecated/importJavaSamInterface.kt b/compiler/testData/diagnostics/tests/deprecated/importJavaSamInterface.kt new file mode 100644 index 00000000000..0d5a0ac64f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/importJavaSamInterface.kt @@ -0,0 +1,13 @@ +// SKIP_TXT +// FILE: test/J.java + +package test; + +@Deprecated +public interface J { + public String foo(int x); +} + +// FILE: K.kt + +import test.J diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 581f5adc164..9147709ad8d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -5946,6 +5946,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("importJavaSamInterface.kt") + public void testImportJavaSamInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/importJavaSamInterface.kt"); + doTest(fileName); + } + @TestMetadata("imports.kt") public void testImports() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/imports.kt");