FIR IDE: add completion support to classes and to type aliases

This commit is contained in:
Ilya Kirillov
2021-04-19 20:15:21 +02:00
committed by TeamCityServer
parent a5c33c8d42
commit da6c5e13d5
30 changed files with 504 additions and 34 deletions
@@ -31,7 +31,6 @@ class RawFirFragmentForLazyBodiesBuilder private constructor(
designation: List<FirDeclaration>, designation: List<FirDeclaration>,
declaration: KtDeclaration, declaration: KtDeclaration,
): FirDeclaration { ): FirDeclaration {
require(declaration is KtNamedFunction || declaration is KtProperty) { "Not implemented for ${declaration::class.qualifiedName}" }
val builder = RawFirFragmentForLazyBodiesBuilder(session, baseScopeProvider, declaration) val builder = RawFirFragmentForLazyBodiesBuilder(session, baseScopeProvider, declaration)
builder.context.packageFqName = declaration.containingKtFile.packageFqName builder.context.packageFqName = declaration.containingKtFile.packageFqName
return builder.moveNext(designation.iterator()) return builder.moveNext(designation.iterator())
@@ -365,6 +365,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
} }
doTransformTypeParameters(typeAlias) doTransformTypeParameters(typeAlias)
typeAlias.transformAnnotations(transformer, data) typeAlias.transformAnnotations(transformer, data)
transformer.onBeforeDeclarationContentResolve(typeAlias)
typeAlias.transformExpandedTypeRef(transformer, data) typeAlias.transformExpandedTypeRef(transformer, data)
return typeAlias return typeAlias
} }
@@ -81,3 +81,27 @@ inline fun buildRegularClass(init: FirRegularClassBuilder.() -> Unit): FirRegula
} }
return FirRegularClassBuilder().apply(init).build() return FirRegularClassBuilder().apply(init).build()
} }
@OptIn(ExperimentalContracts::class)
inline fun buildRegularClassCopy(original: FirRegularClass, init: FirRegularClassBuilder.() -> Unit): FirRegularClass {
contract {
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
val copyBuilder = FirRegularClassBuilder()
copyBuilder.source = original.source
copyBuilder.session = original.session
copyBuilder.resolvePhase = original.resolvePhase
copyBuilder.origin = original.origin
copyBuilder.attributes = original.attributes.copy()
copyBuilder.annotations.addAll(original.annotations)
copyBuilder.typeParameters.addAll(original.typeParameters)
copyBuilder.status = original.status
copyBuilder.classKind = original.classKind
copyBuilder.declarations.addAll(original.declarations)
copyBuilder.scopeProvider = original.scopeProvider
copyBuilder.name = original.name
copyBuilder.symbol = original.symbol
copyBuilder.companionObject = original.companionObject
copyBuilder.superTypeRefs.addAll(original.superTypeRefs)
return copyBuilder.apply(init).build()
}
@@ -68,3 +68,23 @@ inline fun buildTypeAlias(init: FirTypeAliasBuilder.() -> Unit): FirTypeAlias {
} }
return FirTypeAliasBuilder().apply(init).build() return FirTypeAliasBuilder().apply(init).build()
} }
@OptIn(ExperimentalContracts::class)
inline fun buildTypeAliasCopy(original: FirTypeAlias, init: FirTypeAliasBuilder.() -> Unit): FirTypeAlias {
contract {
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
val copyBuilder = FirTypeAliasBuilder()
copyBuilder.source = original.source
copyBuilder.session = original.session
copyBuilder.resolvePhase = original.resolvePhase
copyBuilder.origin = original.origin
copyBuilder.attributes = original.attributes.copy()
copyBuilder.status = original.status
copyBuilder.typeParameters.addAll(original.typeParameters)
copyBuilder.name = original.name
copyBuilder.symbol = original.symbol
copyBuilder.expandedTypeRef = original.expandedTypeRef
copyBuilder.annotations.addAll(original.annotations)
return copyBuilder.apply(init).build()
}
@@ -28,7 +28,7 @@ inline fun <reified T : ConeKotlinType> FirTypeRef.coneTypeSafe(): T? {
return (this as? FirResolvedTypeRef)?.type as? T return (this as? FirResolvedTypeRef)?.type as? T
} }
inline val FirTypeRef.coneType: ConeKotlinType val FirTypeRef.coneType: ConeKotlinType
get() = coneTypeSafe() get() = coneTypeSafe()
?: error("Expected FirResolvedTypeRef with ConeKotlinType but was ${this::class.simpleName} ${render()}") ?: error("Expected FirResolvedTypeRef with ConeKotlinType but was ${this::class.simpleName} ${render()}")
@@ -37,6 +37,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
parents += typeParameterRefsOwnerBuilder parents += typeParameterRefsOwnerBuilder
defaultNull("companionObject") defaultNull("companionObject")
openBuilder() openBuilder()
withCopy()
} }
val qualifiedAccessBuilder by builder { val qualifiedAccessBuilder by builder {
@@ -95,6 +96,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
builder(typeAlias) { builder(typeAlias) {
parents += typeParametersOwnerBuilder parents += typeParametersOwnerBuilder
withCopy()
} }
builder(annotationCall) { builder(annotationCall) {
@@ -11,3 +11,4 @@ class A() : My<caret> {
} }
// EXIST: MySecondClass, MyFirstClass // EXIST: MySecondClass, MyFirstClass
// FIR_COMPARISON
@@ -9,3 +9,4 @@ class ChromePageManager(): PageManager(object : Runnable {
} }
// EXIST: Tab // EXIST: Tab
// FIR_COMPARISON
@@ -12,3 +12,4 @@ public class Test : String<caret> {
// EXIST: StringMy // EXIST: StringMy
// EXIST: String // EXIST: String
// ABSENT: StringMethod // ABSENT: StringMethod
// FIR_COMPARISON
@@ -0,0 +1,7 @@
class X {
init {
val y = 1
<caret>
}
}
// EXIST: y
@@ -0,0 +1,9 @@
class X {
val x: Int = 10
init {
<caret>
}
}
// EXIST: x
// FIR_COMPARISON
@@ -0,0 +1,5 @@
open class Base
class A : <caret>
// EXIST: Base
// FIR_COMPARISON
@@ -0,0 +1,5 @@
open class Base
class A : B<caret>
// EXIST: Base
// FIR_COMPARISON
@@ -0,0 +1,5 @@
open class Base<T>
class A<U> : Base<<caret>>
// EXIST: U
// FIR_COMPARISON
@@ -0,0 +1,8 @@
class X {
typealias Y = <caret>
}
class Z
// EXIST: Z
// FIR_COMPARISON
@@ -0,0 +1,5 @@
typealias Y = <caret>
class Z
// EXIST: Z
// FIR_COMPARISON
@@ -0,0 +1,6 @@
val y = 10
class X(val x: Int = <caret>)
// EXIST: y
// FIR_COMPARISON
@@ -0,0 +1,4 @@
class X(val y: Int, val x: Int = <caret>)
// EXIST: y
// FIR_COMPARISON
@@ -0,0 +1,6 @@
class Y
class X(val x: <caret>)
// EXIST: Y
// FIR_COMPARISON
@@ -5,3 +5,4 @@ annotation class SomeAnnotation
class Complete(@set:Some<caret> var field: Int) class Complete(@set:Some<caret> var field: Int)
// ELEMENT: SomeAnnotation // ELEMENT: SomeAnnotation
// FIR_COMPARISON
@@ -5,3 +5,4 @@ annotation class SomeAnnotation
class Complete(@set:SomeAnnotation<caret> var field: Int) class Complete(@set:SomeAnnotation<caret> var field: Int)
// ELEMENT: SomeAnnotation // ELEMENT: SomeAnnotation
// FIR_COMPARISON
@@ -1,3 +1,4 @@
package some package some
class Complete(@set:SomeAnn<caret> var field: Int) class Complete(@set:SomeAnn<caret> var field: Int)
// FIR_COMPARISON
@@ -3,3 +3,4 @@ package some
import other.SomeAnnotation import other.SomeAnnotation
class Complete(@set:SomeAnnotation<caret> var field: Int) class Complete(@set:SomeAnnotation<caret> var field: Int)
// FIR_COMPARISON
@@ -1677,6 +1677,29 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inInitBlock")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InInitBlock extends AbstractJSBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInInitBlock() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inInitBlock"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/localVariable.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/property.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals") @TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1720,6 +1743,57 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inSuperTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InSuperTypes extends AbstractJSBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInSuperTypes() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inSuperTypes"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("baseClass.kt")
public void testBaseClass() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClass.kt");
}
@TestMetadata("baseClassWithPrefix.kt")
public void testBaseClassWithPrefix() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClassWithPrefix.kt");
}
@TestMetadata("typeParameter.kt")
public void testTypeParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/typeParameter.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InTypeAlias extends AbstractJSBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInTypeAlias() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inTypeAlias"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("member.kt")
public void testMember() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/member.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/topLevel.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature") @TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -2231,6 +2305,34 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/primaryConstructor")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimaryConstructor extends AbstractJSBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInPrimaryConstructor() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/primaryConstructor"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("parameterDefaultValue.kt")
public void testParameterDefaultValue() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/parameterDefaultValue.kt");
}
@TestMetadata("previousParameter.kt")
public void testPreviousParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/previousParameter.kt");
}
@TestMetadata("propertyType.kt")
public void testPropertyType() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/propertyType.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion") @TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1677,6 +1677,29 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inInitBlock")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InInitBlock extends AbstractJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInInitBlock() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inInitBlock"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/localVariable.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/property.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals") @TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1720,6 +1743,57 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inSuperTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InSuperTypes extends AbstractJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInSuperTypes() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inSuperTypes"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("baseClass.kt")
public void testBaseClass() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClass.kt");
}
@TestMetadata("baseClassWithPrefix.kt")
public void testBaseClassWithPrefix() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClassWithPrefix.kt");
}
@TestMetadata("typeParameter.kt")
public void testTypeParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/typeParameter.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InTypeAlias extends AbstractJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInTypeAlias() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inTypeAlias"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("member.kt")
public void testMember() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/member.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/topLevel.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature") @TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -2231,6 +2305,34 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/primaryConstructor")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimaryConstructor extends AbstractJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInPrimaryConstructor() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/primaryConstructor"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("parameterDefaultValue.kt")
public void testParameterDefaultValue() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/parameterDefaultValue.kt");
}
@TestMetadata("previousParameter.kt")
public void testPreviousParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/previousParameter.kt");
}
@TestMetadata("propertyType.kt")
public void testPropertyType() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/propertyType.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion") @TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1677,6 +1677,29 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inInitBlock")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InInitBlock extends AbstractHighLevelJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInInitBlock() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inInitBlock"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/localVariable.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inInitBlock/property.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals") @TestMetadata("idea/idea-completion/testData/basic/common/inStringLiterals")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1720,6 +1743,57 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/inSuperTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InSuperTypes extends AbstractHighLevelJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInSuperTypes() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inSuperTypes"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("baseClass.kt")
public void testBaseClass() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClass.kt");
}
@TestMetadata("baseClassWithPrefix.kt")
public void testBaseClassWithPrefix() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/baseClassWithPrefix.kt");
}
@TestMetadata("typeParameter.kt")
public void testTypeParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inSuperTypes/typeParameter.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/inTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InTypeAlias extends AbstractHighLevelJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInTypeAlias() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/inTypeAlias"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("member.kt")
public void testMember() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/member.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/idea-completion/testData/basic/common/inTypeAlias/topLevel.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature") @TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -2231,6 +2305,34 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ
} }
} }
@TestMetadata("idea/idea-completion/testData/basic/common/primaryConstructor")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimaryConstructor extends AbstractHighLevelJvmBasicCompletionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInPrimaryConstructor() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/primaryConstructor"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("parameterDefaultValue.kt")
public void testParameterDefaultValue() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/parameterDefaultValue.kt");
}
@TestMetadata("previousParameter.kt")
public void testPreviousParameter() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/previousParameter.kt");
}
@TestMetadata("propertyType.kt")
public void testPropertyType() throws Exception {
runTest("idea/idea-completion/testData/basic/common/primaryConstructor/propertyType.kt");
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion") @TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -8,14 +8,11 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyAccessorCopy import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
object DeclarationCopyBuilder { object DeclarationCopyBuilder {
fun createDeclarationCopy( fun createDeclarationCopy(
@@ -24,26 +21,36 @@ object DeclarationCopyBuilder {
state: FirModuleResolveState, state: FirModuleResolveState,
): FirDeclaration { ): FirDeclaration {
return when (fakeKtDeclaration) { return when (fakeKtDeclaration) {
is KtNamedFunction -> buildFunctionCopy( is KtNamedFunction -> createFunctionCopy(
fakeKtDeclaration, fakeKtDeclaration,
originalFirDeclaration as FirSimpleFunction, originalFirDeclaration as FirSimpleFunction,
state state
) )
is KtProperty -> buildPropertyCopy( is KtProperty -> createPropertyCopy(
fakeKtDeclaration, fakeKtDeclaration,
originalFirDeclaration as FirProperty, originalFirDeclaration as FirProperty,
state state
) )
is KtClassOrObject -> createClassCopy(
fakeKtDeclaration,
originalFirDeclaration as FirRegularClass,
state
)
is KtTypeAlias -> createTypeAliasCopy(
fakeKtDeclaration,
originalFirDeclaration as FirTypeAlias,
state
)
else -> error("Unsupported declaration ${fakeKtDeclaration::class.simpleName}") else -> error("Unsupported declaration ${fakeKtDeclaration::class.simpleName}")
} }
} }
private fun buildFunctionCopy( private fun createFunctionCopy(
element: KtNamedFunction, element: KtNamedFunction,
originalFunction: FirSimpleFunction, originalFunction: FirSimpleFunction,
state: FirModuleResolveState, state: FirModuleResolveState,
): FirSimpleFunction { ): FirSimpleFunction {
val builtFunction = createCopy(element, originalFunction) as FirSimpleFunction val builtFunction = createCopy(element, originalFunction)
// right now we can't resolve builtFunction header properly, as it built right in air, // right now we can't resolve builtFunction header properly, as it built right in air,
// without file, which is now required for running stages other then body resolve, so we // without file, which is now required for running stages other then body resolve, so we
@@ -57,12 +64,45 @@ object DeclarationCopyBuilder {
}.apply { reassignAllReturnTargets(builtFunction) } }.apply { reassignAllReturnTargets(builtFunction) }
} }
private fun buildPropertyCopy( private fun createClassCopy(
fakeKtClassOrObject: KtClassOrObject,
originalFirClass: FirRegularClass,
state: FirModuleResolveState,
): FirRegularClass {
val builtClass = createCopy(fakeKtClassOrObject, originalFirClass)
return buildRegularClassCopy(originalFirClass) {
declarations.clear()
declarations.addAll(builtClass.declarations)
symbol = builtClass.symbol
resolvePhase = minOf(originalFirClass.resolvePhase, FirResolvePhase.DECLARATIONS)
source = builtClass.source
session = state.rootModuleSession
}
}
private fun createTypeAliasCopy(
fakeKtTypeAlias: KtTypeAlias,
originalFirTypeAlias: FirTypeAlias,
state: FirModuleResolveState,
): FirTypeAlias {
val builtTypeAlias = createCopy(fakeKtTypeAlias, originalFirTypeAlias)
return buildTypeAliasCopy(originalFirTypeAlias) {
expandedTypeRef = builtTypeAlias.expandedTypeRef
symbol = builtTypeAlias.symbol
resolvePhase = minOf(originalFirTypeAlias.resolvePhase, FirResolvePhase.DECLARATIONS)
source = builtTypeAlias.source
session = state.rootModuleSession
}
}
private fun createPropertyCopy(
element: KtProperty, element: KtProperty,
originalProperty: FirProperty, originalProperty: FirProperty,
state: FirModuleResolveState state: FirModuleResolveState
): FirProperty { ): FirProperty {
val builtProperty = createCopy(element, originalProperty) as FirProperty val builtProperty = createCopy(element, originalProperty)
val originalSetter = originalProperty.setter val originalSetter = originalProperty.setter
val builtSetter = builtProperty.setter val builtSetter = builtProperty.setter
@@ -80,7 +120,7 @@ object DeclarationCopyBuilder {
builtSetter builtSetter
} }
return org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy(originalProperty) { return buildPropertyCopy(originalProperty) {
symbol = builtProperty.symbol symbol = builtProperty.symbol
initializer = builtProperty.initializer initializer = builtProperty.initializer
@@ -93,16 +133,16 @@ object DeclarationCopyBuilder {
} }
} }
fun createCopy( internal inline fun <reified T : FirDeclaration> createCopy(
fakeKtDeclaration: KtDeclaration, fakeKtDeclaration: KtDeclaration,
originalFirDeclaration: FirDeclaration, originalFirDeclaration: T,
): FirDeclaration { ): T {
return RawFirFragmentForLazyBodiesBuilder.build( return RawFirFragmentForLazyBodiesBuilder.build(
session = originalFirDeclaration.session, session = originalFirDeclaration.session,
baseScopeProvider = originalFirDeclaration.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = originalFirDeclaration.session.firIdeProvider.kotlinScopeProvider,
designation = originalFirDeclaration.collectDesignation().fullDesignation, designation = originalFirDeclaration.collectDesignation().fullDesignation,
declaration = fakeKtDeclaration declaration = fakeKtDeclaration
) ) as T
} }
private fun FirFunction<*>.reassignAllReturnTargets(from: FirFunction<*>) { private fun FirFunction<*>.reassignAllReturnTargets(from: FirFunction<*>) {
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@ThreadSafeMutableState @ThreadSafeMutableState
@@ -36,11 +37,21 @@ class FirTowerDataContextCollector {
} }
fun FirTowerDataContextCollector.getClosestAvailableParentContext(element: KtElement): FirTowerDataContext? { fun FirTowerDataContextCollector.getClosestAvailableParentContext(element: KtElement): FirTowerDataContext? {
var current: KtElement = element var current: PsiElement? = element
while (true) { while (current != null) {
getContext(current)?.let { return it } if (current is KtElement) {
current = current.parent as? KtElement ?: return null getContext(current)?.let { return it }
}
if (current is KtDeclaration) {
val originalDeclaration = current.originalDeclaration
originalDeclaration?.let { getContext(it) }?.let { return it }
}
if (current is KtFile) {
break
}
current = current.parent
} }
return null
} }
private tailrec fun PsiElement.closestBlockLevelOrInitializerExpression(): KtExpression? = private tailrec fun PsiElement.closestBlockLevelOrInitializerExpression(): KtExpression? =
@@ -80,7 +80,7 @@ internal class ReanalyzableFunctionStructureElement(
towerDataContextCollector: FirTowerDataContextCollector, towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzableFunctionStructureElement { ): ReanalyzableFunctionStructureElement {
val originalFunction = firSymbol.fir as FirSimpleFunction val originalFunction = firSymbol.fir as FirSimpleFunction
val newFunction = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalFunction) as FirSimpleFunction val newFunction = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalFunction)
return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalFunction, newFunction) { return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalFunction, newFunction) {
firLazyDeclarationResolver.lazyResolveDeclaration( firLazyDeclarationResolver.lazyResolveDeclaration(
@@ -122,7 +122,7 @@ internal class ReanalyzablePropertyStructureElement(
towerDataContextCollector: FirTowerDataContextCollector, towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzablePropertyStructureElement { ): ReanalyzablePropertyStructureElement {
val originalProperty = firSymbol.fir val originalProperty = firSymbol.fir
val newProperty = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalProperty) as FirProperty val newProperty = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalProperty)
return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalProperty, newProperty) { return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalProperty, newProperty) {
firLazyDeclarationResolver.lazyResolveDeclaration( firLazyDeclarationResolver.lazyResolveDeclaration(
@@ -34,8 +34,8 @@ internal sealed class EnclosingDeclarationContext {
ktDeclaration.canBeEnclosingDeclaration() ktDeclaration.canBeEnclosingDeclaration()
} }
if (fakeKtDeclaration != null) { if (fakeKtDeclaration != null) {
val originalDeclaration = originalFile.findDeclarationOfTypeAt(fakeKtDeclaration.textOffset, fakeKtDeclaration::class) val originalDeclaration = findMatchingElementInCopy(fakeKtDeclaration, originalFile)
?: error("Cannot find original function matching to ${fakeKtDeclaration.getElementTextInContext()} in $originalFile") ?: error("Cannot find original declaration matching to ${fakeKtDeclaration.getElementTextInContext()} in $originalFile")
recordOriginalDeclaration(originalDeclaration, fakeKtDeclaration) recordOriginalDeclaration(originalDeclaration, fakeKtDeclaration)
return EnclosingDeclarationContextImpl(fakeKtDeclaration, originalDeclaration) return EnclosingDeclarationContextImpl(fakeKtDeclaration, originalDeclaration)
} }
@@ -62,7 +62,6 @@ internal class EnclosingDeclarationContextImpl(
) : EnclosingDeclarationContext() ) : EnclosingDeclarationContext()
internal fun EnclosingDeclarationContext.recordCompletionContext(originalFirFile: FirFile, firResolveState: FirModuleResolveState) { internal fun EnclosingDeclarationContext.recordCompletionContext(originalFirFile: FirFile, firResolveState: FirModuleResolveState) {
LowLevelFirApiFacadeForCompletion.recordCompletionContextForDeclaration( LowLevelFirApiFacadeForCompletion.recordCompletionContextForDeclaration(
originalFirFile, originalFirFile,
@@ -73,7 +72,8 @@ internal fun EnclosingDeclarationContext.recordCompletionContext(originalFirFile
) )
} }
private fun <T : KtElement> KtFile.findDeclarationOfTypeAt(offset: Int, declarationType: KClass<T>): T? { fun <T : KtElement> findMatchingElementInCopy(element: T, copy: KtFile): T? {
val elementAtOffset = findElementAt(offset) ?: return null val elementOffset = element.textOffset
return PsiTreeUtil.getParentOfType(elementAtOffset, declarationType.java, false)?.takeIf { it.textOffset == offset } val elementAtOffset = copy.findElementAt(elementOffset) ?: return null
return PsiTreeUtil.getParentOfType(elementAtOffset, element::class.java, false)?.takeIf { it.textOffset == elementOffset }
} }