FIR IDE: Search for the first non-local declaration in EnclosingDeclarationContext::detect
Local declarations do not have a stable `ClassId`, which is used in `declarationUtils.collectDesignation`. Local classes will always have `outerClassId.isLocal = true`, even when it is not true (see `org.jetbrains.kotlin.fir.builder.Context.currentClassId` for why this happens)
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_COMPARISON
|
||||||
class A(private val xxx1: Int, val xxx2: Int) {
|
class A(private val xxx1: Int, val xxx2: Int) {
|
||||||
private val xxx3: Int = 0
|
private val xxx3: Int = 0
|
||||||
|
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class T
|
||||||
|
|
||||||
|
fun topLevelFun(param: T) {
|
||||||
|
val firstVariable = T()
|
||||||
|
|
||||||
|
class LocalClass(constructorParam: T) {
|
||||||
|
val localClassField = constructorParam
|
||||||
|
|
||||||
|
init {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val secondVariable = T()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: firstVariable, param, constructorParam, localClassField
|
||||||
|
// ABSENT: secondVariable
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class T
|
||||||
|
|
||||||
|
fun topLevelFun(param: T) {
|
||||||
|
val firstVariable = T()
|
||||||
|
|
||||||
|
class LocalClass(constructorParam: T) {
|
||||||
|
val localClassField = constructorParam
|
||||||
|
|
||||||
|
fun localClassMethod(localParam: T) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val secondVariable = T()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: firstVariable, param, constructorParam, localClassField, localParam
|
||||||
|
// ABSENT: secondVariable
|
||||||
+10
@@ -2328,6 +2328,16 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassConstructor.kt")
|
||||||
|
public void testLocalClassConstructor() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassMember.kt")
|
||||||
|
public void testLocalClassMember() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassMember.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localVariablesAndFunctions.kt")
|
@TestMetadata("localVariablesAndFunctions.kt")
|
||||||
public void testLocalVariablesAndFunctions() throws Exception {
|
public void testLocalVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||||
|
|||||||
+10
@@ -2328,6 +2328,16 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassConstructor.kt")
|
||||||
|
public void testLocalClassConstructor() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassMember.kt")
|
||||||
|
public void testLocalClassMember() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassMember.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localVariablesAndFunctions.kt")
|
@TestMetadata("localVariablesAndFunctions.kt")
|
||||||
public void testLocalVariablesAndFunctions() throws Exception {
|
public void testLocalVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||||
|
|||||||
+10
@@ -2328,6 +2328,16 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassConstructor.kt")
|
||||||
|
public void testLocalClassConstructor() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassMember.kt")
|
||||||
|
public void testLocalClassMember() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localClassMember.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localVariablesAndFunctions.kt")
|
@TestMetadata("localVariablesAndFunctions.kt")
|
||||||
public void testLocalVariablesAndFunctions() throws Exception {
|
public void testLocalVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||||
|
|||||||
+8
-2
@@ -12,12 +12,15 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCo
|
|||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration
|
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration
|
||||||
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
|
||||||
internal sealed class EnclosingDeclarationContext {
|
internal sealed class EnclosingDeclarationContext {
|
||||||
companion object {
|
companion object {
|
||||||
fun detect(originalFile: KtFile, positionInFakeFile: KtElement): EnclosingDeclarationContext {
|
fun detect(originalFile: KtFile, positionInFakeFile: KtElement): EnclosingDeclarationContext {
|
||||||
val fakeFunction = positionInFakeFile.parentsOfType<KtNamedFunction>().firstOrNull { !it.isLocal }
|
val fakeFunction = positionInFakeFile.parentsOfType<KtNamedFunction>().firstOrNull {
|
||||||
|
it.isTopLevel || it.containingClassOrObject?.isLocal == false
|
||||||
|
}
|
||||||
if (fakeFunction != null) {
|
if (fakeFunction != null) {
|
||||||
val originalFunction = originalFile.findDeclarationOfTypeAt<KtNamedFunction>(fakeFunction.textOffset)
|
val originalFunction = originalFile.findDeclarationOfTypeAt<KtNamedFunction>(fakeFunction.textOffset)
|
||||||
?: error("Cannot find original function matching to ${fakeFunction.getElementTextInContext()} in $originalFile")
|
?: error("Cannot find original function matching to ${fakeFunction.getElementTextInContext()} in $originalFile")
|
||||||
@@ -25,7 +28,10 @@ internal sealed class EnclosingDeclarationContext {
|
|||||||
return FunctionContext(fakeFunction, originalFunction)
|
return FunctionContext(fakeFunction, originalFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fakeProperty = positionInFakeFile.parentsOfType<KtProperty>().firstOrNull { !it.isLocal }
|
val fakeProperty = positionInFakeFile.parentsOfType<KtProperty>().firstOrNull {
|
||||||
|
it.isTopLevel || it.containingClassOrObject?.isLocal == false
|
||||||
|
}
|
||||||
|
|
||||||
if (fakeProperty != null) {
|
if (fakeProperty != null) {
|
||||||
val originalProperty = originalFile.findDeclarationOfTypeAt<KtProperty>(fakeProperty.textOffset)
|
val originalProperty = originalFile.findDeclarationOfTypeAt<KtProperty>(fakeProperty.textOffset)
|
||||||
?: error("Cannot find original property matching to ${fakeProperty.getElementTextInContext()} in $originalFile")
|
?: error("Cannot find original property matching to ${fakeProperty.getElementTextInContext()} in $originalFile")
|
||||||
|
|||||||
Reference in New Issue
Block a user