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 3a7956967ca..2becfa1cdba 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 @@ -15,6 +15,9 @@ 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.name.SpecialNames +import org.jetbrains.kotlin.types.DefinitelyNotNullType +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils internal class KtFe10TypeInfoProvider( @@ -37,4 +40,17 @@ internal class KtFe10TypeInfoProvider( require(type is KtFe10Type) return TypeUtils.isNullableType(type.type) } + + override fun isDenotable(type: KtType): Boolean { + require(type is KtFe10Type) + val kotlinType = type.type + return kotlinType.isDenotable() + } + + private fun KotlinType.isDenotable(): Boolean { + if (this is DefinitelyNotNullType) return false + return constructor.isDenotable && + constructor.declarationDescriptor?.name != SpecialNames.NO_NAME_PROVIDED && + arguments.all { it.type.isDenotable() } + } } diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/KtFe10FrontendApiTestConfiguratorService.kt b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/KtFe10FrontendApiTestConfiguratorService.kt index 1f575725368..465c1ab3fe4 100644 --- a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/KtFe10FrontendApiTestConfiguratorService.kt +++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/KtFe10FrontendApiTestConfiguratorService.kt @@ -27,6 +27,9 @@ import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.compilerConfigurationProvider +import java.nio.file.Path +import kotlin.io.path.extension +import kotlin.io.path.nameWithoutExtension object KtFe10FrontendApiTestConfiguratorService : FrontendApiTestConfiguratorService { override val testPrefix: String @@ -64,4 +67,10 @@ object KtFe10FrontendApiTestConfiguratorService : FrontendApiTestConfiguratorSer override fun doOutOfBlockModification(file: KtFile) { // TODO not supported yet } + + override fun preprocessTestDataPath(path: Path): Path { + val newPath = path.resolveSibling(path.nameWithoutExtension + "." + testPrefix + "." + path.extension) + if (newPath.toFile().exists()) return newPath + return path + } } \ No newline at end of file diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/AbstractKtFe10IsDenotableTest.kt b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/AbstractKtFe10IsDenotableTest.kt new file mode 100644 index 00000000000..b9aa6f66c46 --- /dev/null +++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/AbstractKtFe10IsDenotableTest.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.typeProvider + +import org.jetbrains.kotlin.analysis.api.descriptors.test.KtFe10FrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.typeInfoProvider.AbstractIsDenotableTest + +abstract class AbstractKtFe10IsDenotableTest : AbstractIsDenotableTest(KtFe10FrontendApiTestConfiguratorService) \ No newline at end of file diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/KtFe10IsDenotableTestGenerated.java b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/KtFe10IsDenotableTestGenerated.java new file mode 100644 index 00000000000..fb3c9f0733d --- /dev/null +++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/typeProvider/KtFe10IsDenotableTestGenerated.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.descriptors.test.components.typeProvider; + +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/typeInfoProvider/isDenotable") +@TestDataPath("$PROJECT_ROOT") +public class KtFe10IsDenotableTestGenerated extends AbstractKtFe10IsDenotableTest { + @Test + public void testAllFilesPresentInIsDenotable() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile(".*\\.descriptors\\.kt$"), true); + } + + @Test + @TestMetadata("localTypes.kt") + public void testLocalTypes() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.kt"); + } + + @Test + @TestMetadata("simpleTypes.kt") + public void testSimpleTypes() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/simpleTypes.kt"); + } + + @Test + @TestMetadata("smartcast.kt") + public void testSmartcast() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.kt"); + } + + @Test + @TestMetadata("typeParameter.kt") + public void testTypeParameter() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.kt"); + } +} 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 b4207a146d7..0dcb7e96849 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 @@ -5,16 +5,18 @@ package org.jetbrains.kotlin.analysis.api.fir.components -import org.jetbrains.kotlin.fir.resolve.FirSamResolverImpl -import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.types.canBeNull import org.jetbrains.kotlin.analysis.api.components.KtTypeInfoProvider import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType +import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator 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.resolve.FirSamResolverImpl +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.types.canBeNull import org.jetbrains.kotlin.fir.types.functionClassKind +import org.jetbrains.kotlin.fir.types.typeApproximator internal class KtFirTypeInfoProvider( override val analysisSession: KtFirAnalysisSession, @@ -33,4 +35,12 @@ internal class KtFirTypeInfoProvider( } override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull + + override fun isDenotable(type: KtType): Boolean { + val coneType = (type as KtFirType).coneType + return analysisSession.rootModuleSession.typeApproximator.approximateToSuperType( + coneType, + PublicTypeApproximator.PublicApproximatorConfiguration(false) + ) == null + } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/PublicTypeApproximator.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/PublicTypeApproximator.kt index 8b516c19421..bcbd30804e4 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/PublicTypeApproximator.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/PublicTypeApproximator.kt @@ -20,7 +20,7 @@ internal object PublicTypeApproximator { return approximator.approximateToSuperType(type, PublicApproximatorConfiguration(approximateLocalTypes)) } - private class PublicApproximatorConfiguration( + internal class PublicApproximatorConfiguration( override val localTypes: Boolean ) : TypeApproximatorConfiguration.AllFlexibleSameValue() { override val allFlexible: Boolean get() = false diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/AbstractFirIsDenotableTest.kt b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/AbstractFirIsDenotableTest.kt new file mode 100644 index 00000000000..b58c72a6e83 --- /dev/null +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/AbstractFirIsDenotableTest.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.typeProvider + +import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.typeInfoProvider.AbstractIsDenotableTest + +abstract class AbstractFirIsDenotableTest : AbstractIsDenotableTest(FirFrontendApiTestConfiguratorService) \ No newline at end of file diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/FirIsDenotableTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/FirIsDenotableTestGenerated.java new file mode 100644 index 00000000000..a7089fc76ed --- /dev/null +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/typeProvider/FirIsDenotableTestGenerated.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.typeProvider; + +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/typeInfoProvider/isDenotable") +@TestDataPath("$PROJECT_ROOT") +public class FirIsDenotableTestGenerated extends AbstractFirIsDenotableTest { + @Test + public void testAllFilesPresentInIsDenotable() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile(".*\\.descriptors\\.kt$"), true); + } + + @Test + @TestMetadata("localTypes.kt") + public void testLocalTypes() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.kt"); + } + + @Test + @TestMetadata("simpleTypes.kt") + public void testSimpleTypes() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/simpleTypes.kt"); + } + + @Test + @TestMetadata("smartcast.kt") + public void testSmartcast() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.kt"); + } + + @Test + @TestMetadata("typeParameter.kt") + public void testTypeParameter() throws Exception { + runTest("analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.kt"); + } +} diff --git a/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/AbstractFrontendApiTest.kt b/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/AbstractFrontendApiTest.kt index af23e4a5837..832d331f6bb 100644 --- a/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/AbstractFrontendApiTest.kt +++ b/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/AbstractFrontendApiTest.kt @@ -55,6 +55,8 @@ interface FrontendApiTestConfiguratorService { fun prepareTestFiles(files: List, module: TestModule, testServices: TestServices) {} fun doOutOfBlockModification(file: KtFile) + + fun preprocessTestDataPath(path: Path) : Path = path } abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfiguratorService) : TestWithDisposable() { @@ -138,7 +140,7 @@ abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfigur } protected fun runTest(@TestDataFile path: String) { - testDataPath = Paths.get(path) + testDataPath = configurator.preprocessTestDataPath(Paths.get(path)) val testConfiguration = testConfiguration(path, configure) Disposer.register(disposable, testConfiguration.rootDisposable) val testServices = testConfiguration.testServices diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/typeInfoProvider/AbstractIsDenotableTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/typeInfoProvider/AbstractIsDenotableTest.kt new file mode 100644 index 00000000000..2e4d1b421d9 --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/typeInfoProvider/AbstractIsDenotableTest.kt @@ -0,0 +1,94 @@ +/* + * 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.typeInfoProvider + +import com.intellij.psi.PsiElement +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.analysis.api.impl.barebone.parentOfType +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService +import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtAnnotatedExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiUtil.deparenthesize +import org.jetbrains.kotlin.psi.KtQualifiedExpression +import org.jetbrains.kotlin.psi.KtTreeVisitorVoid +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.directives.ConfigurationDirectives +import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives +import org.jetbrains.kotlin.test.model.TestFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.AdditionalSourceProvider +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions +import java.io.File + +abstract class AbstractIsDenotableTest(configurator: FrontendApiTestConfiguratorService) : AbstractHLApiSingleFileTest(configurator) { + val denotableName = Name.identifier("Denotable") + val undenotableName = Name.identifier("Nondenotable") + override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { + val actualText = buildString { + ktFile.accept(object : KtTreeVisitorVoid() { + override fun visitElement(element: PsiElement) { + if (element is LeafPsiElement) { + append(element.text) + } + super.visitElement(element) + } + + + override fun visitAnnotatedExpression(expression: KtAnnotatedExpression) { + val base = expression.baseExpression + if (base == null || expression.annotationEntries.none { + it.shortName == denotableName || it.shortName == undenotableName + }) { + super.visitAnnotatedExpression(expression) + return + } + + analyseForTest(expression) { + val parent = expression.parentOfType() + // Try locating the containing PSI that is a receiver of a qualified expression because the smart cast information + // is only available at that level for FE1.0. For example, consider + // ``` + // if (a is String) { + // (@Denotable("...") a).length + // } + // ``` + // smart cast is available for `(@Denotable("...") a)` and not for `a` or `@Denotable("...") a`. + val ktType = if (parent != null && deparenthesize(parent.receiverExpression) == deparenthesize(base)) { + parent.receiverExpression.getKtType() + } else { + expression.getKtType() + } + val actualHasDenotableType = ktType?.isDenotable ?: error("${base.text} does not have a type.") + when (actualHasDenotableType) { + true -> append("@Denotable") + false -> append("@Nondenotable") + } + append("(\"${ktType.render()}\") ") + append(base.text) + } + } + }) + } + testServices.assertions.assertEqualsToFile(testDataPath, actualText) + } + + override fun configureTest(builder: TestConfigurationBuilder) { + super.configureTest(builder) + builder.useAdditionalSourceProviders(AbstractIsDenotableTest::TestHelperProvider) + builder.defaultDirectives { + +ConfigurationDirectives.WITH_STDLIB + } + } + + private class TestHelperProvider(testServices: TestServices) : AdditionalSourceProvider(testServices) { + override fun produceAdditionalFiles(globalDirectives: RegisteredDirectives, module: TestModule): List { + return listOf(File("analysis/analysis-api/testData/helpers/isDenotable/helpers.kt").toTestFile()) + } + } +} \ No newline at end of file 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 182022d3b53..645882daaa0 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 @@ -19,9 +19,17 @@ 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 + public abstract fun isDenotable(type: KtType): Boolean } public interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn { + /** + * Returns true if this type is denotable. A denotable type is a type that can be written in Kotlin by end users. See + * https://kotlinlang.org/spec/type-system.html#type-kinds for more details. + */ + public val KtType.isDenotable: Boolean + get() = analysisSession.typeInfoProvider.isDenotable(this) + /** * Returns true if this type is a functional interface type, a.k.a. SAM type, e.g., Runnable. */ diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.descriptors.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.descriptors.kt new file mode 100644 index 00000000000..41d3fdeed4a --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.descriptors.kt @@ -0,0 +1,7 @@ +fun test() { + class A + @Denotable("A") A() + @Denotable("kotlin.collections.List") listOf(A()) + @Nondenotable("") object {} + @Nondenotable("kotlin.collections.List<>") listOf(object {}) +} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.kt new file mode 100644 index 00000000000..15c0fb47b64 --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/localTypes.kt @@ -0,0 +1,7 @@ +fun test() { + class A + @Denotable("A") A() + @Denotable("kotlin.collections.List") listOf(A()) + @Nondenotable("") object {} + @Nondenotable("kotlin.collections.List<>") listOf(object {}) +} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/simpleTypes.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/simpleTypes.kt new file mode 100644 index 00000000000..b757d86222f --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/simpleTypes.kt @@ -0,0 +1,6 @@ +interface A +fun test(a: A) { + @Denotable("kotlin.Int") 1 + @Denotable("kotlin.String") "" + Denotable("A") a +} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.descriptors.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.descriptors.kt new file mode 100644 index 00000000000..998cfc95581 --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.descriptors.kt @@ -0,0 +1,28 @@ +fun test(a: Any?) { + if (a is String) { + (@Denotable("kotlin.String") a).length + if (a is Int) { + (@Denotable("kotlin.Int") a).inc() + } + if (a is String) { + (@Denotable("kotlin.String") a).length + } + } + if (a != null) { + (@Denotable("kotlin.Any") a).hashCode() + } + if (a == null) { + (@Denotable("kotlin.Any?") a).isNothing() + } + if (a is String || a is Int) { + (@Denotable("kotlin.Any?") a).length + (@Denotable("kotlin.Any?") a).inc() + } + @Nondenotable("(kotlin.Comparable<*> & java.io.Serializable)") if (true) { + "" + } else { + 1 + } +} + +fun Nothing?.isNothing() {} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.kt new file mode 100644 index 00000000000..6f817e2f7e5 --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/smartcast.kt @@ -0,0 +1,28 @@ +fun test(a: Any?) { + if (a is String) { + (@Denotable("kotlin.String") a).length + if (a is Int) { + (@Nondenotable("(kotlin.String&kotlin.Int)") a).inc() + } + if (a is String) { + (@Denotable("kotlin.String") a).length + } + } + if (a != null) { + (@Denotable("kotlin.Any") a).hashCode() + } + if (a == null) { + (@Denotable("kotlin.Nothing?") a).isNothing() + } + if (a is String || a is Int) { + (@Nondenotable("(kotlin.Comparable<(kotlin.String&kotlin.Int)>&java.io.Serializable)") a).length + (@Nondenotable("(kotlin.Comparable<(kotlin.String&kotlin.Int)>&java.io.Serializable)") a).inc() + } + @Nondenotable("(kotlin.Comparable<*>&java.io.Serializable)") if (true) { + "" + } else { + 1 + } +} + +fun Nothing?.isNothing() {} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.descriptors.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.descriptors.kt new file mode 100644 index 00000000000..da7c04d7b7e --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.descriptors.kt @@ -0,0 +1,25 @@ +interface A + +fun test(t: T) { + @Denotable("T") t + if (t != null) { + (@Nondenotable("T & Any") t).equals("") + } + val outs = take(getOutProjection()) + @Denotable("A") outs + + val ins = take(getInProjection()) + @Denotable(kotlin.Any?) ins +} + +fun getOutProjection(): MutableList { + TODO() +} + +fun getInProjection(): MutableList { + TODO() +} + +fun take(l: MutableList): T { + TODO() +} diff --git a/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.kt b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.kt new file mode 100644 index 00000000000..81b55d58186 --- /dev/null +++ b/analysis/analysis-api/testData/components/typeInfoProvider/isDenotable/typeParameter.kt @@ -0,0 +1,25 @@ +interface A + +fun test(t: T) { + @Denotable("T") t + if (t != null) { + (@Nondenotable("T!!") t).equals("") + } + val outs = take(getOutProjection()) + @Denotable("A") outs + + val ins = take(getInProjection()) + @Denotable(kotlin.Any?) ins +} + +fun getOutProjection(): MutableList { + TODO() +} + +fun getInProjection(): MutableList { + TODO() +} + +fun take(l: MutableList): T { + TODO() +} diff --git a/analysis/analysis-api/testData/helpers/isDenotable/helpers.kt b/analysis/analysis-api/testData/helpers/isDenotable/helpers.kt new file mode 100644 index 00000000000..41655aba3bd --- /dev/null +++ b/analysis/analysis-api/testData/helpers/isDenotable/helpers.kt @@ -0,0 +1,8 @@ +@Target(AnnotationTarget.EXPRESSION) +@Retention(AnnotationRetention.SOURCE) +annotation class Denotable(val type: String) + +@Target(AnnotationTarget.EXPRESSION) +@Retention(AnnotationRetention.SOURCE) +annotation class Nondenotable(val type: String) + diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt index 50e875902d5..5590ffcea64 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.test.components.symbolDecla 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.scopes.AbstractKtFe10SubstitutionOverridesUnwrappingTest +import org.jetbrains.kotlin.analysis.api.descriptors.test.components.typeProvider.AbstractKtFe10IsDenotableTest 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 @@ -46,6 +47,7 @@ import org.jetbrains.kotlin.analysis.api.fir.components.typeCreator.AbstractFirT import org.jetbrains.kotlin.analysis.api.fir.components.typeInfoProvider.AbstractFirFunctionClassKindTest import org.jetbrains.kotlin.analysis.api.fir.components.typeProvider.AbstractFirGetSuperTypesTest import org.jetbrains.kotlin.analysis.api.fir.components.typeProvider.AbstractFirHasCommonSubtypeTest +import org.jetbrains.kotlin.analysis.api.fir.components.typeProvider.AbstractFirIsDenotableTest import org.jetbrains.kotlin.analysis.api.fir.scopes.AbstractFirDelegateMemberScopeTest import org.jetbrains.kotlin.analysis.api.fir.scopes.AbstractFirFileScopeTest import org.jetbrains.kotlin.analysis.api.fir.scopes.AbstractFirMemberScopeByFqNameTest @@ -257,6 +259,9 @@ private fun TestGroupSuite.generateAnalysisApiComponentsTests() { test(fir = AbstractFirGetSuperTypesTest::class, fe10 = null) { model("superTypes") } + test(fir = AbstractFirIsDenotableTest::class, fe10 = AbstractKtFe10IsDenotableTest::class) { + model("isDenotable", excludedPattern = ".*\\.descriptors\\.kt$") + } } component("typeProvider") {