From 2a69efba8a4080af3fce02d1460bfb8705fffade Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 30 Jul 2019 10:16:39 +0300 Subject: [PATCH] FIR resolution API: fix handling of expressions inside local functions --- .../kotlin/idea/fir/FirResolutionApi.kt | 31 ++++++++++++------- .../fir/lazyResolve/inLocal/inLocal.test | 3 ++ idea/testData/fir/lazyResolve/inLocal/main.kt | 14 +++++++++ .../testData/fir/lazyResolve/inLocal/main.txt | 12 +++++++ .../fir/lazyResolve/inLocal/results.txt | 1 + .../idea/fir/FirLazyResolveTestGenerated.java | 5 +++ 6 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 idea/testData/fir/lazyResolve/inLocal/inLocal.test create mode 100644 idea/testData/fir/lazyResolve/inLocal/main.kt create mode 100644 idea/testData/fir/lazyResolve/inLocal/main.txt create mode 100644 idea/testData/fir/lazyResolve/inLocal/results.txt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirResolutionApi.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirResolutionApi.kt index 3e2d48d52ab..f147740b342 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirResolutionApi.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirResolutionApi.kt @@ -15,8 +15,8 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope -import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol -import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.types.FirErrorTypeRef import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.name.ClassId @@ -37,15 +37,14 @@ private fun KtClassOrObject.relativeFqName(): FqName { private fun FirFile.findCallableMember( provider: FirProvider, callableMember: KtCallableDeclaration, packageFqName: FqName, klassFqName: FqName?, declName: Name -): FirCallableMemberDeclaration<*> { +): FirCallableDeclaration<*> { val memberScope = if (klassFqName == null) FirTopLevelDeclaredMemberScope(this, session) else provider.getClassDeclaredMemberScope(ClassId(packageFqName, klassFqName, false))!! - var result: FirCallableMemberDeclaration<*>? = null - val processor = { symbol: ConeCallableSymbol -> - val firSymbol = symbol as? FirBasedSymbol<*> - val fir = firSymbol?.fir as? FirCallableMemberDeclaration<*> - if (fir?.psi == callableMember) { + var result: FirCallableDeclaration<*>? = null + val processor = { symbol: FirCallableSymbol<*> -> + val fir = symbol.fir + if (fir.psi == callableMember) { result = fir ProcessorAction.STOP } else { @@ -58,13 +57,15 @@ private fun FirFile.findCallableMember( memberScope.processPropertiesByName(declName, processor) } - return result!! + return result + ?: error("Cannot find FIR callable declaration ${CallableId(packageFqName, klassFqName, declName)}") } +// NB: at this moment it crashes with ISE when called on local declaration fun KtCallableDeclaration.getOrBuildFir( state: FirResolveState, phase: FirResolvePhase = FirResolvePhase.DECLARATIONS -): FirCallableMemberDeclaration<*> { +): FirCallableDeclaration<*> { val session = state.getSession(this) val file = this.containingKtFile @@ -131,12 +132,20 @@ private fun FirDeclaration.runResolve( } } +private fun KtElement.containingNonLocalDeclaration(): KtDeclaration { + var container = this.containingDeclarationForPseudocode + while (container != null && KtPsiUtil.isLocal(container)) { + container = container.containingDeclarationForPseudocode + } + return container ?: error("No containing non-local declaration: $text") +} + fun KtElement.getOrBuildFir( state: FirResolveState, phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE ): FirElement { val containerFir: FirDeclaration = - when (val container = this.containingDeclarationForPseudocode ?: error("No containing declaration: $text")) { + when (val container = this.containingNonLocalDeclaration()) { is KtCallableDeclaration -> container.getOrBuildFir(state, phase) is KtClassOrObject -> container.getOrBuildFir(state, phase) else -> error("Unsupported: ${container.text}") diff --git a/idea/testData/fir/lazyResolve/inLocal/inLocal.test b/idea/testData/fir/lazyResolve/inLocal/inLocal.test new file mode 100644 index 00000000000..3099545c162 --- /dev/null +++ b/idea/testData/fir/lazyResolve/inLocal/inLocal.test @@ -0,0 +1,3 @@ +{ + "mainFile": "main.kt" +} \ No newline at end of file diff --git a/idea/testData/fir/lazyResolve/inLocal/main.kt b/idea/testData/fir/lazyResolve/inLocal/main.kt new file mode 100644 index 00000000000..f1ad18c89b7 --- /dev/null +++ b/idea/testData/fir/lazyResolve/inLocal/main.kt @@ -0,0 +1,14 @@ +package main + +fun main() { + fun foo(): Int { + return bar() + } + + foo() +} + +fun bar(): Int { + val x = 4 + return 9 * x +} \ No newline at end of file diff --git a/idea/testData/fir/lazyResolve/inLocal/main.txt b/idea/testData/fir/lazyResolve/inLocal/main.txt new file mode 100644 index 00000000000..4570884e8d0 --- /dev/null +++ b/idea/testData/fir/lazyResolve/inLocal/main.txt @@ -0,0 +1,12 @@ +FILE: main.kt + public final fun main(): R|kotlin/Unit| { + local final fun foo(): R|kotlin/Int| { + ^foo R|main/bar|() + } + + R|/foo|() + } + public final fun bar(): R|kotlin/Int| { + lval x: = Int(4) + ^bar Int(9).times#(x#) + } diff --git a/idea/testData/fir/lazyResolve/inLocal/results.txt b/idea/testData/fir/lazyResolve/inLocal/results.txt new file mode 100644 index 00000000000..c66d5d5313e --- /dev/null +++ b/idea/testData/fir/lazyResolve/inLocal/results.txt @@ -0,0 +1 @@ +R|main/bar|() diff --git a/idea/tests/org/jetbrains/kotlin/idea/fir/FirLazyResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/fir/FirLazyResolveTestGenerated.java index 16813e569c1..0f5719c9d9d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/fir/FirLazyResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/fir/FirLazyResolveTestGenerated.java @@ -29,6 +29,11 @@ public class FirLazyResolveTestGenerated extends AbstractFirLazyResolveTest { KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/fir/lazyResolve"), Pattern.compile("^(.+)\\.test$"), TargetBackend.ANY); } + @TestMetadata("inLocal/inLocal.test") + public void testInLocal_InLocal() throws Exception { + runTest("idea/testData/fir/lazyResolve/inLocal/inLocal.test"); + } + @TestMetadata("simple/simple.test") public void testSimple_Simple() throws Exception { runTest("idea/testData/fir/lazyResolve/simple/simple.test");