diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt index e5ee1ff45c0..74f180453e9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt @@ -96,7 +96,9 @@ private fun ConeKotlinType.simplifyType( return currentType } currentType = currentType.upperBoundIfFlexible() - currentType = substitutor.substituteOrSelf(currentType) + if (visibilityForApproximation != Visibilities.Local) { + currentType = substitutor.substituteOrSelf(currentType) + } val needLocalTypeApproximation = needLocalTypeApproximation(visibilityForApproximation, isInlineFunction, session, useSitePosition) // TODO: can we approximate local types in type arguments *selectively* ? currentType = PublicTypeApproximator.approximateTypeToPublicDenotable(currentType, session, needLocalTypeApproximation) @@ -132,6 +134,7 @@ private val PsiElement.visibilityForApproximation: Visibility val containerVisibility = if (parent is KtLightClassForFacade) Visibilities.Public else (parent as? PsiClass)?.visibility ?: Visibilities.Local + val visibility = visibility if (containerVisibility == Visibilities.Local || visibility == Visibilities.Local) return Visibilities.Local if (containerVisibility == Visibilities.Private) return Visibilities.Private return visibility @@ -140,6 +143,7 @@ private val PsiElement.visibilityForApproximation: Visibility // Mimic JavaElementUtil#getVisibility private val PsiModifierListOwner.visibility: Visibility get() { + if (parents.any { it is PsiMethod }) return Visibilities.Local if (hasModifierProperty(PsiModifier.PUBLIC)) { return Visibilities.Public } @@ -211,19 +215,12 @@ private class AnonymousTypesSubstitutor( override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeClassLikeType) return null - val isAnonymous = type.classId.let { it?.shortClassName?.asString() == SpecialNames.ANONYMOUS_STRING } - if (!isAnonymous) return null - - fun ConeClassLikeType.isNotInterface(): Boolean { - val firClassNode = lookupTag.toSymbol(session) as? FirClassSymbol<*> ?: return false - return firClassNode.classKind != ClassKind.INTERFACE - } + val hasStableName = type.classId?.isLocal == true + if (!hasStableName) return null val firClassNode = type.lookupTag.toSymbol(session) as? FirClassSymbol if (firClassNode != null) { - val superTypesCones = firClassNode.resolvedSuperTypes - val superClass = superTypesCones.firstOrNull { (it as? ConeClassLikeType)?.isNotInterface() == true } - if (superClass != null) return superClass + firClassNode.resolvedSuperTypes.singleOrNull()?.let { return it } } return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/psiTypeProvider/AbstractAnalysisApiPsiTypeProviderTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/psiTypeProvider/AbstractAnalysisApiPsiTypeProviderTest.kt index d47560c19d8..2c46c3c10c8 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/psiTypeProvider/AbstractAnalysisApiPsiTypeProviderTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/psiTypeProvider/AbstractAnalysisApiPsiTypeProviderTest.kt @@ -14,11 +14,11 @@ import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerPro import org.jetbrains.kotlin.analysis.test.framework.utils.executeOnPooledThreadInReadAction import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.test.services.TestModuleStructure import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.assertions import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull abstract class AbstractAnalysisApiPsiTypeProviderTest : AbstractAnalysisApiBasedTest() { override fun doTestByModuleStructure(moduleStructure: TestModuleStructure, testServices: TestServices) { @@ -26,9 +26,14 @@ abstract class AbstractAnalysisApiPsiTypeProviderTest : AbstractAnalysisApiBased val ktFiles = testServices.ktModuleProvider.getModuleFiles(module).filterIsInstance() testServices.expressionMarkerProvider.getElementsOfTypeAtCarets(ktFiles) }.single() - val containingClass = getContainingKtLightClass(declaration, ktFile) - val psiContext = containingClass.findLightDeclarationContext(declaration) - ?: error("Can't find psi context for $declaration") + + val psiContext = if (KtPsiUtil.isLocal(declaration)) { + declaration + } else { + val containingClass = getContainingKtLightClass(declaration, ktFile) + containingClass.findLightDeclarationContext(declaration) ?: error("Can't find psi context for $declaration") + } + val actual = buildString { executeOnPooledThreadInReadAction { analyze(declaration) { @@ -38,6 +43,7 @@ abstract class AbstractAnalysisApiPsiTypeProviderTest : AbstractAnalysisApiBased } } } + testServices.assertions.assertEqualsToTestDataFileSibling(actual) } } \ No newline at end of file diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java index 315748b59ce..a43a02892c8 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java @@ -96,6 +96,12 @@ public class SymbolLightClassesByPsiForLibraryTestGenerated extends AbstractSymb runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/enums.kt"); } + @Test + @TestMetadata("exposedAnonymousType.kt") + public void testExposedAnonymousType() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.kt"); + } + @Test @TestMetadata("generics.kt") public void testGenerics() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java index c3d65340e83..ed0b6eb5146 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java @@ -96,6 +96,12 @@ public class SymbolLightClassesByPsiForSourceTestGenerated extends AbstractSymbo runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/enums.kt"); } + @Test + @TestMetadata("exposedAnonymousType.kt") + public void testExposedAnonymousType() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.kt"); + } + @Test @TestMetadata("generics.kt") public void testGenerics() throws Exception { diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.fir.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.fir.java new file mode 100644 index 00000000000..e48b4cb410c --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.fir.java @@ -0,0 +1,38 @@ +final class null /* null*/ { + private ();// .ctor() +} + +final class null /* null*/ extends A { + private ();// .ctor() +} + +final class null /* null*/ implements B { + private ();// .ctor() +} + +final class null /* null*/ extends A implements B { + private ();// .ctor() +} + +public abstract class A /* A*/ { + public A();// .ctor() +} + +public abstract interface B /* B*/ { +} + +public final class C /* C*/ { + @org.jetbrains.annotations.NotNull() + private final A x2; + + @org.jetbrains.annotations.NotNull() + private final B x3; + + @org.jetbrains.annotations.NotNull() + private final java.lang.Object x1; + + @org.jetbrains.annotations.NotNull() + private final java.lang.Object x4; + + public C();// .ctor() +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.java new file mode 100644 index 00000000000..929b16c229b --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.java @@ -0,0 +1,38 @@ +final class null /* null*/ { + private ();// .ctor() +} + +final class null /* null*/ extends A { + private ();// .ctor() +} + +final class null /* null*/ implements B { + private ();// .ctor() +} + +final class null /* null*/ extends A implements B { + private ();// .ctor() +} + +public abstract class A /* A*/ { + public A();// .ctor() +} + +public abstract interface B /* B*/ { +} + +public final class C /* C*/ { + @org.jetbrains.annotations.NotNull() + private final A x2; + + @org.jetbrains.annotations.NotNull() + private final A x4; + + @org.jetbrains.annotations.NotNull() + private final B x3; + + @org.jetbrains.annotations.NotNull() + private final java.lang.Object x1; + + public C();// .ctor() +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.kt b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.kt new file mode 100644 index 00000000000..83fadf6a086 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.kt @@ -0,0 +1,9 @@ +abstract class A +interface B + +class C { + private val x1 = object {} + private val x2 = object : A() {} + private val x3 = object : B {} + private val x4 = object : A(), B {} +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.lib.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.lib.java new file mode 100644 index 00000000000..8f784c0f129 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/exposedAnonymousType.lib.java @@ -0,0 +1,22 @@ +public abstract class A /* A*/ { + public A();// .ctor() +} + +public abstract interface B /* B*/ { +} + +public final class C /* C*/ { + @org.jetbrains.annotations.NotNull() + private final C.x1.1 x1; + + @org.jetbrains.annotations.NotNull() + private final C.x2.1 x2; + + @org.jetbrains.annotations.NotNull() + private final C.x3.1 x3; + + @org.jetbrains.annotations.NotNull() + private final C.x4.1 x4; + + public C();// .ctor() +}