From 08433b9ac95cc951dce4ea3b22f1dc147e74ffbc Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 11 Mar 2021 18:45:45 +0100 Subject: [PATCH] FIR IDE: fix constructor symbol building for type alias constructors --- .../kotlin/generators/tests/GenerateTests.kt | 5 +++ .../frontend/api/fir/KtSymbolByFirBuilder.kt | 6 +++- .../constructorViaTypeAlias.kt | 22 ++++++++++++ ...stractOverriddenDeclarationProviderTest.kt | 7 +--- .../symbols/AbstractSymbolByReferenceTest.kt | 34 ++++++++++++++++++ .../SymbolByReferenceTestGenerated.java | 36 +++++++++++++++++++ .../idea/test/framework/AbstractKtIdeaTest.kt | 6 ++++ .../test/framework/TestStructureRenderer.kt | 11 +++++- .../org/jetbrains/kotlin/idea/testUtils.kt | 9 +++++ 9 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 idea/idea-frontend-fir/testData/symbolByReference/constructorViaTypeAlias.kt create mode 100644 idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/AbstractSymbolByReferenceTest.kt create mode 100644 idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolByReferenceTestGenerated.java diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index d17f6119bf2..5ccf4815bff 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -1022,6 +1022,11 @@ fun main(args: Array) { model("symbolsByFqName", extension = "txt") } + + testClass { + model("symbolByReference") + } + testClass { model("memberScopeByFqName", extension = "txt") } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt index 362f9890c6a..641a6cdfa3d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt @@ -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) } diff --git a/idea/idea-frontend-fir/testData/symbolByReference/constructorViaTypeAlias.kt b/idea/idea-frontend-fir/testData/symbolByReference/constructorViaTypeAlias.kt new file mode 100644 index 00000000000..a4cd967257e --- /dev/null +++ b/idea/idea-frontend-fir/testData/symbolByReference/constructorViaTypeAlias.kt @@ -0,0 +1,22 @@ +// WITH_RUNTIME + +fun x() { + val a = ArrayList(listOf(1)) +} +// RESULT + +/* +KtFirConstructorSymbol: + annotatedType: [] java/util/ArrayList + annotationClassIds: [] + annotations: [] + containingClassIdIfNonLocal: java/util/ArrayList + dispatchType: java/util/ArrayList + isPrimary: false + origin: JAVA + symbolKind: MEMBER + typeParameters: [KtFirTypeParameterSymbol(E)] + valueParameters: [KtFirConstructorValueParameterSymbol(c)] + visibility: PUBLIC +*/ + diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/components/AbstractOverriddenDeclarationProviderTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/components/AbstractOverriddenDeclarationProviderTest.kt index 9a03b40707f..459ebdabe25 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/components/AbstractOverriddenDeclarationProviderTest.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/components/AbstractOverriddenDeclarationProviderTest.kt @@ -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().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}") } \ No newline at end of file diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/AbstractSymbolByReferenceTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/AbstractSymbolByReferenceTest.kt new file mode 100644 index 00000000000..4f42f4f4572 --- /dev/null +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/AbstractSymbolByReferenceTest.kt @@ -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() + 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) + } +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolByReferenceTestGenerated.java b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolByReferenceTestGenerated.java new file mode 100644 index 00000000000..6d30bf539fa --- /dev/null +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolByReferenceTestGenerated.java @@ -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"); + } +} diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/AbstractKtIdeaTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/AbstractKtIdeaTest.kt index 5fc25d2cf79..01e756127c2 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/AbstractKtIdeaTest.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/AbstractKtIdeaTest.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 getElementOfTypeAtCaret(): P = + file.findElementAt(myFixture.caretOffset) + ?.parentOfType

() + ?: error("No ${P::class.simpleName} found at caret with position ${myFixture.caretOffset}") + abstract fun doTestByFileStructure(fileStructure: TestFileStructure) } diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/TestStructureRenderer.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/TestStructureRenderer.kt index 49becf86c32..81a3a283c9a 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/TestStructureRenderer.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/test/framework/TestStructureRenderer.kt @@ -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") + } } } diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/testUtils.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/testUtils.kt index ece3c63ebda..15dcbaaabd1 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/testUtils.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/testUtils.kt @@ -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 executeOnPooledThreadInReadAction(action: () -> R): R = ApplicationManager.getApplication().executeOnPooledThread { runReadAction(action) }.get() +inline fun analyseOnPooledThreadInReadAction(context: KtElement, crossinline action: KtAnalysisSession.() -> R): R = + executeOnPooledThreadInReadAction { + analyze(context) { action() } + } + + fun addExternalTestFiles(testDataFilePath: String) { File(testDataFilePath).getExternalFiles().forEach(::addFile) }