FIR resolution API: fix handling of expressions inside local functions
This commit is contained in:
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider
|
|||||||
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -37,15 +37,14 @@ private fun KtClassOrObject.relativeFqName(): FqName {
|
|||||||
private fun FirFile.findCallableMember(
|
private fun FirFile.findCallableMember(
|
||||||
provider: FirProvider, callableMember: KtCallableDeclaration,
|
provider: FirProvider, callableMember: KtCallableDeclaration,
|
||||||
packageFqName: FqName, klassFqName: FqName?, declName: Name
|
packageFqName: FqName, klassFqName: FqName?, declName: Name
|
||||||
): FirCallableMemberDeclaration<*> {
|
): FirCallableDeclaration<*> {
|
||||||
val memberScope =
|
val memberScope =
|
||||||
if (klassFqName == null) FirTopLevelDeclaredMemberScope(this, session)
|
if (klassFqName == null) FirTopLevelDeclaredMemberScope(this, session)
|
||||||
else provider.getClassDeclaredMemberScope(ClassId(packageFqName, klassFqName, false))!!
|
else provider.getClassDeclaredMemberScope(ClassId(packageFqName, klassFqName, false))!!
|
||||||
var result: FirCallableMemberDeclaration<*>? = null
|
var result: FirCallableDeclaration<*>? = null
|
||||||
val processor = { symbol: ConeCallableSymbol ->
|
val processor = { symbol: FirCallableSymbol<*> ->
|
||||||
val firSymbol = symbol as? FirBasedSymbol<*>
|
val fir = symbol.fir
|
||||||
val fir = firSymbol?.fir as? FirCallableMemberDeclaration<*>
|
if (fir.psi == callableMember) {
|
||||||
if (fir?.psi == callableMember) {
|
|
||||||
result = fir
|
result = fir
|
||||||
ProcessorAction.STOP
|
ProcessorAction.STOP
|
||||||
} else {
|
} else {
|
||||||
@@ -58,13 +57,15 @@ private fun FirFile.findCallableMember(
|
|||||||
memberScope.processPropertiesByName(declName, processor)
|
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(
|
fun KtCallableDeclaration.getOrBuildFir(
|
||||||
state: FirResolveState,
|
state: FirResolveState,
|
||||||
phase: FirResolvePhase = FirResolvePhase.DECLARATIONS
|
phase: FirResolvePhase = FirResolvePhase.DECLARATIONS
|
||||||
): FirCallableMemberDeclaration<*> {
|
): FirCallableDeclaration<*> {
|
||||||
val session = state.getSession(this)
|
val session = state.getSession(this)
|
||||||
|
|
||||||
val file = this.containingKtFile
|
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(
|
fun KtElement.getOrBuildFir(
|
||||||
state: FirResolveState,
|
state: FirResolveState,
|
||||||
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
|
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||||
): FirElement {
|
): FirElement {
|
||||||
val containerFir: FirDeclaration =
|
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 KtCallableDeclaration -> container.getOrBuildFir(state, phase)
|
||||||
is KtClassOrObject -> container.getOrBuildFir(state, phase)
|
is KtClassOrObject -> container.getOrBuildFir(state, phase)
|
||||||
else -> error("Unsupported: ${container.text}")
|
else -> error("Unsupported: ${container.text}")
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"mainFile": "main.kt"
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
fun foo(): Int {
|
||||||
|
return <caret>bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): Int {
|
||||||
|
val x = 4
|
||||||
|
return 9 * x
|
||||||
|
}
|
||||||
+12
@@ -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|<local>/foo|()
|
||||||
|
}
|
||||||
|
public final fun bar(): R|kotlin/Int| {
|
||||||
|
lval x: <implicit> = Int(4)
|
||||||
|
^bar Int(9).times#(x#)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
R|main/bar|()
|
||||||
@@ -29,6 +29,11 @@ public class FirLazyResolveTestGenerated extends AbstractFirLazyResolveTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/fir/lazyResolve"), Pattern.compile("^(.+)\\.test$"), TargetBackend.ANY);
|
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")
|
@TestMetadata("simple/simple.test")
|
||||||
public void testSimple_Simple() throws Exception {
|
public void testSimple_Simple() throws Exception {
|
||||||
runTest("idea/testData/fir/lazyResolve/simple/simple.test");
|
runTest("idea/testData/fir/lazyResolve/simple/simple.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user