Try to avoid loading ast for decompiled files (KT-14804)

#KT-14804 Fixed
This commit is contained in:
Nikolay Krasko
2016-11-23 21:59:44 +03:00
parent 68df8c55e7
commit b816c182f0
7 changed files with 113 additions and 16 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationContainer
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -147,6 +148,24 @@ object ByDescriptorIndexer : DecompiledTextIndexer<String> {
return classOrObject?.getPrimaryConstructor() ?: classOrObject
}
if (!file.isContentsLoaded) {
if (original is MemberDescriptor) {
val declarationContainer: KtDeclarationContainer? = when {
DescriptorUtils.isTopLevelDeclaration(original) -> file
original.containingDeclaration is ClassDescriptor ->
getDeclarationForDescriptor(original.containingDeclaration as ClassDescriptor, file) as? KtClassOrObject
else -> null
}
if (declarationContainer != null) {
val descriptorName = original.name.asString()
val singleOrNull = declarationContainer.declarations.singleOrNull { it.name == descriptorName }
if (singleOrNull != null) {
return singleOrNull
}
}
}
}
return file.getDeclaration(this, original.toStringKey()) ?: run {
if (descriptor !is ClassDescriptor) return null
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileFilter
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiManagerImpl
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import kotlin.test.fail
@@ -48,15 +49,16 @@ object AstAccessControl {
shouldFail: Boolean, allowedFiles: List<VirtualFile>,
project: Project, disposable: Disposable, testBody: () -> Unit
) {
setFilter(allowedFiles, disposable, project)
performTest(shouldFail, testBody)
val filter = wrapWithDirectiveAllow { file ->
file.fileType != KotlinFileType.INSTANCE || file in allowedFiles
}
execute(shouldFail, project, disposable, filter, testBody)
}
private fun setFilter(allowedFiles: List<VirtualFile>, disposable: Disposable, project: Project) {
val manager = (PsiManager.getInstance(project) as PsiManagerImpl)
val filter = VirtualFileFilter {
file ->
if (file!!.fileType != KotlinFileType.INSTANCE || file in allowedFiles) {
fun wrapWithDirectiveAllow(allowedFiles: (VirtualFile) -> Boolean): (VirtualFile) -> Boolean {
return { file ->
if (allowedFiles(file)) {
false
}
else {
@@ -64,23 +66,38 @@ object AstAccessControl {
!InTextDirectivesUtils.isDirectiveDefined(text, ALLOW_AST_ACCESS_DIRECTIVE)
}
}
manager.setAssertOnFileLoadingFilter(filter, disposable)
}
private fun performTest(shouldFail: Boolean, testBody: () -> Unit) {
fun <T : Any> execute(shouldFail: Boolean, disposable: Disposable, fixture: CodeInsightTestFixture, testBody: () -> T): T? {
return execute(shouldFail, fixture.project, disposable, { file -> file != fixture.file.virtualFile }, testBody)
}
private fun <T : Any> execute(shouldFail: Boolean, project: Project, disposable: Disposable,
forbidAstAccessFilter: (VirtualFile) -> Boolean, testBody: () -> T): T? {
val manager = (PsiManager.getInstance(project) as PsiManagerImpl)
manager.setAssertOnFileLoadingFilter(VirtualFileFilter { file -> forbidAstAccessFilter(file) }, disposable)
try {
testBody()
val result = testBody()
if (shouldFail) {
fail("This failure means that that a test that should fail (by triggering ast switch) in fact did not.\n" +
"This could happen for the following reasons:\n" +
"1. This kind of operation no longer trigger ast switch, choose better indicator test case." +
"2. Test is now misconfigured and no longer checks for ast switch, reconfigure the test.")
"This could happen for the following reasons:\n" +
"1. This kind of operation no longer trigger ast switch, choose better indicator test case." +
"2. Test is now misconfigured and no longer checks for ast switch, reconfigure the test.")
}
return result
}
catch (e: Throwable) {
if (!shouldFail) {
throw e
}
}
finally {
manager.setAssertOnFileLoadingFilter(VirtualFileFilter.NONE, disposable)
}
return null
}
}
+10
View File
@@ -0,0 +1,10 @@
package test
import dependency.*
fun foo() {
t<caret>est("")
}
// ALLOW_AST_ACCESS
// REF: (dependency).test(kotlin.String)
@@ -0,0 +1,7 @@
package dependency
fun test(a: Int) {
}
fun test(a: String) {
}
@@ -58,7 +58,7 @@ abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixt
protected fun doSingleResolveTest() {
forEachCaret { index, offset ->
val expectedResolveData = readResolveData(myFixture.file.text, index, refMarkerText)
val psiReference = myFixture.file.findReferenceAt(offset)
val psiReference = wrapReference(myFixture.file.findReferenceAt(offset))
checkReferenceResolve(expectedResolveData, offset, psiReference) { checkResolvedTo(it) }
}
}
@@ -67,6 +67,9 @@ abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixt
// do nothing
}
open fun wrapReference(reference: PsiReference?): PsiReference? = reference
open fun wrapReference(reference: PsiPolyVariantReference): PsiPolyVariantReference = reference
protected fun doMultiResolveTest() {
forEachCaret { index, offset ->
val expectedReferences = getExpectedReferences(myFixture.file.text, index, refMarkerText)
@@ -75,7 +78,7 @@ abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixt
assertTrue(psiReference is PsiPolyVariantReference)
psiReference as PsiPolyVariantReference
val results = psiReference.multiResolve(true)
val results = wrapReference(psiReference).multiResolve(true)
val actualResolvedTo = Lists.newArrayList<String>()
for (result in results) {
@@ -140,7 +143,7 @@ abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixt
}
else {
if (!expectedResolveData.shouldBeUnresolved()) {
assertNull("Element $psiReference wasn't resolved to anything, but $expectedString was expected", expectedString)
assertNull("Element $psiReference (${psiReference.element.text}) wasn't resolved to anything, but $expectedString was expected", expectedString)
}
}
}
@@ -16,9 +16,16 @@
package org.jetbrains.kotlin.idea.resolve;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiDelegateReference;
import com.intellij.testFramework.LightProjectDescriptor;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.test.AstAccessControl;
import org.jetbrains.kotlin.idea.test.JdkAndMockLibraryProjectDescriptor;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
public abstract class AbstractReferenceResolveWithLibTest extends AbstractReferenceResolveTest {
private static final String TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/resolve/referenceWithLib";
@@ -30,4 +37,32 @@ public abstract class AbstractReferenceResolveWithLibTest extends AbstractRefere
}
return new JdkAndMockLibraryProjectDescriptor(TEST_DATA_PATH + "/" + getTestName(true) + "Src", false, true, false, false);
}
@Nullable
@Override
public PsiReference wrapReference(@Nullable final PsiReference reference) {
if (reference == null) return null;
if (InTextDirectivesUtils.isDirectiveDefined(myFixture.getFile().getText(), AstAccessControl.INSTANCE.getALLOW_AST_ACCESS_DIRECTIVE())) {
return reference;
}
return new PsiDelegateReference(reference) {
@Nullable
@Override
public PsiElement resolve() {
return AstAccessControl.INSTANCE.execute(false, myTestRootDisposable, myFixture, new Function0<PsiElement>() {
@Override
public PsiElement invoke() {
return reference.resolve();
}
});
}
@Override
public String toString() {
return reference.toString();
}
};
}
}
@@ -78,6 +78,12 @@ public class ReferenceResolveWithLibTestGenerated extends AbstractReferenceResol
doTest(fileName);
}
@TestMetadata("overloadFun.kt")
public void testOverloadFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/referenceWithLib/overloadFun.kt");
doTest(fileName);
}
@TestMetadata("overridingFunctionWithSamAdapter.kt")
public void testOverridingFunctionWithSamAdapter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/referenceWithLib/overridingFunctionWithSamAdapter.kt");