Analysis API: add test for getReturnExpressionTargetSymbol

Also fix FIR and FE1.0 implementations.
This commit is contained in:
Tianyu Geng
2021-11-16 19:59:43 -08:00
committed by Ilya Kirillov
parent 7aef45d5cf
commit d0d1c8c4b9
16 changed files with 269 additions and 27 deletions
@@ -6,15 +6,17 @@
package org.jetbrains.kotlin.analysis.api.descriptors.components
import org.jetbrains.kotlin.analysis.api.components.KtExpressionInfoProvider
import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode
import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.impl.barebone.parentOfType
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.cfg.WhenChecker
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.BindingContext
@@ -27,7 +29,9 @@ internal class KtFe10ExpressionInfoProvider(
override fun getReturnExpressionTargetSymbol(returnExpression: KtReturnExpression): KtCallableSymbol? = withValidityAssertion {
val bindingContext = analysisContext.analyze(returnExpression, AnalysisMode.PARTIAL)
val targetLabel = returnExpression.getTargetLabel() ?: return null
val targetLabel = returnExpression.getTargetLabel()
?: return returnExpression.parentOfType<KtNamedFunction>()
?.let { with(analysisSession) { it.getSymbol() as? KtCallableSymbol } }
val labelTarget = bindingContext[BindingContext.LABEL_TARGET, targetLabel] as? KtDeclaration ?: return null
return with(analysisSession) { labelTarget.getSymbol() as? KtCallableSymbol }
}
@@ -0,0 +1,11 @@
/*
* 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.analysis.api.descriptors.test.components.expressionInfoProvider
import org.jetbrains.kotlin.analysis.api.descriptors.test.KtFe10FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionInfoProvider.AbstractReturnTargetSymbolTest
abstract class AbstractKtFe10ReturnTargetSymbolTest : AbstractReturnTargetSymbolTest(KtFe10FrontendApiTestConfiguratorService)
@@ -0,0 +1,44 @@
/*
* 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.analysis.api.descriptors.test.components.expressionInfoProvider;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol")
@TestDataPath("$PROJECT_ROOT")
public class KtFe10ReturnTargetSymbolTestGenerated extends AbstractKtFe10ReturnTargetSymbolTest {
@Test
public void testAllFilesPresentInReturnExpressionTargetSymbol() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("labeledReturn.kt")
public void testLabeledReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/labeledReturn.kt");
}
@Test
@TestMetadata("normalReturn.kt")
public void testNormalReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/normalReturn.kt");
}
@Test
@TestMetadata("unresolvedReturn.kt")
public void testUnresolvedReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/unresolvedReturn.kt");
}
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.components.KtExpressionInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtWhenExpression
@@ -24,6 +25,7 @@ internal class KtFirExpressionInfoProvider(
override fun getReturnExpressionTargetSymbol(returnExpression: KtReturnExpression): KtCallableSymbol? {
val fir = returnExpression.getOrBuildFirSafe<FirReturnExpression>(firResolveState) ?: return null
val firTargetSymbol = fir.target.labeledElement
if (firTargetSymbol is FirErrorFunction) return null
return firSymbolBuilder.callableBuilder.buildCallableSymbol(firTargetSymbol)
}
@@ -0,0 +1,11 @@
/*
* 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.analysis.api.fir.components.expressionInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionInfoProvider.AbstractReturnTargetSymbolTest
abstract class AbstractFirReturnTargetSymbolTest : AbstractReturnTargetSymbolTest(FirFrontendApiTestConfiguratorService)
@@ -0,0 +1,44 @@
/*
* 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.analysis.api.fir.components.expressionInfoProvider;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol")
@TestDataPath("$PROJECT_ROOT")
public class FirReturnTargetSymbolTestGenerated extends AbstractFirReturnTargetSymbolTest {
@Test
public void testAllFilesPresentInReturnExpressionTargetSymbol() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("labeledReturn.kt")
public void testLabeledReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/labeledReturn.kt");
}
@Test
@TestMetadata("normalReturn.kt")
public void testNormalReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/normalReturn.kt");
}
@Test
@TestMetadata("unresolvedReturn.kt")
public void testUnresolvedReturn() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionInfoProvider/returnExpressionTargetSymbol/unresolvedReturn.kt");
}
}
@@ -7,9 +7,14 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils.offsetToLineAndColumn
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
inline fun <T> runReadAction(crossinline runnable: () -> T): T {
return ApplicationManager.getApplication().runReadAction(Computable { runnable() })
@@ -21,4 +26,18 @@ fun <R> executeOnPooledThreadInReadAction(action: () -> R): R =
inline fun <R> analyseOnPooledThreadInReadAction(context: KtElement, crossinline action: KtAnalysisSession.() -> R): R =
executeOnPooledThreadInReadAction {
analyse(context) { action() }
}
}
fun PsiElement?.position(): String {
if (this == null) return "(unknown)"
return offsetToLineAndColumn(containingFile.viewProvider.document, textRange.startOffset).toString()
}
fun KtSymbol.getNameWithPositionString(): String {
return when (val psi = this.psi) {
is KtDeclarationWithBody -> psi.name
is KtNamedDeclaration -> psi.name
null -> "null"
else -> psi::class.simpleName
} + "@" + psi.position()
}
@@ -0,0 +1,58 @@
/*
* 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.analysis.api.impl.base.test.components.expressionInfoProvider
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.getNameWithPositionString
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractReturnTargetSymbolTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractHLApiSingleFileTest(configurator) {
val commentRegex = Regex("""/\* (.+@\(.+\)|null) \*/""")
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
super.doTestByFileStructure(ktFile, module, testServices)
val original = ktFile.text
val actual = buildString {
ktFile.accept(object : KtTreeVisitorVoid() {
override fun visitElement(element: PsiElement) {
if (element is LeafPsiElement) {
append(element.text)
}
super.visitElement(element)
}
override fun visitReturnExpression(expression: KtReturnExpression) {
expression.returnKeyword.accept(this)
expression.labeledExpression?.accept(this)
analyseForTest(expression) {
val target = expression.getReturnTargetSymbol()
append("/* " + target?.getNameWithPositionString() + " */")
}
expression.returnedExpression?.accept(this)
}
override fun visitComment(comment: PsiComment) {
// Skip such comments so that test become idempotent
if (comment.text.matches(commentRegex)) return
super.visitComment(comment)
}
})
}
if (actual != original) {
testServices.assertions.assertEqualsToFile(testDataPath, actual)
}
}
}
@@ -0,0 +1,22 @@
fun test() {
run {
return@run/* <anonymous>@(2,9) */
}
run {
return@test/* test@(1,1) */
}
run a@{
return@a/* <anonymous>@(8,11) */
}
run {
with("") {
return@with/* <anonymous>@(12,18) */
return@run/* <anonymous>@(11,9) */
return@test/* test@(1,1) */
}
}
}
val i = a@{
return@a/* <anonymous>@(20,11) */
}
@@ -0,0 +1,36 @@
fun foo() {
return/* foo@(1,1) */
}
fun bar(): String {
return/* bar@(5,1) */""
}
fun baz(): Int {
if (true) {
return/* baz@(9,1) */1
} else {
return/* baz@(9,1) */2
}
}
fun quux(): Int {
while(true) {
return/* quux@(17,1) */1
}
return/* quux@(17,1) */2
}
fun test() {
run {
return/* test@(24,1) */
}
fun() {
return/* null@(28,5) */
}
run {
with("") {
return/* test@(24,1) */
}
}
}
@@ -1,8 +0,0 @@
fun /* EXPECTED_TARGET */x(): Int {
receiveLambda {
return<caret> 1
}
return 2
}
inline fun receiveLambda(x: () -> Unit){}
@@ -1,3 +0,0 @@
fun /* EXPECTED_TARGET */x(): Int {
return<caret> 1
}
@@ -1,3 +0,0 @@
fun /* EXPECTED_TARGET */x(): Int {
return<caret> 1
}
@@ -1,8 +0,0 @@
fun x(): Int {
receiveLambda { /* EXPECTED_TARGET */
return@receiveLambda<caret> 1
}
return 2
}
fun receiveLambda(x: () -> Int){}
@@ -0,0 +1,11 @@
fun test() {
return@blah/* null */
}
val i = {
return/* null */
}
val i = {
return@i/* null */
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.generators.tests.analysis.api
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.callResolver.AbstractKtFe10ResolveCallTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.compileTimeConstantProvider.AbstractKtFe10CompileTimeConstantEvaluatorTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.expressionInfoProvider.AbstractKtFe10ReturnTargetSymbolTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.expressionInfoProvider.AbstractKtFe10WhenMissingCasesTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.expressionTypeProvider.AbstractKtFe10ExpectedExpressionTypeTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.expressionTypeProvider.AbstractKtFe10HLExpressionTypeTest
@@ -14,13 +16,13 @@ import org.jetbrains.kotlin.analysis.api.descriptors.test.components.symbolDecla
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.symbolDeclarationRenderer.AbstractKtFe10RendererTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.typeCreator.AbstractKtFe10TypeParameterTypeTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.typeProvider.AbstractKtFe10HasCommonSubtypeTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.compileTimeConstantProvider.AbstractKtFe10CompileTimeConstantEvaluatorTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByPsiTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByReferenceTest
import org.jetbrains.kotlin.analysis.api.fir.AbstractFirReferenceResolveTest
import org.jetbrains.kotlin.analysis.api.fir.components.callResolver.AbstractFirResolveCallTest
import org.jetbrains.kotlin.analysis.api.fir.components.compileTimeConstantProvider.AbstractFirCompileTimeConstantEvaluatorTest
import org.jetbrains.kotlin.analysis.api.fir.components.expressionInfoProvider.AbstractFirReturnTargetSymbolTest
import org.jetbrains.kotlin.analysis.api.fir.components.expressionInfoProvider.AbstractFirWhenMissingCasesTest
import org.jetbrains.kotlin.analysis.api.fir.components.expressionTypeProvider.AbstractFirExpectedExpressionTypeTest
import org.jetbrains.kotlin.analysis.api.fir.components.expressionTypeProvider.AbstractFirHLExpressionTypeTest
@@ -128,7 +130,7 @@ private fun TestGroupSuite.generateAnalysisApiComponentsTests() {
}
test(
fir = null /*TODO*/, fe10 = null
fir = AbstractFirReturnTargetSymbolTest::class, fe10 = AbstractKtFe10ReturnTargetSymbolTest::class
) {
model("returnExpressionTargetSymbol")
}