From 481962d5f6c832baf68047eb784828b0d9aab5a7 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Sat, 27 May 2023 15:11:20 +0200 Subject: [PATCH] [LL FIR] get rid of on-air resolve of partial type qualifiers It's very slow and leads to performance problems (see KT-58125) Instead, we do the following: - For a fully resolved type qualifier, when we want to resolve its part, we are looking for the corresponding symbol by traversing nested classes bottom up. - For an error qualifier, we are trying to resolve the maximum possible qualifier in the types transformer where all the type scopes are already available. ^KT-58125 fixed --- ...ceModuleReferenceResolveTestGenerated.java | 70 +++++++++++++++++++ .../references/FirReferenceResolveHelper.kt | 67 ++++++++++++++++-- ...ceModuleReferenceResolveTestGenerated.java | 70 +++++++++++++++++++ ...ceModuleReferenceResolveTestGenerated.java | 70 +++++++++++++++++++ ...ceModuleReferenceResolveTestGenerated.java | 70 +++++++++++++++++++ .../ClassNameBeforeOneUnsresolvedClass.kt | 7 ++ .../ClassNameBeforeOneUnsresolvedClass.txt | 2 + ...assNameBeforeOneUnsresolvedClassWithDot.kt | 7 ++ ...ssNameBeforeOneUnsresolvedClassWithDot.txt | 2 + ...eforeOneUnsresolvedClassWithTwoResolved.kt | 9 +++ ...foreOneUnsresolvedClassWithTwoResolved.txt | 2 + ...eUnsresolvedClassWithTwoResolvedWithDot.kt | 8 +++ ...UnsresolvedClassWithTwoResolvedWithDot.txt | 2 + .../ClassNameBeforeTwoUnsresolvedClasses.kt | 7 ++ .../ClassNameBeforeTwoUnsresolvedClasses.txt | 2 + ...eBeforeTwoUnsresolvedClassesTwoResolved.kt | 9 +++ ...BeforeTwoUnsresolvedClassesTwoResolved.txt | 2 + ...sNameBeforeTwoUnsresolvedClassesWithDot.kt | 7 ++ ...NameBeforeTwoUnsresolvedClassesWithDot.txt | 2 + ...econdQualifierBeforeOneUnsresolvedClass.kt | 9 +++ ...condQualifierBeforeOneUnsresolvedClass.txt | 2 + ...alifierBeforeOneUnsresolvedClassWithDot.kt | 9 +++ ...lifierBeforeOneUnsresolvedClassWithDot.txt | 2 + ...eUnsresolvedClassWithTwoResolvedWithDot.kt | 8 +++ ...UnsresolvedClassWithTwoResolvedWithDot.txt | 2 + .../api/fir/LLFirResolveSessionDepended.kt | 2 +- .../fir/element/builder/FirElementBuilder.kt | 2 +- .../file/structure/FileStructureElement.kt | 30 +++----- .../fir/file/structure/FirElementsRecorder.kt | 13 ++++ .../LLFirSupertypeLazyResolver.kt | 1 - ...cCompilerTestFirTestdataTestGenerated.java | 12 ++++ ...osticCompilerFirTestDataTestGenerated.java | 12 ++++ .../LazyBodyIsNotTouchedTestGenerated.java | 10 +++ .../problems/incompleteUserType.fir.txt | 3 + .../resolve/problems/incompleteUserType.kt | 1 + ...UserTypeWithUnresovledTypeArgument.fir.txt | 9 +++ ...pleteUserTypeWithUnresovledTypeArgument.kt | 3 + .../FirLightTreeDiagnosticsTestGenerated.java | 12 ++++ .../FirPsiDiagnosticTestGenerated.java | 12 ++++ .../converter/DeclarationsConverter.kt | 12 +++- .../kotlin/fir/builder/RawFirBuilder.kt | 11 +++ .../FirSpecificTypeResolverTransformer.kt | 41 ++++++++++- 42 files changed, 600 insertions(+), 33 deletions(-) create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.txt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt create mode 100644 analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/references/Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/references/Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java index 6630dd845b1..75608c08659 100644 --- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/references/Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/references/Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java @@ -2158,5 +2158,75 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte public void testWrongNumberOfTypeArgumentsInSupertype() throws Exception { runTest("analysis/analysis-api/testData/referenceResolve/withErrors/WrongNumberOfTypeArgumentsInSupertype.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier") + @TestDataPath("$PROJECT_ROOT") + public class PartiallyUnresolvedTypeQualifier { + @Test + public void testAllFilesPresentInPartiallyUnresolvedTypeQualifier() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClass.kt") + public void testClassNameBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClasses.kt") + public void testClassNameBeforeTwoUnsresolvedClasses() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt") + public void testClassNameBeforeTwoUnsresolvedClassesTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesWithDot.kt") + public void testClassNameBeforeTwoUnsresolvedClassesWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + } } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt index 5c38295f39b..c2f7f137b28 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.references +import com.intellij.psi.PsiElement import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession @@ -15,9 +16,12 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirPackageSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError +import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError import org.jetbrains.kotlin.fir.FirPackageDirective import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE +import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.buildImport import org.jetbrains.kotlin.fir.declarations.utils.classId @@ -28,10 +32,9 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError -import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.providers.toSymbol +import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator @@ -39,6 +42,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.ClassId @@ -48,6 +52,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty internal object FirReferenceResolveHelper { fun FirResolvedTypeRef.toTargetSymbol(session: FirSession, symbolBuilder: KtSymbolByFirBuilder): KtSymbol? { @@ -471,14 +476,62 @@ internal object FirReferenceResolveHelper { session: FirSession, symbolBuilder: KtSymbolByFirBuilder, ): Collection { + if (!expression.isPartOfUserTypeRefQualifier()) { + return listOfNotNull(fir.toTargetSymbol(session, symbolBuilder)) + } - val isPossiblyPackage = fir is FirErrorTypeRef && expression.isPartOfUserTypeRefQualifier() + if (fir is FirErrorTypeRef) { + tryGettingSymbolFromPartiallyResolvedType(fir, expression, session, symbolBuilder).ifNotEmpty { return this } + return listOfNotNull(getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true)) + } - val resultSymbol = - if (isPossiblyPackage) getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true) - else fir.toTargetSymbol(session, symbolBuilder) + fun unwrapType(type: PsiElement?): KtTypeElement = when (type) { + is KtTypeReference -> unwrapType(type.typeElement) + is KtNullableType -> type.innerType + is KtTypeElement -> type + is KtNameReferenceExpression -> unwrapType(type.parent) + else -> unexpectedElementError(type) + } ?: unexpectedElementError(type) - return listOfNotNull(resultSymbol) + val ktTypeElementFromFirType = unwrapType(fir.psi) + + val classifiersToSkip = expression.parents.takeWhile { it != ktTypeElementFromFirType }.count() + var classifier: FirClassLikeSymbol<*>? = fir.type.toRegularClassSymbol(session) + repeat(classifiersToSkip) { + classifier = classifier?.getContainingClassSymbol(session) + } + + val firClassSymbol = classifier + ?: return listOfNotNull(getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true)) + return listOf(symbolBuilder.classifierBuilder.buildClassifierSymbol(firClassSymbol)) + } + + private tailrec fun tryGettingSymbolFromPartiallyResolvedType( + typeRef: FirTypeRef?, + expression: KtSimpleNameExpression, + session: FirSession, + symbolBuilder: KtSymbolByFirBuilder, + ): Collection { + return when (typeRef) { + null -> emptyList() + is FirErrorTypeRef -> { + tryGettingSymbolFromPartiallyResolvedType( + typeRef.partiallyResolvedTypeRef, + expression, + session, + symbolBuilder, + ) + } + is FirResolvedTypeRef -> { + return getSymbolsForResolvedTypeRef(typeRef, expression, session, symbolBuilder) + } + else -> throwUnexpectedFirElementError( + typeRef, + ktElement = null, + FirErrorTypeRef::class, + FirResolvedTypeRef::class + ) + } } private fun getSymbolsForResolvedQualifier( diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated.java index c358d46096f..685f0f68674 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated.java @@ -2158,5 +2158,75 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex public void testWrongNumberOfTypeArgumentsInSupertype() throws Exception { runTest("analysis/analysis-api/testData/referenceResolve/withErrors/WrongNumberOfTypeArgumentsInSupertype.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier") + @TestDataPath("$PROJECT_ROOT") + public class PartiallyUnresolvedTypeQualifier { + @Test + public void testAllFilesPresentInPartiallyUnresolvedTypeQualifier() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClass.kt") + public void testClassNameBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClasses.kt") + public void testClassNameBeforeTwoUnsresolvedClasses() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt") + public void testClassNameBeforeTwoUnsresolvedClassesTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesWithDot.kt") + public void testClassNameBeforeTwoUnsresolvedClassesWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + } } } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java index 64abd5cb554..4957e50e5d0 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated.java @@ -2158,5 +2158,75 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten public void testWrongNumberOfTypeArgumentsInSupertype() throws Exception { runTest("analysis/analysis-api/testData/referenceResolve/withErrors/WrongNumberOfTypeArgumentsInSupertype.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier") + @TestDataPath("$PROJECT_ROOT") + public class PartiallyUnresolvedTypeQualifier { + @Test + public void testAllFilesPresentInPartiallyUnresolvedTypeQualifier() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClass.kt") + public void testClassNameBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClasses.kt") + public void testClassNameBeforeTwoUnsresolvedClasses() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt") + public void testClassNameBeforeTwoUnsresolvedClassesTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesWithDot.kt") + public void testClassNameBeforeTwoUnsresolvedClassesWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + } } } diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerated.java index 1506e39356c..842aa14b3a1 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerated.java @@ -2158,5 +2158,75 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate public void testWrongNumberOfTypeArgumentsInSupertype() throws Exception { runTest("analysis/analysis-api/testData/referenceResolve/withErrors/WrongNumberOfTypeArgumentsInSupertype.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier") + @TestDataPath("$PROJECT_ROOT") + public class PartiallyUnresolvedTypeQualifier { + @Test + public void testAllFilesPresentInPartiallyUnresolvedTypeQualifier() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClass.kt") + public void testClassNameBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClasses.kt") + public void testClassNameBeforeTwoUnsresolvedClasses() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt") + public void testClassNameBeforeTwoUnsresolvedClassesTwoResolved() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt"); + } + + @Test + @TestMetadata("ClassNameBeforeTwoUnsresolvedClassesWithDot.kt") + public void testClassNameBeforeTwoUnsresolvedClassesWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClass() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt"); + } + + @Test + @TestMetadata("ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt") + public void testClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot() throws Exception { + runTest("analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt"); + } + } } } diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt new file mode 100644 index 00000000000..9d3a4b6c83e --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.kt @@ -0,0 +1,7 @@ + +class Foo + +class C { + val prop: Foo.Bar +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.txt new file mode 100644 index 00000000000..5dd2693fe09 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClass.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt new file mode 100644 index 00000000000..b1324b018c8 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.kt @@ -0,0 +1,7 @@ + +class Foo + +class C { + val prop: Foo.Bar. +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.txt new file mode 100644 index 00000000000..5dd2693fe09 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithDot.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt new file mode 100644 index 00000000000..5d4581a4f17 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.kt @@ -0,0 +1,9 @@ + +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.txt new file mode 100644 index 00000000000..1f890b4875b --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolved.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo \ No newline at end of file diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt new file mode 100644 index 00000000000..e813dd19907 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt @@ -0,0 +1,8 @@ +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz. +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt new file mode 100644 index 00000000000..1f890b4875b --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo \ No newline at end of file diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt new file mode 100644 index 00000000000..88189db8ef4 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.kt @@ -0,0 +1,7 @@ + +class Foo + +class C { + val prop: Foo.Bar.Baz +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.txt new file mode 100644 index 00000000000..5dd2693fe09 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClasses.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt new file mode 100644 index 00000000000..188e260c636 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.kt @@ -0,0 +1,9 @@ + +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz.Bazzzz +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.txt new file mode 100644 index 00000000000..1f890b4875b --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesTwoResolved.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo \ No newline at end of file diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt new file mode 100644 index 00000000000..93c872dbc04 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.kt @@ -0,0 +1,7 @@ + +class Foo + +class C { + val prop: Foo.Bar.Baz. +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.txt new file mode 100644 index 00000000000..5dd2693fe09 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameBeforeTwoUnsresolvedClassesWithDot.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in ROOT) class Foo diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt new file mode 100644 index 00000000000..e08dc99a75a --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.kt @@ -0,0 +1,9 @@ + +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.txt new file mode 100644 index 00000000000..44d815d0b5d --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClass.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in Foo) class Bar diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt new file mode 100644 index 00000000000..dcf79eb9f08 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.kt @@ -0,0 +1,9 @@ + +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz. +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.txt new file mode 100644 index 00000000000..44d815d0b5d --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithDot.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in Foo) class Bar diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt new file mode 100644 index 00000000000..bf104407a20 --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.kt @@ -0,0 +1,8 @@ +class Foo { + class Bar +} + +class C { + val prop: Foo.Bar.Baz. +} + diff --git a/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt new file mode 100644 index 00000000000..44d815d0b5d --- /dev/null +++ b/analysis/analysis-api/testData/referenceResolve/withErrors/partiallyUnresolvedTypeQualifier/ClassNameSecondQualifierBeforeOneUnsresolvedClassWithTwoResolvedWithDot.txt @@ -0,0 +1,2 @@ +Resolved to: +0: (in Foo) class Bar diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt index 6de2f5d9e8b..cd16b8c995c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt @@ -60,7 +60,7 @@ internal class LLFirResolveSessionDepended( override fun getOrBuildFirFor(element: KtElement): FirElement? { val psi = FirElementBuilder.getPsiAsFirElementSource(element) ?: return null - ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it } + ktToFirMapping?.getFirOfClosestParent(psi)?.let { return it } return originalFirResolveSession.getOrBuildFirFor(element = element) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt index 1733af8e5d8..e58330e38d9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt @@ -84,7 +84,7 @@ internal class FirElementBuilder( val structureElement = fileStructure.getStructureElementFor(element) val psi = getPsiAsFirElementSource(element) ?: return null val mappings = structureElement.mappings - return mappings.getFirOfClosestParent(psi, firResolveSession) + return mappings.getFirOfClosestParent(psi) ?: firResolveSession.getOrBuildFirFile(firFile) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt index e469f6c7db0..cb59a8d6487 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt @@ -8,13 +8,17 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.* +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.ClassDiagnosticRetriever import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileDiagnosticRetriever import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirNonLocalDeclarationBuilder import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.correspondingProperty import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.FirBackingFieldBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirFunctionBuilder @@ -26,7 +30,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.psi.* import java.util.concurrent.ConcurrentHashMap -import org.jetbrains.kotlin.fir.correspondingProperty internal sealed class FileStructureElement(val firFile: FirFile, protected val moduleComponents: LLFirModuleResolveComponents) { abstract val psi: KtAnnotated @@ -36,31 +39,16 @@ internal sealed class FileStructureElement(val firFile: FirFile, protected val m internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) { private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder) - private val userTypeMapping = ConcurrentHashMap() - fun getElement(ktElement: KtElement, firResolveSession: LLFirResolveSession): FirElement? { - mapping[ktElement]?.let { return it } - - val userType = when (ktElement) { - is KtUserType -> ktElement - is KtNameReferenceExpression -> ktElement.parent as? KtUserType - else -> null - } ?: return null - - //This is for not inner KtUserType - if (userType.parent is KtTypeReference) return null - - return userTypeMapping.getOrPut(userType) { - val typeReference = KtPsiFactory(ktElement.project).createType(userType.text) - LowLevelFirApiFacadeForResolveOnAir.onAirResolveTypeInPlace(ktElement, typeReference, firResolveSession) - } + fun getElement(ktElement: KtElement): FirElement? { + return mapping[ktElement] } - fun getFirOfClosestParent(element: KtElement, firResolveSession: LLFirResolveSession): FirElement? { + fun getFirOfClosestParent(element: KtElement): FirElement? { var current: PsiElement? = element while (current != null && current !is KtFile) { if (current is KtElement) { - getElement(current, firResolveSession)?.let { return it } + getElement(current)?.let { return it } } current = current.parent } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FirElementsRecorder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FirElementsRecorder.kt index c6a29dc85e2..d9c3515b7b0 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FirElementsRecorder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FirElementsRecorder.kt @@ -105,11 +105,13 @@ internal open class FirElementsRecorder : FirVisitor) { super.visitResolvedTypeRef(errorTypeRef, data) + recordTypeQualifiers(errorTypeRef, data) errorTypeRef.delegatedTypeRef?.accept(this, data) } override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: MutableMap) { super.visitResolvedTypeRef(resolvedTypeRef, data) + recordTypeQualifiers(resolvedTypeRef, data) resolvedTypeRef.delegatedTypeRef?.accept(this, data) } @@ -219,6 +221,17 @@ internal open class FirElementsRecorder : FirVisitor) { + val userTypeRef = resolvedTypeRef.delegatedTypeRef as? FirUserTypeRef ?: return + val qualifiers = userTypeRef.qualifier + if (qualifiers.size <= 1) return + qualifiers.forEachIndexed { index, qualifierPart -> + if (index == qualifiers.lastIndex) return@forEachIndexed + val source = qualifierPart.source?.psi as? KtElement ?: return@forEachIndexed + cache(source, resolvedTypeRef, data) + } + } + companion object { fun recordElementsFrom(firElement: FirElement, recorder: FirElementsRecorder): Map = buildMap { firElement.accept(recorder, this) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt index b3fdf4eeb30..6170449983d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataCo import org.jetbrains.kotlin.fir.resolve.transformers.platformSupertypeUpdater import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.name.ClassId internal object LLFirSupertypeLazyResolver : LLFirLazyResolver(FirResolvePhase.SUPER_TYPES) { override fun resolve( diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java index 517d77f894b..d0ad7b42e4b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java @@ -3781,6 +3781,18 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt"); } + @Test + @TestMetadata("incompleteUserType.kt") + public void testIncompleteUserType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt"); + } + + @Test + @TestMetadata("incompleteUserTypeWithUnresovledTypeArgument.kt") + public void testIncompleteUserTypeWithUnresovledTypeArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt"); + } + @Test @TestMetadata("innerClassHierarchy.kt") public void testInnerClassHierarchy() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java index ad0dc210622..7583bbf1907 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java @@ -3781,6 +3781,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt"); } + @Test + @TestMetadata("incompleteUserType.kt") + public void testIncompleteUserType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt"); + } + + @Test + @TestMetadata("incompleteUserTypeWithUnresovledTypeArgument.kt") + public void testIncompleteUserTypeWithUnresovledTypeArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt"); + } + @Test @TestMetadata("innerClassHierarchy.kt") public void testInnerClassHierarchy() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java index 1845ba88e29..a8b2f3924ae 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java @@ -3326,6 +3326,16 @@ public class LazyBodyIsNotTouchedTestGenerated extends AbstractLazyBodyIsNotTouc runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt"); } + @TestMetadata("incompleteUserType.kt") + public void testIncompleteUserType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt"); + } + + @TestMetadata("incompleteUserTypeWithUnresovledTypeArgument.kt") + public void testIncompleteUserTypeWithUnresovledTypeArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt"); + } + @TestMetadata("innerClassHierarchy.kt") public void testInnerClassHierarchy() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/problems/innerClassHierarchy.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.fir.txt b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.fir.txt new file mode 100644 index 00000000000..b2bd3eeafb0 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.fir.txt @@ -0,0 +1,3 @@ +FILE: incompleteUserType.kt + public final fun foo(a: ): R|kotlin/Unit| { + } diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt new file mode 100644 index 00000000000..1786e01b86b --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt @@ -0,0 +1 @@ +fun foo(a : Unresolved.) {} diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.fir.txt b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.fir.txt new file mode 100644 index 00000000000..7dc837551c1 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.fir.txt @@ -0,0 +1,9 @@ +FILE: incompleteUserTypeWithUnresovledTypeArgument.kt + public final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + } + public final fun foo(a: ): R|kotlin/Unit| { + } diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt new file mode 100644 index 00000000000..748bf0dbb50 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt @@ -0,0 +1,3 @@ +class A + +fun foo(a : A<Unresolved>.) {} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java index 7081378ac1b..74dd31493e2 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java @@ -3781,6 +3781,18 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt"); } + @Test + @TestMetadata("incompleteUserType.kt") + public void testIncompleteUserType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt"); + } + + @Test + @TestMetadata("incompleteUserTypeWithUnresovledTypeArgument.kt") + public void testIncompleteUserTypeWithUnresovledTypeArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt"); + } + @Test @TestMetadata("innerClassHierarchy.kt") public void testInnerClassHierarchy() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java index 9cd3cff32a5..72729bc3fc5 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java @@ -3781,6 +3781,18 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest runTest("compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt"); } + @Test + @TestMetadata("incompleteUserType.kt") + public void testIncompleteUserType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserType.kt"); + } + + @Test + @TestMetadata("incompleteUserTypeWithUnresovledTypeArgument.kt") + public void testIncompleteUserTypeWithUnresovledTypeArgument() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/incompleteUserTypeWithUnresovledTypeArgument.kt"); + } + @Test @TestMetadata("innerClassHierarchy.kt") public void testInnerClassHierarchy() throws Exception { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 2ab6f648fc5..31f073f81c5 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -2168,11 +2168,21 @@ class DeclarationsConverter( } } - if (identifier == null) + if (identifier == null) { return buildErrorTypeRef { source = typeRefSource diagnostic = ConeSyntaxDiagnostic("Incomplete user type") + simpleFirUserType?.let { qualifierPart -> + if (qualifierPart.qualifier.isNotEmpty()) { + partiallyResolvedTypeRef = buildUserTypeRef { + source = qualifierPart.qualifier.last().source + isMarkedNullable = false + this.qualifier.addAll(qualifierPart.qualifier) + } + } + } } + } val qualifierPart = FirQualifierPartImpl( identifierSource!!, diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 48e98794d15..542b020a128 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -1979,6 +1979,17 @@ open class RawFirBuilder( FirErrorTypeRefBuilder().apply { this.source = source diagnostic = ConeSyntaxDiagnostic("Incomplete user type") + + val qualifier = unwrappedElement.qualifier + val reference = qualifier?.referenceExpression + if (qualifier != null && reference != null) { + partiallyResolvedTypeRef = convertKtTypeElement( + qualifier.toFirSourceElement(), + isNullable = false, + qualifier, + reference + ).build() + } } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt index bc74ba3a0ce..083c9fcf284 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.resolve.typeResolver import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef +import org.jetbrains.kotlin.fir.types.builder.buildUserTypeRef class FirSpecificTypeResolverTransformer( override val session: FirSession, @@ -82,7 +83,7 @@ class FirSpecificTypeResolverTransformer( typeRef.transformChildren(this, data) } val (resolvedType, diagnostic) = resolveType(typeRef, data) - return transformType(typeRef, resolvedType, diagnostic) + return transformType(typeRef, resolvedType, diagnostic, data) } @OptIn(PrivateForInline::class) @@ -135,6 +136,7 @@ class FirSpecificTypeResolverTransformer( typeRef: FirTypeRef, resolvedType: ConeKotlinType, diagnostic: ConeDiagnostic?, + scopeClassDeclaration: ScopeClassDeclaration, ): FirResolvedTypeRef { return when { resolvedType is ConeErrorType -> { @@ -154,6 +156,7 @@ class FirSpecificTypeResolverTransformer( delegatedTypeRef = typeRef type = resolvedType + partiallyResolvedTypeRef = tryCalculatingPartiallyResolvedTypeRef(typeRef, scopeClassDeclaration) this.diagnostic = resolvedType.diagnostic } @@ -164,6 +167,7 @@ class FirSpecificTypeResolverTransformer( this.diagnostic = diagnostic type = resolvedType delegatedTypeRef = typeRef + partiallyResolvedTypeRef = tryCalculatingPartiallyResolvedTypeRef(typeRef, scopeClassDeclaration) } } else -> { @@ -177,6 +181,41 @@ class FirSpecificTypeResolverTransformer( } } + /** + * Tries to calculate a partially resolved type reference for a type reference which was resolved to an error type. + * It will attempt to resolve the type with a decreasing number of qualifiers until it succeeds, allowing + * partial resolution in case of errors in the type reference. + * + * This is useful for providing better IDE support when resolving partially incorrect types. + * + * @param typeRef The type reference for which to try to calculate a partially resolved type reference. + * @param data The scope class declaration containing relevant information for resolving the reference. + * @return A partially resolved type reference if it was resolved, or `null` otherwise. + */ + private fun tryCalculatingPartiallyResolvedTypeRef(typeRef: FirTypeRef, data: ScopeClassDeclaration): FirTypeRef? { + if (typeRef !is FirUserTypeRef) return null + val qualifiers = typeRef.qualifier + if (qualifiers.size <= 1) { + return null + } + val qualifiersToTry = qualifiers.toMutableList() + while (qualifiersToTry.size > 1) { + qualifiersToTry.removeLast() + val typeRefToTry = buildUserTypeRef { + qualifier += qualifiersToTry + isMarkedNullable = false + } + val (resolvedType, diagnostic) = resolveType(typeRefToTry, data) + if (resolvedType is ConeErrorType || diagnostic != null) continue + return buildResolvedTypeRef { + source = qualifiersToTry.last().source + type = resolvedType + delegatedTypeRef = typeRefToTry + } + } + return null + } + private fun ConeKotlinType.takeIfAcceptable(): ConeKotlinType? = this.takeUnless { !errorTypeAsResolved && it is ConeErrorType }