diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LightMemberOriginForCompiledElement.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LightMemberOriginForCompiledElement.kt index fa4e96f2b2c..03473130556 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LightMemberOriginForCompiledElement.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LightMemberOriginForCompiledElement.kt @@ -28,7 +28,9 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledTextIndexer import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.MemberSignature import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtDeclarationContainer import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind @@ -51,7 +53,7 @@ data class LightMemberOriginForCompiledField(val psiField: PsiField, val file: K override val originalElement: KtDeclaration? by lazy(LazyThreadSafetyMode.PUBLICATION) { val desc = MapPsiToAsmDesc.typeDesc(psiField.type) val signature = MemberSignature.fromFieldNameAndDesc(psiField.name!!, desc) - file.getDeclaration(ByJvmSignatureIndexer, ClassNameAndSignature(psiField.relativeClassName(), signature)) + findDeclarationInCompiledFile(file, psiField, signature) } } @@ -63,10 +65,38 @@ data class LightMemberOriginForCompiledMethod(val psiMethod: PsiMethod, val file override val originalElement: KtDeclaration? by lazy(LazyThreadSafetyMode.PUBLICATION) { val desc = MapPsiToAsmDesc.methodDesc(psiMethod) val signature = MemberSignature.fromMethodNameAndDesc(psiMethod.name, desc) - file.getDeclaration(ByJvmSignatureIndexer, ClassNameAndSignature(psiMethod.relativeClassName(), signature)) + findDeclarationInCompiledFile(file, psiMethod, signature) } } +private fun findDeclarationInCompiledFile(file: KtClsFile, member: PsiMember, signature: MemberSignature): KtDeclaration? { + val relativeClassName = member.relativeClassName() + val key = ClassNameAndSignature(relativeClassName, signature) + + val memberName = member.name + + if (memberName != null && !file.isContentsLoaded && file.hasDeclarationWithKey(ByJvmSignatureIndexer, key)) { + val container: KtDeclarationContainer? = if (relativeClassName.isEmpty()) + file + else { + val topClassOrObject = file.declarations.singleOrNull() as? KtClassOrObject + relativeClassName.fold(topClassOrObject) { classOrObject, name -> + classOrObject?.declarations?.singleOrNull { it.name == name.asString() } as? KtClassOrObject + } + } + + val declaration = container?.declarations?.singleOrNull { + it.name == memberName + } + + if (declaration != null) { + return declaration + } + } + + return file.getDeclaration(ByJvmSignatureIndexer, key) +} + // this is convenient data structure for this purpose and is not supposed to be used outside this file // every member is represented by its jvm signature and relative class name (which is easy to obtain from descriptors or cls psi) diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.java b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.java new file mode 100644 index 00000000000..7ffa7c30f64 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.java @@ -0,0 +1,11 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import test.kotlin.A.B.C.C; + +public class FunctionInNestedClassInDataFlowInspection { + void other(@NotNull Object some) { + Object foo = new C().foo(some); + } +} + diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.kt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.kt new file mode 100644 index 00000000000..a60b152bbec --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.kt @@ -0,0 +1,11 @@ +package test.kotlin + +class A { + class B { + class C { + class C { + fun foo(a: Any): Any = a + } + } + } +} diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.txt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.txt new file mode 100644 index 00000000000..667982be541 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.txt @@ -0,0 +1 @@ +// TOOL: DataFlowInspection \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.java b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.java new file mode 100644 index 00000000000..3f718388985 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.java @@ -0,0 +1,10 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import test.kotlin.*; + +public class TopLevelFunctionWithNameSimilarToClassInDataFlowInspection { + void other(@NotNull Object some) { + Object foo = TopLevelFunctionWithNameSimilarToClassInDataFlowInspectionKt.foo(some); + } +} diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt new file mode 100644 index 00000000000..9576560eb10 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt @@ -0,0 +1,4 @@ +package test.kotlin + +class foo +fun foo(a: Any): Any = a \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.txt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.txt new file mode 100644 index 00000000000..667982be541 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.txt @@ -0,0 +1 @@ +// TOOL: DataFlowInspection \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.java b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.java new file mode 100644 index 00000000000..02e968a4dff --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.java @@ -0,0 +1,10 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import test.kotlin.*; + +public class TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection { + void other(@NotNull Object some) { + Object foo = (new Test()).foo(some); + } +} diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt new file mode 100644 index 00000000000..d8a16395a3a --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt @@ -0,0 +1,8 @@ +package test.kotlin + +class Test { + val foo: Int = 12 + fun foo(a: Any): Any = a +} + +// ALLOW_AST_ACCESS \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.txt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.txt new file mode 100644 index 00000000000..667982be541 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.txt @@ -0,0 +1 @@ +// TOOL: DataFlowInspection \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.java b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.java new file mode 100644 index 00000000000..4a92f000756 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.java @@ -0,0 +1,10 @@ +package test; + +import org.jetbrains.annotations.NotNull; +import test.kotlin.*; + +public class TopLevelOverloadedFunctionInDataFlowInspection { + void other(@NotNull Object some) { + Object foo = TopLevelOverloadedFunctionInDataFlowInspectionKt.foo(some); + } +} diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.kt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.kt new file mode 100644 index 00000000000..8b67e796d1e --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.kt @@ -0,0 +1,7 @@ +package test.kotlin + +fun foo(a: Any?, b: Any): Any? = a +fun foo(a: Any): Any = a + + +// ALLOW_AST_ACCESS \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.txt b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.txt new file mode 100644 index 00000000000..667982be541 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.txt @@ -0,0 +1 @@ +// TOOL: DataFlowInspection \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/checkers/AbstractJavaAgainstKotlinBinariesCheckerTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/AbstractJavaAgainstKotlinBinariesCheckerTest.kt index ac6a39b1bc8..b606e2587c7 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/AbstractJavaAgainstKotlinBinariesCheckerTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/AbstractJavaAgainstKotlinBinariesCheckerTest.kt @@ -17,10 +17,14 @@ package org.jetbrains.kotlin.checkers import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt +import org.jetbrains.kotlin.idea.test.AstAccessControl import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.MockLibraryUtil +import java.io.File abstract class AbstractJavaAgainstKotlinBinariesCheckerTest : AbstractJavaAgainstKotlinCheckerTest() { override fun setUp() { @@ -39,6 +43,13 @@ abstract class AbstractJavaAgainstKotlinBinariesCheckerTest : AbstractJavaAgains } fun doTest(path: String) { + val ktFileText = FileUtil.loadFile(File(path), true) + val allowAstForCompiledFile = InTextDirectivesUtils.isDirectiveDefined(ktFileText, AstAccessControl.ALLOW_AST_ACCESS_DIRECTIVE) + + if (allowAstForCompiledFile) { + allowTreeAccessForAllFiles() + } + doTest(true, true, path.replace(".kt", ".java")) } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinBinariesCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinBinariesCheckerTestGenerated.java index a8da8668424..221bebaf65e 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinBinariesCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinBinariesCheckerTestGenerated.java @@ -72,6 +72,12 @@ public class JavaAgainstKotlinBinariesCheckerTestGenerated extends AbstractJavaA doTest(fileName); } + @TestMetadata("FunctionInNestedClassInDataFlowInspection.kt") + public void testFunctionInNestedClassInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.kt"); + doTest(fileName); + } + @TestMetadata("ImplementedMethodsFromTraits.kt") public void testImplementedMethodsFromTraits() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/ImplementedMethodsFromTraits.kt"); @@ -120,6 +126,24 @@ public class JavaAgainstKotlinBinariesCheckerTestGenerated extends AbstractJavaA doTest(fileName); } + @TestMetadata("TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt") + public void testTopLevelFunctionWithNameSimilarToClassInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt") + public void testTopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelOverloadedFunctionInDataFlowInspection.kt") + public void testTopLevelOverloadedFunctionInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.kt"); + doTest(fileName); + } + @TestMetadata("UseKotlinConstInSwitch.kt") public void testUseKotlinConstInSwitch() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/UseKotlinConstInSwitch.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinSourceCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinSourceCheckerTestGenerated.java index 14299ee4015..20e0fb359c5 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinSourceCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/JavaAgainstKotlinSourceCheckerTestGenerated.java @@ -74,6 +74,12 @@ public class JavaAgainstKotlinSourceCheckerTestGenerated extends AbstractJavaAga doTest(fileName); } + @TestMetadata("FunctionInNestedClassInDataFlowInspection.kt") + public void testFunctionInNestedClassInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/FunctionInNestedClassInDataFlowInspection.kt"); + doTest(fileName); + } + @TestMetadata("ImplementedMethodsFromTraits.kt") public void testImplementedMethodsFromTraits() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/ImplementedMethodsFromTraits.kt"); @@ -122,6 +128,24 @@ public class JavaAgainstKotlinSourceCheckerTestGenerated extends AbstractJavaAga doTest(fileName); } + @TestMetadata("TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt") + public void testTopLevelFunctionWithNameSimilarToClassInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToClassInDataFlowInspection.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt") + public void testTopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelFunctionWithNameSimilarToPropertyInDataFlowInspection.kt"); + doTest(fileName); + } + + @TestMetadata("TopLevelOverloadedFunctionInDataFlowInspection.kt") + public void testTopLevelOverloadedFunctionInDataFlowInspection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/TopLevelOverloadedFunctionInDataFlowInspection.kt"); + doTest(fileName); + } + @TestMetadata("UseKotlinConstInSwitch.kt") public void testUseKotlinConstInSwitch() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/kotlinAndJavaChecker/javaAgainstKotlin/UseKotlinConstInSwitch.kt");