Avoid loading psi for compiled kotlin file if it's possible to get declaration by name from stubs

This commit is contained in:
Nikolay Krasko
2016-12-02 15:58:08 +03:00
parent 299f477a1b
commit 726471d98e
16 changed files with 166 additions and 2 deletions
@@ -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<Name, KtClassOrObject?>(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)
@@ -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);
}
}
@@ -0,0 +1,11 @@
package test.kotlin
class A {
class B {
class C {
class C {
fun foo(a: Any): Any = a
}
}
}
}
@@ -0,0 +1 @@
// TOOL: DataFlowInspection
@@ -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);
}
}
@@ -0,0 +1,4 @@
package test.kotlin
class foo
fun foo(a: Any): Any = a
@@ -0,0 +1 @@
// TOOL: DataFlowInspection
@@ -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);
}
}
@@ -0,0 +1,8 @@
package test.kotlin
class Test {
val foo: Int = 12
fun foo(a: Any): Any = a
}
// ALLOW_AST_ACCESS
@@ -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);
}
}
@@ -0,0 +1,7 @@
package test.kotlin
fun foo(a: Any?, b: Any): Any? = a
fun foo(a: Any): Any = a
// ALLOW_AST_ACCESS
@@ -0,0 +1 @@
// TOOL: DataFlowInspection
@@ -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"))
}
}
@@ -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");
@@ -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");