From bf610323cfb488e568a063c00908da10254ce12c Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 23 Aug 2019 16:22:30 +0300 Subject: [PATCH] Support basic light-classes basic with FIR for CLI --- .../kotlin/fir/java/FirJavaElementFinder.kt | 282 ++++++++++++++++++ .../fir/java/FirJavaModuleBasedSession.kt | 6 + .../fir/java/declarations/FirJavaClass.kt | 3 + .../kotlin/fir/resolve/FirProvider.kt | 4 +- .../fir/resolve/impl/FirProviderImpl.kt | 14 +- .../transformers/FirBodyResolveTransformer.kt | 6 +- .../kotlin/fir/types/ConeTypeContext.kt | 74 ++++- .../diagnostics/j+k/KJKComplexHierarchy.kt | 30 ++ .../diagnostics/j+k/KJKComplexHierarchy.txt | 39 +++ .../j+k/KJKComplexHierarchyWithNested.kt | 37 +++ .../j+k/KJKComplexHierarchyWithNested.txt | 45 +++ .../diagnostics/j+k/KJKInheritance.kt | 18 ++ .../diagnostics/j+k/KJKInheritance.txt | 22 ++ .../diagnostics/j+k/KJKInheritanceGeneric.kt | 17 ++ .../diagnostics/j+k/KJKInheritanceGeneric.txt | 23 ++ .../diagnostics/j+k/KotlinClassParameter.kt | 13 + .../diagnostics/j+k/KotlinClassParameter.txt | 12 + .../j+k/KotlinClassParameterGeneric.kt | 15 + .../j+k/KotlinClassParameterGeneric.txt | 14 + .../diagnostics/j+k/outerInnerClasses.kt | 34 +++ .../diagnostics/j+k/outerInnerClasses.txt | 46 +++ .../testData/lightClasses/genericClasses.kt | 5 + .../testData/lightClasses/genericClasses.txt | 4 + .../testData/lightClasses/nestedClasses.kt | 8 + .../testData/lightClasses/nestedClasses.txt | 7 + .../resolve/testData/lightClasses/simple.kt | 11 + .../resolve/testData/lightClasses/simple.txt | 5 + .../testData/lightClasses/typeMapping.kt | 16 + .../testData/lightClasses/typeMapping.txt | 20 ++ .../fir/AbstractFirDiagnosticsSmokeTest.kt | 15 +- .../kotlin/fir/AbstractFirDiagnosticsTest.kt | 26 ++ .../fir/FirDiagnosticsTestGenerated.java | 79 +++++ .../fir/java/AbstractFirLightClassesTest.kt | 53 ++++ .../java/FirLightClassesTestGenerated.java | 51 ++++ .../fir/declarations/FirRegularClass.kt | 2 + .../fir/declarations/impl/FirClassImpl.kt | 8 + .../fir/declarations/impl/FirEnumEntryImpl.kt | 10 +- .../generators/tests/GenerateCompilerTests.kt | 14 + 38 files changed, 1077 insertions(+), 11 deletions(-) create mode 100644 compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.txt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt create mode 100644 compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.txt create mode 100644 compiler/fir/resolve/testData/lightClasses/genericClasses.kt create mode 100644 compiler/fir/resolve/testData/lightClasses/genericClasses.txt create mode 100644 compiler/fir/resolve/testData/lightClasses/nestedClasses.kt create mode 100644 compiler/fir/resolve/testData/lightClasses/nestedClasses.txt create mode 100644 compiler/fir/resolve/testData/lightClasses/simple.kt create mode 100644 compiler/fir/resolve/testData/lightClasses/simple.txt create mode 100644 compiler/fir/resolve/testData/lightClasses/typeMapping.kt create mode 100644 compiler/fir/resolve/testData/lightClasses/typeMapping.txt create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsTest.kt create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/AbstractFirLightClassesTest.kt create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/FirLightClassesTestGenerated.java diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt new file mode 100644 index 00000000000..2d3586b2fce --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt @@ -0,0 +1,282 @@ +/* + * Copyright 2010-2019 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.fir.java + +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Pair +import com.intellij.psi.* +import com.intellij.psi.impl.cache.ModifierFlags +import com.intellij.psi.impl.compiled.ClsClassImpl +import com.intellij.psi.impl.compiled.ClsFileImpl +import com.intellij.psi.impl.file.PsiPackageImpl +import com.intellij.psi.impl.java.stubs.* +import com.intellij.psi.impl.java.stubs.impl.* +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.stubs.StubElement +import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.classId +import org.jetbrains.kotlin.fir.declarations.superConeTypes +import org.jetbrains.kotlin.fir.resolve.FirProvider +import org.jetbrains.kotlin.fir.resolve.directExpansionType +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.service +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType +import org.jetbrains.kotlin.resolve.jvm.KotlinFinderMarker + +class FirJavaElementFinder( + private val session: FirSession, + project: Project +) : PsiElementFinder(), KotlinFinderMarker { + private val psiManager = PsiManager.getInstance(project) + private val firProvider = session.service() + + override fun findPackage(qualifiedName: String): PsiPackage? { + if (firProvider.getClassNamesInPackage(FqName(qualifiedName)).isEmpty()) return null + return PsiPackageImpl(psiManager, qualifiedName) + } + + override fun getClasses(psiPackage: PsiPackage, scope: GlobalSearchScope): Array { + return firProvider + .getClassNamesInPackage(FqName(psiPackage.qualifiedName)) + .mapNotNull { findClass(psiPackage.qualifiedName + "." + it.identifier, scope) } + .toTypedArray() + } + + override fun findClasses(qualifiedName: String, scope: GlobalSearchScope): Array { + return findClass(qualifiedName, scope)?.let(::arrayOf) ?: emptyArray() + } + + override fun findClass(qualifiedName: String, scope: GlobalSearchScope): PsiClass? { + val classId = ClassId.topLevel(FqName(qualifiedName)) + + val firClass = + firProvider.getFirClassifierByFqName(classId) as? FirRegularClass + ?: return null + + val ktFile = firClass.psi?.containingFile as KtFile + val fileStub = createJavaFileStub(classId.packageFqName, listOf(ktFile)) + + return buildStub(firClass, fileStub).psi + } + + private fun buildStub(firClass: FirRegularClass, parent: StubElement<*>): PsiClassStub<*> { + val classId = firClass.classId + val stub = PsiClassStubImpl( + JavaStubElementTypes.CLASS, parent, classId.asSingleFqName().asString(), firClass.name.identifier, null, + PsiClassStubImpl.packFlags( + false, + firClass.classKind == ClassKind.INTERFACE, + firClass.classKind == ClassKind.ENUM_CLASS, false, false, + firClass.classKind == ClassKind.ANNOTATION_CLASS, false, false, + false, false, false + ) + ) + + PsiModifierListStubImpl(stub, firClass.packFlags()) + + newTypeParameterList( + stub, + firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) } + ) + + if (firClass.superTypeRefs.any { it !is FirResolvedTypeRef }) { + firClass.setCallbackOnSupertypesComputed { + stub.addSupertypesReferencesLists(firClass, session) + } + } else { + stub.addSupertypesReferencesLists(firClass, session) + } + + for (nestedClass in firClass.declarations.filterIsInstance()) { + buildStub(nestedClass, stub) + } + + return stub + } + +} + +private fun FirRegularClass.packFlags(): Int { + var flags = when (visibility) { + Visibilities.PRIVATE -> ModifierFlags.PRIVATE_MASK + Visibilities.PROTECTED -> ModifierFlags.PROTECTED_MASK + Visibilities.PUBLIC -> ModifierFlags.PUBLIC_MASK + else -> ModifierFlags.PACKAGE_LOCAL_MASK + } + + flags = flags or when (modality) { + Modality.FINAL -> ModifierFlags.FINAL_MASK + Modality.ABSTRACT -> ModifierFlags.ABSTRACT_MASK + else -> 0 + } + + if (classId.isNestedClass && !isInner) { + flags = flags or ModifierFlags.STATIC_MASK + } + + return flags +} + +private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: FirRegularClass, session: FirSession) { + require(firRegularClass.superTypeRefs.all { it is FirResolvedTypeRef }) { + "Supertypes for light class $qualifiedName are being added too early" + } + + val isInterface = firRegularClass.classKind == ClassKind.INTERFACE + + val interfaceNames = mutableListOf() + var superName: String? = null + + for (superConeType in firRegularClass.superConeTypes) { + val supertypeFirClass = superConeType.toFirClass(session) ?: continue + + val canonicalString = superConeType.mapToCanonicalString(session) + + if (isInterface || supertypeFirClass.classKind == ClassKind.INTERFACE) { + interfaceNames.add(canonicalString) + } else { + superName = canonicalString + } + } + + if (this.isInterface) { + if (interfaceNames.isNotEmpty() && this.isAnnotationType) { + interfaceNames.remove(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION) + } + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, this, ArrayUtil.toStringArray(interfaceNames)) + newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, this, ArrayUtil.EMPTY_STRING_ARRAY) + } else { + if (superName == null || "java/lang/Object" == superName || this.isEnum && "java/lang/Enum" == superName) { + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, this, ArrayUtil.EMPTY_STRING_ARRAY) + } else { + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, this, arrayOf(superName)) + } + newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, this, ArrayUtil.toStringArray(interfaceNames)) + } + +} + +private fun newReferenceList(type: JavaClassReferenceListElementType, parent: StubElement<*>, types: Array) { + PsiClassReferenceListStubImpl(type, parent, types) +} + +private fun newTypeParameterList(parent: StubElement<*>, parameters: List>>) { + val listStub = PsiTypeParameterListStubImpl(parent) + for (parameter in parameters) { + val parameterStub = PsiTypeParameterStubImpl(listStub, parameter.first) + newReferenceList(JavaStubElementTypes.EXTENDS_BOUND_LIST, parameterStub, parameter.second) + } +} + +private fun createJavaFileStub(packageFqName: FqName, files: Collection): PsiJavaFileStub { + val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), /*compiled = */true) + javaFileStub.psiFactory = ClsStubPsiFactory.INSTANCE + + val fakeFile = object : ClsFileImpl(files.first().viewProvider) { + override fun getStub() = javaFileStub + + override fun getPackageName() = packageFqName.asString() + + override fun isPhysical() = false + + override fun getText(): String { + return files.singleOrNull()?.text ?: super.getText() + } + } + + javaFileStub.psi = fakeFile + return javaFileStub +} + +private fun ConeClassLikeType.toFirClass(session: FirSession): FirRegularClass? { + return when (this) { + is ConeAbbreviatedType -> this.directExpansionType(session)?.toFirClass(session) + else -> (this.lookupTag.toSymbol(session) as? FirClassSymbol)?.fir + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// JVM TYPE MAPPING +// TODO: reuse other type mapping implementations when possible +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +private const val ERROR_TYPE_STUB = CommonClassNames.JAVA_LANG_OBJECT + +private fun ConeKotlinType.mapToCanonicalString(session: FirSession): String { + return when (this) { + is ConeClassLikeType -> mapToCanonicalString(session) + is ConeTypeParameterType -> lookupTag.name.asString() + is ConeTypeVariableType, is ConeFlexibleType, is ConeCapturedType, is ConeDefinitelyNotNullType, is ConeIntersectionType -> + error("Unexpected type: $this [${this::class}]") + } +} + +private fun ConeClassLikeType.mapToCanonicalString(session: FirSession): String { + return when (this) { + is ConeAbbreviatedType -> this.directExpansionType(session)?.mapToCanonicalString(session) ?: ERROR_TYPE_STUB + is ConeClassType -> mapToCanonicalString(session) + is ConeClassErrorType -> ERROR_TYPE_STUB + } +} + +private fun ConeClassType.mapToCanonicalString(session: FirSession): String { + if (lookupTag.classId == StandardClassIds.Array) { + return when (val typeProjection = typeArguments[0]) { + is ConeStarProjection -> CommonClassNames.JAVA_LANG_OBJECT + is ConeTypedProjection -> { + if (typeProjection.kind == ProjectionKind.IN) + CommonClassNames.JAVA_LANG_VOID + else + (typeProjection.type as ConeClassLikeType).mapToCanonicalString(session) + } + else -> ERROR_TYPE_STUB + } + "[]" + } + + val context = ConeTypeCheckerContext(false, session) + + with(context) { + val typeConstructor = typeConstructor() + typeConstructor.getPrimitiveType()?.let { return JvmPrimitiveType.get(it).wrapperFqName.asString() } + typeConstructor.getPrimitiveArrayType()?.let { return JvmPrimitiveType.get(it).javaKeywordName + "[]" } + val kotlinClassFqName = typeConstructor.getClassFqNameUnsafe() ?: return ERROR_TYPE_STUB + val mapped = JavaToKotlinClassMap.mapKotlinToJava(kotlinClassFqName)?.asSingleFqName() ?: kotlinClassFqName + + return mapped.toString() + + typeArguments.takeIf { it.isNotEmpty() } + ?.joinToString(separator = ", ", prefix = "<", postfix = ">") { it.mapToCanonicalString(session) } + .orEmpty() + } + +} + +private fun ConeKotlinTypeProjection.mapToCanonicalString(session: FirSession): String { + return when (this) { + is ConeStarProjection -> "?" + is ConeTypedProjection -> { + val wildcard = when (kind) { + ProjectionKind.STAR -> error("Should be handled in the case above") + ProjectionKind.IN -> "? super " + ProjectionKind.OUT -> "? extends " + ProjectionKind.INVARIANT -> "" + } + + wildcard + type.mapToCanonicalString(session) + } + else -> ERROR_TYPE_STUB + } +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt index a726e31644f..77b0d0e0741 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt @@ -5,7 +5,9 @@ package org.jetbrains.kotlin.fir.java +import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElementFinder import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.* @@ -52,6 +54,10 @@ class FirJavaModuleBasedSession( FirCorrespondingSupertypesCache::class, FirCorrespondingSupertypesCache(this) ) + + Extensions.getArea(sessionProvider.project) + .getExtensionPoint(PsiElementFinder.EP_NAME) + .registerExtension(FirJavaElementFinder(this, sessionProvider.project)) } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt index 106cba23234..0d0141ee99d 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt @@ -57,4 +57,7 @@ class FirJavaClass internal constructor( superTypeRefs.addAll(newSupertypes) return this } + + override fun setCallbackOnSupertypesComputed(callback: () -> Unit) = + error("Supertypes computation should happen just before the instance is published") } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt index 2d5ce1b3914..299accc8d5b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt @@ -6,8 +6,8 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.service import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol @@ -18,7 +18,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name abstract class FirProvider : FirSymbolProvider() { - abstract fun getFirClassifierByFqName(fqName: ClassId): FirMemberDeclaration? + abstract fun getFirClassifierByFqName(fqName: ClassId): FirClassLikeDeclaration<*>? abstract override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt index e6cd796b888..333206adfa2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt @@ -14,7 +14,9 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.buildDefaultUseSiteScope import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope -import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol @@ -46,6 +48,10 @@ class FirProviderImpl(val session: FirSession) : FirProvider() { return state.classifierContainerFileMap[fqName] ?: error("Couldn't find container for $fqName") } + override fun getClassNamesInPackage(fqName: FqName): Set { + return state.classesInPackage[fqName] ?: emptySet() + } + fun recordFile(file: FirFile) { recordFile(file, state) } @@ -64,6 +70,10 @@ class FirProviderImpl(val session: FirSession) : FirProvider() { state.classifierMap[classId] = regularClass state.classifierContainerFileMap[classId] = file + if (!classId.isNestedClass && !classId.isLocal) { + state.classesInPackage.getOrPut(classId.packageFqName, ::mutableSetOf).add(classId.shortClassName) + } + regularClass.acceptChildren(this) } @@ -102,6 +112,7 @@ class FirProviderImpl(val session: FirSession) : FirProvider() { val fileMap = mutableMapOf>() val classifierMap = mutableMapOf>() val classifierContainerFileMap = mutableMapOf() + val classesInPackage = mutableMapOf>() val callableMap = mutableMapOf>>() val callableContainerMap = mutableMapOf() @@ -117,6 +128,7 @@ class FirProviderImpl(val session: FirSession) : FirProvider() { classifierContainerFileMap.putAll(other.classifierContainerFileMap) callableMap.putAll(other.callableMap) callableContainerMap.putAll(other.callableContainerMap) + classesInPackage.putAll(other.classesInPackage) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 48658d342c9..a7ea87ef063 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -25,6 +25,10 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult @@ -1028,4 +1032,4 @@ internal inline var FirExpression.resultType: FirTypeRef get() = typeRef set(type) { replaceTypeRef(type) - } \ No newline at end of file + } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index f0e6192da91..6be033fddea 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -5,10 +5,12 @@ package org.jetbrains.kotlin.fir.types +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirTypeParameter import org.jetbrains.kotlin.fir.declarations.expandedConeType import org.jetbrains.kotlin.fir.declarations.superConeTypes import org.jetbrains.kotlin.fir.resolve.* @@ -17,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.ConeTypeVariableTypeConstructor import org.jetbrains.kotlin.fir.resolve.calls.hasNullableSuperType import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap +import org.jetbrains.kotlin.fir.resolve.transformers.firSafeNullable import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe import org.jetbrains.kotlin.fir.service import org.jetbrains.kotlin.fir.symbols.* @@ -26,13 +29,18 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.AbstractTypeCheckerContext +import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.checker.convertVariance import org.jetbrains.kotlin.types.model.* class ErrorTypeConstructor(val reason: String) : TypeConstructorMarker -interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, TypeCheckerProviderContext { +interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, TypeCheckerProviderContext, TypeSystemCommonBackendContext { val session: FirSession override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean { @@ -431,6 +439,70 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty return false } + private fun TypeConstructorMarker.toFirRegularClass(): FirRegularClass? { + if (this !is ConeClassLikeSymbol) return null + return this.firSafeNullable() + } + + override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean { + val firRegularClass = toFirRegularClass() ?: return false + + return firRegularClass.modality == Modality.FINAL || + firRegularClass.classKind == ClassKind.ENUM_ENTRY || + firRegularClass.classKind == ClassKind.ANNOTATION_CLASS + } + + override fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean { + // TODO support annotations + return false + } + + override fun KotlinTypeMarker.getAnnotationFirstArgumentValue(fqName: FqName): Any? { + // TODO support annotations + return null + } + + override fun TypeConstructorMarker.getTypeParameterClassifier(): TypeParameterMarker? { + return this as? FirTypeParameterSymbol + } + + override fun TypeConstructorMarker.isInlineClass(): Boolean { + return toFirRegularClass()?.isInline == true + } + + override fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker { + require(this is ConeTypeParameterSymbol) + return this.firSafeNullable()?.bounds?.getOrNull(0)?.let { (it as? FirResolvedTypeRef)?.type } + ?: ConeClassTypeImpl( + ConeClassLikeLookupTagImpl(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.any.toSafe())), emptyArray(), true + ) + } + + override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? { + // TODO: support inline classes + return null + } + + override fun TypeConstructorMarker.getPrimitiveType() = + getClassFqNameUnsafe()?.let(KotlinBuiltIns.FQ_NAMES.fqNameToPrimitiveType::get) + + override fun TypeConstructorMarker.getPrimitiveArrayType() = + getClassFqNameUnsafe()?.let(KotlinBuiltIns.FQ_NAMES.arrayClassFqNameToPrimitiveType::get) + + override fun TypeConstructorMarker.isUnderKotlinPackage() = + getClassFqNameUnsafe()?.startsWith(Name.identifier("kotlin")) == true + + override fun TypeConstructorMarker.getClassFqNameUnsafe(): FqNameUnsafe? { + return toFirRegularClass()?.symbol?.toLookupTag()?.classId?.asSingleFqName()?.toUnsafe() + } + + override fun TypeParameterMarker.getName() = (this as ConeTypeParameterSymbol).name + + override fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean { + val classKind = typeConstructor().toFirRegularClass()?.classKind ?: return false + return classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.INTERFACE + } + override fun TypeConstructorMarker.isError(): Boolean { return this is ErrorTypeConstructor } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt new file mode 100644 index 00000000000..0f5420d0296 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt @@ -0,0 +1,30 @@ +// FILE: K1.kt +class K2: J1() { + fun bar() { + foo() + baz() + + superClass() + superI() + } +} + +// FILE: J1.java +public class J1 extends KFirst { + void baz() {} +} + +// FILE: K2.kt +open class KFirst : SuperClass(), SuperI { + fun foo() { + } +} + +// FILE: K3.kt +abstract class SuperClass { + fun superClass() {} +} + +interface SuperI { + fun superI() {} +} diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.txt new file mode 100644 index 00000000000..415260790a1 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.txt @@ -0,0 +1,39 @@ +FILE: K1.kt + public final class K2 : R|J1| { + public constructor(): R|K2| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + this@R|/KFirst|.R|/KFirst.foo|() + this@R|/J1|.R|/J1.baz|() + this@R|/SuperClass|.R|/SuperClass.superClass|() + this@R|/SuperI|.R|/SuperI.superI|() + } + + } +FILE: K2.kt + public open class KFirst : R|SuperClass|, R|SuperI| { + public constructor(): R|KFirst| { + super() + } + + public final fun foo(): R|kotlin/Unit| { + } + + } +FILE: K3.kt + public abstract class SuperClass : R|kotlin/Any| { + public constructor(): R|SuperClass| { + super() + } + + public final fun superClass(): R|kotlin/Unit| { + } + + } + public abstract interface SuperI : R|kotlin/Any| { + public open fun superI(): R|kotlin/Unit| { + } + + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt new file mode 100644 index 00000000000..d397bbfd6e7 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt @@ -0,0 +1,37 @@ +// FILE: K1.kt +class KSub : J1() + +fun main(k: KSub, vString: SuperClass.NestedInSuperClass, vInt: SuperClass.NestedInSuperClass) { + k.getImpl().nestedI(vString) + + // TODO: Support parametrisized inner classes + k.getImpl().nestedI(vInt) + k.getNestedSubClass().nested("") + k.getNestedSubClass().nested(1) +} + +// FILE: J1.java +public class J1 extends KFirst { + + public class NestedSubClass extends NestedInSuperClass {} + public abstract class NestedIImpl implements NestedInI {} + + public NestedIImpl getImpl() { return null; } + public NestedSubClass getNestedSubClass() { return null; } +} + +// FILE: K2.kt +open class KFirst : SuperClass(), SuperI + +// FILE: K3.kt +abstract class SuperClass { + inner open class NestedInSuperClass { + fun nested(x: T) {} + } +} + +interface SuperI { + interface NestedInI { + fun nestedI(f: F) {} + } +} diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.txt new file mode 100644 index 00000000000..9357a5a572d --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.txt @@ -0,0 +1,45 @@ +FILE: K1.kt + public final class KSub : R|J1| { + public constructor(): R|KSub| { + super() + } + + } + public final fun main(k: R|KSub|, vString: R|SuperClass.NestedInSuperClass|, vInt: R|SuperClass.NestedInSuperClass|): R|kotlin/Unit| { + R|/k|.R|/J1.getImpl|().R|FakeOverride|(R|/vString|) + R|/k|.R|/J1.getImpl|().R|FakeOverride|(R|/vInt|) + R|/k|.R|/J1.getNestedSubClass|().#(String()) + R|/k|.R|/J1.getNestedSubClass|().#(Int(1)) + } +FILE: K2.kt + public open class KFirst : R|SuperClass|, R|SuperI| { + public constructor(): R|KFirst| { + super|>() + } + + } +FILE: K3.kt + public abstract class SuperClass : R|kotlin/Any| { + public constructor(): R|SuperClass| { + super() + } + + public open inner class NestedInSuperClass : R|kotlin/Any| { + public constructor(): R|SuperClass.NestedInSuperClass| { + super() + } + + public final fun nested(x: R|T|): R|kotlin/Unit| { + } + + } + + } + public abstract interface SuperI : R|kotlin/Any| { + public abstract interface NestedInI : R|kotlin/Any| { + public open fun nestedI(f: R|F|): R|kotlin/Unit| { + } + + } + + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.kt new file mode 100644 index 00000000000..dc8ab1f5d86 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.kt @@ -0,0 +1,18 @@ +// FILE: K1.kt +open class KFirst() { + fun foo() { + } +} + +// FILE: J1.java +public class J1 extends KFirst { + void baz() {} +} + +// FILE: K2.kt +class K2: J1() { + fun bar() { + foo() + baz() + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.txt new file mode 100644 index 00000000000..e29f1eeba3f --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.txt @@ -0,0 +1,22 @@ +FILE: K1.kt + public open class KFirst : R|kotlin/Any| { + public constructor(): R|KFirst| { + super() + } + + public final fun foo(): R|kotlin/Unit| { + } + + } +FILE: K2.kt + public final class K2 : R|J1| { + public constructor(): R|K2| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + this@R|/KFirst|.R|/KFirst.foo|() + this@R|/J1|.R|/J1.baz|() + } + + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.kt new file mode 100644 index 00000000000..2c184f5e70d --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.kt @@ -0,0 +1,17 @@ +// FILE: K1.kt +open class KFirst() { + fun foo(t: T): T = t +} + +// FILE: J1.java +public class J1 extends KFirst { + void baz() {} +} + +// FILE: K2.kt +class K2: J1() { + fun bar() { + foo(1) + baz() + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.txt new file mode 100644 index 00000000000..6a5328ff634 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.txt @@ -0,0 +1,23 @@ +FILE: K1.kt + public open class KFirst : R|kotlin/Any| { + public constructor(): R|KFirst| { + super() + } + + public final fun foo(t: R|T|): R|T| { + ^foo R|/t| + } + + } +FILE: K2.kt + public final class K2 : R|J1| { + public constructor(): R|K2| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + this@R|/KFirst|.R|FakeOverride|(Int(1)) + this@R|/J1|.R|/J1.baz|() + } + + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.kt new file mode 100644 index 00000000000..dc876022ff2 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.kt @@ -0,0 +1,13 @@ +// FILE: K1.kt +class KotlinClass + +// FILE: JavaClass.java +public class JavaClass { + public static void baz(KotlinClass k) {} +} + +// FILE: K2.kt +fun main() { + JavaClass.baz(KotlinClass()) + JavaClass.baz("") +} diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.txt new file mode 100644 index 00000000000..f021cfdd380 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.txt @@ -0,0 +1,12 @@ +FILE: K1.kt + public final class KotlinClass : R|kotlin/Any| { + public constructor(): R|KotlinClass| { + super() + } + + } +FILE: K2.kt + public final fun main(): R|kotlin/Unit| { + Q|JavaClass|.R|/JavaClass.baz|(R|/KotlinClass.KotlinClass|()) + Q|JavaClass|.#(String()) + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.kt b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.kt new file mode 100644 index 00000000000..e4bc5663386 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.kt @@ -0,0 +1,15 @@ +// FILE: K1.kt +class KotlinClass + +// FILE: JavaClass.java +public class JavaClass { + public static void baz(KotlinClass k) {} +} + +// FILE: K2.kt +fun main() { + JavaClass.baz(KotlinClass()) + JavaClass.baz(KotlinClass()) + JavaClass.baz(KotlinClass()) + JavaClass.baz("") +} diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.txt b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.txt new file mode 100644 index 00000000000..514df44bbf3 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.txt @@ -0,0 +1,14 @@ +FILE: K1.kt + public final class KotlinClass : R|kotlin/Any| { + public constructor(): R|KotlinClass| { + super() + } + + } +FILE: K2.kt + public final fun main(): R|kotlin/Unit| { + Q|JavaClass|.R|/JavaClass.baz|(R|/KotlinClass.KotlinClass|!|>()) + Q|JavaClass|.R|/JavaClass.baz|(R|/KotlinClass.KotlinClass|()) + Q|JavaClass|.#(R|/KotlinClass.KotlinClass|()) + Q|JavaClass|.#(String()) + } diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt b/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt new file mode 100644 index 00000000000..d3da2e63c48 --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt @@ -0,0 +1,34 @@ +// FILE: K1.kt +open class KotlinOuter { + inner open class KotlinInner { + fun foo() {} + } + + fun bar() {} +} + +// FILE: J1.java +public class J1 extends KotlinOuter { + public class J2 extends KotlinInner { + public void bazbaz() {} + } + + public void baz() {} +} + +// FILE: K2.kt +class K2: J1() { + fun main() { + bar() + baz() + } + + inner class K3 : J2() { + fun main() { + foo() + bazbaz() + bar() + baz() + } + } +} diff --git a/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.txt b/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.txt new file mode 100644 index 00000000000..18d4979c34f --- /dev/null +++ b/compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.txt @@ -0,0 +1,46 @@ +FILE: K1.kt + public open class KotlinOuter : R|kotlin/Any| { + public constructor(): R|KotlinOuter| { + super() + } + + public open inner class KotlinInner : R|kotlin/Any| { + public constructor(): R|KotlinOuter.KotlinInner| { + super() + } + + public final fun foo(): R|kotlin/Unit| { + } + + } + + public final fun bar(): R|kotlin/Unit| { + } + + } +FILE: K2.kt + public final class K2 : R|J1| { + public constructor(): R|K2| { + super() + } + + public final fun main(): R|kotlin/Unit| { + this@R|/KotlinOuter|.R|/KotlinOuter.bar|() + this@R|/J1|.R|/J1.baz|() + } + + public final inner class K3 : R|J1.J2| { + public constructor(): R|K2.K3| { + super() + } + + public final fun main(): R|kotlin/Unit| { + this@R|/KotlinOuter.KotlinInner|.R|/KotlinOuter.KotlinInner.foo|() + this@R|/J1.J2|.R|/J1.J2.bazbaz|() + this@R|/KotlinOuter|.R|/KotlinOuter.bar|() + this@R|/J1|.R|/J1.baz|() + } + + } + + } diff --git a/compiler/fir/resolve/testData/lightClasses/genericClasses.kt b/compiler/fir/resolve/testData/lightClasses/genericClasses.kt new file mode 100644 index 00000000000..85bcc4b84aa --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/genericClasses.kt @@ -0,0 +1,5 @@ +interface A + +class B : A + +// LIGHT_CLASS_FQ_NAME: A, B diff --git a/compiler/fir/resolve/testData/lightClasses/genericClasses.txt b/compiler/fir/resolve/testData/lightClasses/genericClasses.txt new file mode 100644 index 00000000000..0d116f529d8 --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/genericClasses.txt @@ -0,0 +1,4 @@ +public interface A extends java.lang.Object { +} +public final class B implements A { +} diff --git a/compiler/fir/resolve/testData/lightClasses/nestedClasses.kt b/compiler/fir/resolve/testData/lightClasses/nestedClasses.kt new file mode 100644 index 00000000000..70c5d028a1f --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/nestedClasses.kt @@ -0,0 +1,8 @@ +interface A + +class B { + inner class C : A + class D : A +} + +// LIGHT_CLASS_FQ_NAME: B diff --git a/compiler/fir/resolve/testData/lightClasses/nestedClasses.txt b/compiler/fir/resolve/testData/lightClasses/nestedClasses.txt new file mode 100644 index 00000000000..e5755ce94a2 --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/nestedClasses.txt @@ -0,0 +1,7 @@ +public final class B extends java.lang.Object { + public final class C implements A { + } + + public static final class D implements A { + } +} diff --git a/compiler/fir/resolve/testData/lightClasses/simple.kt b/compiler/fir/resolve/testData/lightClasses/simple.kt new file mode 100644 index 00000000000..8ff4d323994 --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/simple.kt @@ -0,0 +1,11 @@ +// FILE: a.kt +package a +interface A + +// FILE: b.kt +package b +interface B : a.A + +class C : B + +// LIGHT_CLASS_FQ_NAME: b.B, b.C diff --git a/compiler/fir/resolve/testData/lightClasses/simple.txt b/compiler/fir/resolve/testData/lightClasses/simple.txt new file mode 100644 index 00000000000..93fca0ca961 --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/simple.txt @@ -0,0 +1,5 @@ + +public interface B extends a.A { +} +public final class C implements b.B { +} diff --git a/compiler/fir/resolve/testData/lightClasses/typeMapping.kt b/compiler/fir/resolve/testData/lightClasses/typeMapping.kt new file mode 100644 index 00000000000..56822a7c61d --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/typeMapping.kt @@ -0,0 +1,16 @@ +interface A +interface Pair +interface Triple + +class B1 : A +class B2 : A> +class B3 : A> +class B4 : A> +class B5 : A>> +class B6 : A +class B7 : A +class B8 : A> +class B9 : A> +class B10 : A> + +// LIGHT_CLASS_FQ_NAME: B1, B2, B3, B4, B5, B6, B7, B8, B9, B10 diff --git a/compiler/fir/resolve/testData/lightClasses/typeMapping.txt b/compiler/fir/resolve/testData/lightClasses/typeMapping.txt new file mode 100644 index 00000000000..a36b05758fb --- /dev/null +++ b/compiler/fir/resolve/testData/lightClasses/typeMapping.txt @@ -0,0 +1,20 @@ +public final class B1 implements A { +} +public final class B2 implements A> { +} +public final class B3 implements A> { +} +public final class B4 implements A> { +} +public final class B5 implements A>> { +} +public final class B6 implements A { +} +public final class B7 implements A { +} +public final class B8 implements A { +} +public final class B9 implements A { +} +public final class B10 implements A { +} diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsSmokeTest.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsSmokeTest.kt index adda35d6cea..04292006af7 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsSmokeTest.kt +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsSmokeTest.kt @@ -22,11 +22,8 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.platform.js.JsPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms -import org.jetbrains.kotlin.platform.konan.KonanPlatforms import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import java.io.File @@ -35,7 +32,7 @@ import java.util.* abstract class AbstractFirDiagnosticsSmokeTest : BaseDiagnosticsTest() { override fun analyzeAndCheck(testDataFile: File, files: List) { try { - analyzeAndCheckUnhandled(files) + analyzeAndCheckUnhandled(testDataFile, files) } catch (t: AssertionError) { throw t } catch (t: Throwable) { @@ -52,7 +49,7 @@ abstract class AbstractFirDiagnosticsSmokeTest : BaseDiagnosticsTest() { } } - private fun analyzeAndCheckUnhandled(files: List) { + protected open fun analyzeAndCheckUnhandled(testDataFile: File, files: List) { val groupedByModule = files.groupBy(TestFile::module) val modules = createModules(groupedByModule) @@ -93,6 +90,14 @@ abstract class AbstractFirDiagnosticsSmokeTest : BaseDiagnosticsTest() { doFirResolveTestBench(firFiles, FirTotalResolveTransformer().transformers, gc = false) + checkResultingFirFiles(firFiles, testDataFile) + } + + protected open fun checkResultingFirFiles( + firFiles: MutableList, + testDataFile: File + ) { + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsTest.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsTest.kt new file mode 100644 index 00000000000..ed51a9ae177 --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirDiagnosticsTest.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2019 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.fir + +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractFirDiagnosticsTest : AbstractFirDiagnosticsSmokeTest() { + + override fun checkResultingFirFiles( + firFiles: MutableList, + testDataFile: File + ) { + val firFileDump = StringBuilder().also { stringBuilder -> + firFiles.map { + it.accept(FirRenderer(stringBuilder), null) + } + }.toString() + val expectedPath = testDataFile.path.replace(".kt", ".txt") + KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump) + } +} diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java new file mode 100644 index 00000000000..df9537d62bb --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2019 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.fir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/fir/resolve/testData/diagnostics") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInDiagnostics() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/fir/resolve/testData/diagnostics/j+k") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class J_k extends AbstractFirDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInJ_k() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/j+k"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("KJKComplexHierarchy.kt") + public void testKJKComplexHierarchy() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt"); + } + + @TestMetadata("KJKComplexHierarchyWithNested.kt") + public void testKJKComplexHierarchyWithNested() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt"); + } + + @TestMetadata("KJKInheritance.kt") + public void testKJKInheritance() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritance.kt"); + } + + @TestMetadata("KJKInheritanceGeneric.kt") + public void testKJKInheritanceGeneric() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKInheritanceGeneric.kt"); + } + + @TestMetadata("KotlinClassParameter.kt") + public void testKotlinClassParameter() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameter.kt"); + } + + @TestMetadata("KotlinClassParameterGeneric.kt") + public void testKotlinClassParameterGeneric() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/KotlinClassParameterGeneric.kt"); + } + + @TestMetadata("outerInnerClasses.kt") + public void testOuterInnerClasses() throws Exception { + runTest("compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt"); + } + } +} diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/AbstractFirLightClassesTest.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/AbstractFirLightClassesTest.kt new file mode 100644 index 00000000000..6b566acc95a --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/AbstractFirLightClassesTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2019 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.fir.java + +import com.intellij.openapi.extensions.Extensions +import com.intellij.psi.PsiElementFinder +import com.intellij.psi.impl.compiled.ClsClassImpl +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.fir.AbstractFirDiagnosticsSmokeTest +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractFirLightClassesTest : AbstractFirDiagnosticsSmokeTest() { + override fun checkResultingFirFiles(firFiles: MutableList, testDataFile: File) { + super.checkResultingFirFiles(firFiles, testDataFile) + + val ourFinders = + Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).extensions.filterIsInstance() + + assertNotEmpty(ourFinders) + + val stringBuilder = StringBuilder() + + for (qualifiedName in InTextDirectivesUtils.findListWithPrefixes(testDataFile.readText(), "// LIGHT_CLASS_FQ_NAME: ")) { + val fqName = FqName(qualifiedName) + val packageName = fqName.parent().asString() + + val ourFinder = ourFinders.firstOrNull { finder -> finder.findPackage(packageName) != null } + assertNotNull("PsiPackage for ${fqName.parent()} was not found", ourFinder) + ourFinder!! + + val psiPackage = ourFinder.findPackage(fqName.parent().asString()) + assertNotNull("PsiPackage for ${fqName.parent()} is null", psiPackage) + + val psiClass = assertInstanceOf( + ourFinder.findClass(qualifiedName, GlobalSearchScope.allScope(project)), + ClsClassImpl::class.java + ) + + psiClass.appendMirrorText(0, stringBuilder) + stringBuilder.appendln() + } + + val expectedPath = testDataFile.path.replace(".kt", ".txt") + KotlinTestUtils.assertEqualsToFile(File(expectedPath), stringBuilder.toString()) + } +} diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/FirLightClassesTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/FirLightClassesTestGenerated.java new file mode 100644 index 00000000000..980d9d15ff3 --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/java/FirLightClassesTestGenerated.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2019 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.fir.java; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/fir/resolve/testData/lightClasses") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class FirLightClassesTestGenerated extends AbstractFirLightClassesTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInLightClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/lightClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("genericClasses.kt") + public void testGenericClasses() throws Exception { + runTest("compiler/fir/resolve/testData/lightClasses/genericClasses.kt"); + } + + @TestMetadata("nestedClasses.kt") + public void testNestedClasses() throws Exception { + runTest("compiler/fir/resolve/testData/lightClasses/nestedClasses.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/fir/resolve/testData/lightClasses/simple.kt"); + } + + @TestMetadata("typeMapping.kt") + public void testTypeMapping() throws Exception { + runTest("compiler/fir/resolve/testData/lightClasses/typeMapping.kt"); + } +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirRegularClass.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirRegularClass.kt index c6b490ab458..c94ec0690f0 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirRegularClass.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirRegularClass.kt @@ -36,6 +36,8 @@ interface FirRegularClass : FirClass, @VisitedSupertype FirClassLikeDeclaration< } fun replaceSupertypes(newSupertypes: List): FirRegularClass + + fun setCallbackOnSupertypesComputed(callback: () -> Unit) } val FirRegularClass.classId get() = symbol.classId diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirClassImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirClassImpl.kt index 6162bb9d75a..9a0be985e19 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirClassImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirClassImpl.kt @@ -63,6 +63,8 @@ open class FirClassImpl( override fun replaceSupertypes(newSupertypes: List): FirRegularClass { superTypeRefs.clear() superTypeRefs.addAll(newSupertypes) + callbackOnSupertypesComputed?.invoke() + callbackOnSupertypesComputed = null return this } @@ -76,4 +78,10 @@ open class FirClassImpl( companionObject = declarations.asSequence().filterIsInstance().firstOrNull { it.isCompanion } return result } + + private var callbackOnSupertypesComputed: (() -> Unit)? = null + + override fun setCallbackOnSupertypesComputed(callback: () -> Unit) { + callbackOnSupertypesComputed = callback + } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirEnumEntryImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirEnumEntryImpl.kt index 27a6a541de8..6df62866a42 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirEnumEntryImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirEnumEntryImpl.kt @@ -54,9 +54,17 @@ class FirEnumEntryImpl( override fun replaceSupertypes(newSupertypes: List): FirRegularClass { superTypeRefs.clear() superTypeRefs.addAll(newSupertypes) + callbackOnSupertypesComputed?.invoke() + callbackOnSupertypesComputed = null return this } + private var callbackOnSupertypesComputed: (() -> Unit)? = null + + override fun setCallbackOnSupertypesComputed(callback: () -> Unit) { + callbackOnSupertypesComputed = callback + } + override fun replaceTypeRef(newTypeRef: FirTypeRef) { typeRef = newTypeRef } @@ -85,4 +93,4 @@ class FirEnumEntryImpl( return this } -} \ No newline at end of file +} diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index c362efcb463..65ac0eece67 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest import org.jetbrains.kotlin.codegen.ir.* import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase +import org.jetbrains.kotlin.fir.java.AbstractFirLightClassesTest import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest import org.jetbrains.kotlin.fir.java.AbstractOwnFirTypeEnhancementTest import org.jetbrains.kotlin.generators.tests.generator.testGroup @@ -487,6 +488,19 @@ fun main(args: Array) { } } + testGroup("compiler/fir/resolve/tests", "compiler/fir/resolve/testData") { + + testClass { + model("diagnostics") + } + } + + testGroup("compiler/fir/resolve/tests", "compiler/fir/resolve/testData") { + testClass { + model("lightClasses") + } + } + testGroup("compiler/fir/fir2ir/tests", "compiler/testData") { testClass { model("ir/irText")