FIR IDE: fix constructor symbol building for type alias constructors

This commit is contained in:
Ilya Kirillov
2021-03-11 18:45:45 +01:00
parent 4d5da26696
commit 08433b9ac9
9 changed files with 128 additions and 8 deletions
@@ -1022,6 +1022,11 @@ fun main(args: Array<String>) {
model("symbolsByFqName", extension = "txt")
}
testClass<AbstractSymbolByReferenceTest> {
model("symbolByReference")
}
testClass<AbstractMemberScopeByFqNameTest> {
model("memberScopeByFqName", extension = "txt")
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.resolve.calls.originalConstructorIfTypeAlias
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
@@ -134,7 +135,10 @@ internal class KtSymbolByFirBuilder private constructor(
KtFirFunctionSymbol(fir, resolveState, token, this)
}
fun buildConstructorSymbol(fir: FirConstructor) = symbolsCache.cache(fir) { KtFirConstructorSymbol(fir, resolveState, token, this) }
fun buildConstructorSymbol(fir: FirConstructor): KtFirConstructorSymbol {
val originalFir = fir.originalConstructorIfTypeAlias ?: fir
return symbolsCache.cache(originalFir) { KtFirConstructorSymbol(originalFir, resolveState, token, this) }
}
fun buildTypeParameterSymbol(fir: FirTypeParameter) =
symbolsCache.cache(fir) { KtFirTypeParameterSymbol(fir, resolveState, token, this) }
@@ -0,0 +1,22 @@
// WITH_RUNTIME
fun x() {
val a = <caret>ArrayList(listOf(1))
}
// RESULT
/*
KtFirConstructorSymbol:
annotatedType: [] java/util/ArrayList<E>
annotationClassIds: []
annotations: []
containingClassIdIfNonLocal: java/util/ArrayList
dispatchType: java/util/ArrayList<E>
isPrimary: false
origin: JAVA
symbolKind: MEMBER
typeParameters: [KtFirTypeParameterSymbol(E)]
valueParameters: [KtFirConstructorValueParameterSymbol(c)]
visibility: PUBLIC
*/
@@ -24,7 +24,7 @@ abstract class AbstractOverriddenDeclarationProviderTest : AbstractKtIdeaTest()
override fun doTestByFileStructure(fileStructure: TestFileStructure) {
val signatures = executeOnPooledThreadInReadAction {
analyze(fileStructure.mainKtFile) {
val symbol = getDeclarationAtCaret().getSymbol() as KtCallableSymbol
val symbol = getElementOfTypeAtCaret<KtDeclaration>().getSymbol() as KtCallableSymbol
val allOverriddenSymbols = symbol.getAllOverriddenSymbols().map { renderSignature(it) }
val directlyOverriddenSymbols = symbol.getDirectlyOverriddenSymbols().map { renderSignature(it) }
listOf(
@@ -67,9 +67,4 @@ abstract class AbstractOverriddenDeclarationProviderTest : AbstractKtIdeaTest()
.joinToString(separator = ".")
}
}
private fun getDeclarationAtCaret(): KtDeclaration =
file.findElementAt(myFixture.caretOffset)
?.parentOfType()
?: error("No KtDeclaration found at caret with position ${myFixture.caretOffset}")
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.symbols
import org.jetbrains.kotlin.idea.analyseOnPooledThreadInReadAction
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.test.framework.AbstractKtIdeaTest
import org.jetbrains.kotlin.idea.test.framework.TestFileStructure
import org.jetbrains.kotlin.idea.test.framework.TestStructureExpectedDataBlock
import org.jetbrains.kotlin.idea.test.framework.TestStructureRenderer
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.test.KotlinTestUtils
abstract class AbstractSymbolByReferenceTest : AbstractKtIdeaTest() {
override fun doTestByFileStructure(fileStructure: TestFileStructure) {
val referenceExpression = getElementOfTypeAtCaret<KtNameReferenceExpression>()
val reference = referenceExpression.mainReference
val renderedSymbol = analyseOnPooledThreadInReadAction(fileStructure.mainKtFile) {
val symbol = reference.resolveToSymbol()
?: error("${referenceExpression.text} was not resolved to anything")
DebugSymbolRenderer.render(symbol)
}
val actual = TestStructureRenderer.render(
fileStructure,
TestStructureExpectedDataBlock(renderedSymbol)
)
KotlinTestUtils.assertEqualsToFile(fileStructure.filePath.toFile(), actual)
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.symbols;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/idea-frontend-fir/testData/symbolByReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class SymbolByReferenceTestGenerated extends AbstractSymbolByReferenceTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInSymbolByReference() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/testData/symbolByReference"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("constructorViaTypeAlias.kt")
public void testConstructorViaTypeAlias() throws Exception {
runTest("idea/idea-frontend-fir/testData/symbolByReference/constructorViaTypeAlias.kt");
}
}
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
@@ -64,6 +65,11 @@ abstract class AbstractKtIdeaTest : KotlinLightCodeInsightFixtureTestCase() {
}
}
protected inline fun <reified P : PsiElement> getElementOfTypeAtCaret(): P =
file.findElementAt(myFixture.caretOffset)
?.parentOfType<P>()
?: error("No ${P::class.simpleName} found at caret with position ${myFixture.caretOffset}")
abstract fun doTestByFileStructure(fileStructure: TestFileStructure)
}
@@ -59,7 +59,16 @@ object TestStructureRenderer {
private fun StringBuilder.renderExpectedDataBlock(block: TestStructureExpectedDataBlock) {
block.name?.let { name -> appendLine("// $name") }
block.values.forEach { value ->
appendLine("// $value")
if (value.lines().size > 1) {
appendLine(
"""|/*
|${value.trim()}
|*/
""".trimMargin()
)
} else {
appendLine("// $value")
}
}
}
@@ -12,11 +12,20 @@ import com.intellij.testFramework.LightPlatformTestCase
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.DuplicatedFirSourceElementsException
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.psi.KtElement
import java.io.File
fun <R> executeOnPooledThreadInReadAction(action: () -> R): R =
ApplicationManager.getApplication().executeOnPooledThread<R> { runReadAction(action) }.get()
inline fun <R> analyseOnPooledThreadInReadAction(context: KtElement, crossinline action: KtAnalysisSession.() -> R): R =
executeOnPooledThreadInReadAction {
analyze(context) { action() }
}
fun addExternalTestFiles(testDataFilePath: String) {
File(testDataFilePath).getExternalFiles().forEach(::addFile)
}