diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeInfoProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeInfoProvider.kt index 8c0793c5800..61e4359b80d 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeInfoProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeInfoProvider.kt @@ -11,6 +11,8 @@ import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.withValidityAssertion +import org.jetbrains.kotlin.builtins.functions.FunctionClassKind +import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils import org.jetbrains.kotlin.types.TypeUtils @@ -23,8 +25,13 @@ internal class KtFe10TypeInfoProvider(override val analysisSession: KtFe10Analys return JavaSingleAbstractMethodUtils.isSamType(type.type) } + override fun getFunctionClassKind(type: KtType): FunctionClassKind? { + require(type is KtFe10Type) + return type.type.constructor.declarationDescriptor?.getFunctionalClassKind() + } + override fun canBeNull(type: KtType): Boolean = withValidityAssertion { require(type is KtFe10Type) return TypeUtils.isNullableType(type.type) } -} \ No newline at end of file +} diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/AbstractKtFe10FunctionClassKindTest.kt b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/AbstractKtFe10FunctionClassKindTest.kt new file mode 100644 index 00000000000..e4de23b1bce --- /dev/null +++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/AbstractKtFe10FunctionClassKindTest.kt @@ -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 + +import org.jetbrains.kotlin.analysis.api.descriptors.test.KtFe10FrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.AbstractFunctionClassKindTest + +abstract class AbstractKtFe10FunctionClassKindTest : AbstractFunctionClassKindTest(KtFe10FrontendApiTestConfiguratorService) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt index 87f88732afe..b4207a146d7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.builtins.functions.FunctionClassKind +import org.jetbrains.kotlin.fir.types.functionClassKind internal class KtFirTypeInfoProvider( override val analysisSession: KtFirAnalysisSession, @@ -25,5 +27,10 @@ internal class KtFirTypeInfoProvider( return samResolver.getFunctionTypeForPossibleSamType(coneType) != null } + override fun getFunctionClassKind(type: KtType): FunctionClassKind? { + val coneType = (type as KtFirType).coneType + return coneType.functionClassKind(analysisSession.rootModuleSession) + } + override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull } diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractFirFunctionClassKindTest.kt b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractFirFunctionClassKindTest.kt new file mode 100644 index 00000000000..cb1ecda27cf --- /dev/null +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/AbstractFirFunctionClassKindTest.kt @@ -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 + +import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.AbstractFunctionClassKindTest + +abstract class AbstractFirFunctionClassKindTest : AbstractFunctionClassKindTest(FirFrontendApiTestConfiguratorService) diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirFunctionClassKindTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirFunctionClassKindTestGenerated.java new file mode 100644 index 00000000000..7600c8d9aac --- /dev/null +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirFunctionClassKindTestGenerated.java @@ -0,0 +1,50 @@ +/* + * 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; + +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/functionClassKind") +@TestDataPath("$PROJECT_ROOT") +public class FirFunctionClassKindTestGenerated extends AbstractFirFunctionClassKindTest { + @Test + public void testAllFilesPresentInFunctionClassKind() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/functionClassKind"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("function.kt") + public void testFunction() throws Exception { + runTest("analysis/analysis-api/testData/components/functionClassKind/function.kt"); + } + + @Test + @TestMetadata("kFunction.kt") + public void testKFunction() throws Exception { + runTest("analysis/analysis-api/testData/components/functionClassKind/kFunction.kt"); + } + + @Test + @TestMetadata("kSuspendFunction.kt") + public void testKSuspendFunction() throws Exception { + runTest("analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.kt"); + } + + @Test + @TestMetadata("suspendFunction.kt") + public void testSuspendFunction() throws Exception { + runTest("analysis/analysis-api/testData/components/functionClassKind/suspendFunction.kt"); + } +} diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractFunctionClassKindTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractFunctionClassKindTest.kt new file mode 100644 index 00000000000..eca708db515 --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractFunctionClassKindTest.kt @@ -0,0 +1,39 @@ +/* + * 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 + +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider +import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions + +abstract class AbstractFunctionClassKindTest ( + configurator: FrontendApiTestConfiguratorService +) : AbstractHLApiSingleFileTest(configurator) { + + override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { + super.doTestByFileStructure(ktFile, module, testServices) + + val expressionAtCaret = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) as KtExpression + + val (type, functionClassKind) = executeOnPooledThreadInReadAction { + analyseForTest(expressionAtCaret) { + val functionType = expressionAtCaret.getExpectedType() + functionType?.render() to functionType?.functionClassKind + } + } + val actual = buildString { + appendLine("expression: ${expressionAtCaret.text}") + appendLine("expected type: $type") + appendLine("functionClassKind: $functionClassKind") + } + testServices.assertions.assertEqualsToFile(testDataFileSibling(".txt"), actual) + } +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeInfoProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeInfoProvider.kt index d846a55e8bb..182022d3b53 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeInfoProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeInfoProvider.kt @@ -12,10 +12,12 @@ import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.name.ClassId public abstract class KtTypeInfoProvider : KtAnalysisSessionComponent() { public abstract fun isFunctionalInterfaceType(type: KtType): Boolean + public abstract fun getFunctionClassKind(type: KtType): FunctionClassKind? public abstract fun canBeNull(type: KtType): Boolean } @@ -26,6 +28,24 @@ public interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn { public val KtType.isFunctionalInterfaceType: Boolean get() = analysisSession.typeInfoProvider.isFunctionalInterfaceType(this) + /** + * Returns [FunctionClassKind] of the given [KtType] + */ + public val KtType.functionClassKind: FunctionClassKind? + get() = analysisSession.typeInfoProvider.getFunctionClassKind(this) + + public val KtType.isFunctionType: Boolean + get() = functionClassKind == FunctionClassKind.Function + + public val KtType.isKFunctionType: Boolean + get() = functionClassKind == FunctionClassKind.KFunction + + public val KtType.isSuspendFunctionType: Boolean + get() = functionClassKind == FunctionClassKind.SuspendFunction + + public val KtType.isKSuspendFunctionType: Boolean + get() = functionClassKind == FunctionClassKind.KSuspendFunction + /** * Returns true if a public value of this type can potentially be null. This means this type is not a subtype of [Any]. However, it does not * mean one can assign `null` to a variable of this type because it may be unknown if this type can accept `null`. For example, a public value diff --git a/analysis/analysis-api/testData/components/functionClassKind/function.kt b/analysis/analysis-api/testData/components/functionClassKind/function.kt new file mode 100644 index 00000000000..43d6bba41c4 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/function.kt @@ -0,0 +1,7 @@ +fun foo(p: T, mapper : (T) -> R): R { + mapper(p) +} + +fun bar() { + foo(1, xy) +} diff --git a/analysis/analysis-api/testData/components/functionClassKind/function.txt b/analysis/analysis-api/testData/components/functionClassKind/function.txt new file mode 100644 index 00000000000..319dc119262 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/function.txt @@ -0,0 +1,3 @@ +expression: xy +expected type: (T) -> R +functionClassKind: Function diff --git a/analysis/analysis-api/testData/components/functionClassKind/kFunction.kt b/analysis/analysis-api/testData/components/functionClassKind/kFunction.kt new file mode 100644 index 00000000000..0676e3ea603 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/kFunction.kt @@ -0,0 +1,11 @@ +// WITH_REFLECT + +import kotlin.reflect.KFunction1 + +fun foo(p: T, mapper : (T) -> R): R { + mapper(p) +} + +fun bar() { + foo(1, xy as KFunction1) +} diff --git a/analysis/analysis-api/testData/components/functionClassKind/kFunction.txt b/analysis/analysis-api/testData/components/functionClassKind/kFunction.txt new file mode 100644 index 00000000000..cd2a48ec033 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/kFunction.txt @@ -0,0 +1,3 @@ +expression: xy +expected type: (kotlin.Int) -> kotlin.String +functionClassKind: KFunction diff --git a/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.kt b/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.kt new file mode 100644 index 00000000000..561a15ecbe8 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.kt @@ -0,0 +1,11 @@ +// WITH_REFLECT + +import kotlin.reflect.KSuspendFunction0 + +fun foo(pause : suspend () -> Unit) { + pause() +} + +fun bar() { + foo(xy as KSuspendFunction0) +} diff --git a/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.txt b/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.txt new file mode 100644 index 00000000000..2431cb2d249 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/kSuspendFunction.txt @@ -0,0 +1,3 @@ +expression: xy +expected type: suspend () -> kotlin.Unit +functionClassKind: KSuspendFunction diff --git a/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.kt b/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.kt new file mode 100644 index 00000000000..47ce9f8fe1c --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.kt @@ -0,0 +1,7 @@ +fun foo(pause : suspend () -> Unit) { + pause() +} + +fun bar() { + foo(xy) +} diff --git a/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.txt b/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.txt new file mode 100644 index 00000000000..de253d38255 --- /dev/null +++ b/analysis/analysis-api/testData/components/functionClassKind/suspendFunction.txt @@ -0,0 +1,3 @@ +expression: xy +expected type: suspend () -> kotlin.Unit +functionClassKind: SuspendFunction diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/GenerateAnalysisApiTests.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/GenerateAnalysisApiTests.kt index beb75c7e425..d8bda8cb042 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/GenerateAnalysisApiTests.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/GenerateAnalysisApiTests.kt @@ -73,6 +73,10 @@ fun main(args: Array) { model("components/expectedExpressionType") } + testClass { + model("components/functionClassKind") + } + testClass { model("components/overriddenDeclarations") } @@ -147,6 +151,10 @@ fun main(args: Array) { model("components/expectedExpressionType") } +// testClass { +// model("components/functionClassKind") +// } + testClass { model("components/overriddenDeclarations") }