FIR: implement -Xfriend-paths

This commit is contained in:
pyos
2021-01-07 14:25:24 +01:00
committed by Mikhail Glukhikh
parent bd708da82c
commit f618763250
12 changed files with 101 additions and 15 deletions
@@ -328,7 +328,7 @@ object KotlinToJVMBytecodeCompiler {
project, environment.createPackagePartProvider(librariesScope) project, environment.createPackagePartProvider(librariesScope)
) )
val moduleInfo = FirJvmModuleInfo(module.getModuleName(), listOf(librariesModuleInfo)) val moduleInfo = FirJvmModuleInfo(module, listOf(librariesModuleInfo))
val session = FirSessionFactory.createJavaModuleBasedSession(moduleInfo, provider, scope, project) { val session = FirSessionFactory.createJavaModuleBasedSession(moduleInfo, provider, scope, project) {
if (extendedAnalysisMode) { if (extendedAnalysisMode) {
registerExtendedCommonCheckers() registerExtendedCommonCheckers()
@@ -58,6 +58,7 @@ fun FirSession.registerResolveComponents() {
@OptIn(SessionConfiguration::class) @OptIn(SessionConfiguration::class)
fun FirSession.registerJavaSpecificResolveComponents() { fun FirSession.registerJavaSpecificResolveComponents() {
register(FirVisibilityChecker::class, FirJavaVisibilityChecker) register(FirVisibilityChecker::class, FirJavaVisibilityChecker)
register(FirModuleVisibilityChecker::class, FirJvmModuleVisibilityChecker(this))
register(ConeCallConflictResolverFactory::class, JvmCallConflictResolverFactory) register(ConeCallConflictResolverFactory::class, JvmCallConflictResolverFactory)
register(FirEffectiveVisibilityResolver::class, FirJvmEffectiveVisibilityResolver(this)) register(FirEffectiveVisibilityResolver::class, FirJvmEffectiveVisibilityResolver(this))
register(FirPlatformClassMapper::class, FirJavaClassMapper(this)) register(FirPlatformClassMapper::class, FirJavaClassMapper(this))
@@ -6,23 +6,30 @@
package org.jetbrains.kotlin.fir.session package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
class FirJvmModuleInfo(override val name: Name, val dependencies: List<ModuleInfo>) : ModuleInfo { class FirJvmModuleInfo(
override val name: Name,
val dependencies: List<ModuleInfo> = emptyList(),
val friendPaths: List<String> = emptyList(),
val outputDirectory: String? = null
) : ModuleInfo {
companion object { companion object {
val LIBRARIES_MODULE_NAME = Name.special("<dependencies>") val LIBRARIES_MODULE_NAME = Name.special("<dependencies>")
fun createForLibraries(mainModuleName: String? = null): FirJvmModuleInfo { fun createForLibraries(mainModuleName: String? = null): FirJvmModuleInfo {
val name = mainModuleName?.let { Name.special("<dependencies of $it>") } ?: LIBRARIES_MODULE_NAME val name = mainModuleName?.let { Name.special("<dependencies of $it>") } ?: LIBRARIES_MODULE_NAME
return FirJvmModuleInfo(name, emptyList()) return FirJvmModuleInfo(name)
} }
} }
constructor(moduleName: String, dependencies: List<ModuleInfo>) : this(Name.identifier(moduleName), dependencies) constructor(module: Module, dependencies: List<ModuleInfo>) :
this(Name.identifier(module.getModuleName()), dependencies, module.getFriendPaths(), module.getOutputDirectory())
override val platform: TargetPlatform override val platform: TargetPlatform
get() = JvmPlatforms.unspecifiedJvmPlatform get() = JvmPlatforms.unspecifiedJvmPlatform
@@ -30,7 +37,6 @@ class FirJvmModuleInfo(override val name: Name, val dependencies: List<ModuleInf
override val analyzerServices: PlatformDependentAnalyzerServices override val analyzerServices: PlatformDependentAnalyzerServices
get() = JvmPlatformAnalyzerServices get() = JvmPlatformAnalyzerServices
override fun dependencies(): List<ModuleInfo> { override fun dependencies(): List<ModuleInfo> =
return dependencies dependencies
}
} }
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.session
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore
import org.jetbrains.kotlin.fir.FirModuleVisibilityChecker
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.containerSource
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
import java.nio.file.Paths
class FirJvmModuleVisibilityChecker(private val session: FirSession) : FirModuleVisibilityChecker {
override fun isInFriendModule(declaration: FirMemberDeclaration): Boolean {
val moduleInfo = session.moduleInfo as? FirJvmModuleInfo ?: return false
val binaryClass = when (val source = declaration.containerSource) {
is KotlinJvmBinarySourceElement -> source.binaryClass
is JvmPackagePartSource -> source.knownJvmBinaryClass
else -> null
} as? VirtualFileKotlinClass ?: return false
// For incremental compilation, the already compiled part of the module should be accessible.
return moduleInfo.friendPaths.any { binaryClass.isIn(it) } || moduleInfo.outputDirectory?.let { binaryClass.isIn(it) } == true
}
private fun VirtualFileKotlinClass.isIn(jarOrDirectory: String): Boolean =
when (file.fileSystem.protocol) {
StandardFileSystems.FILE_PROTOCOL ->
VfsUtilCore.virtualToIoFile(file).toPath().startsWith(jarOrDirectory)
StandardFileSystems.JAR_PROTOCOL ->
VfsUtilCore.getVirtualFileForJar(file)?.let(VfsUtilCore::virtualToIoFile)?.toPath() == Paths.get(jarOrDirectory)
else -> false
}
}
@@ -449,6 +449,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
) )
annotations += annotations +=
c.annotationDeserializer.loadConstructorAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable) c.annotationDeserializer.loadConstructorAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
containerSource = c.containerSource
}.build().apply { }.build().apply {
containingClassAttr = c.dispatchReceiver!!.lookupTag containingClassAttr = c.dispatchReceiver!!.lookupTag
versionRequirementsTable = c.versionRequirementTable versionRequirementsTable = c.versionRequirementTable
@@ -22,6 +22,10 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
interface FirModuleVisibilityChecker : FirSessionComponent {
fun isInFriendModule(declaration: FirMemberDeclaration): Boolean
}
abstract class FirVisibilityChecker : FirSessionComponent { abstract class FirVisibilityChecker : FirSessionComponent {
@NoMutableState @NoMutableState
object Default : FirVisibilityChecker() { object Default : FirVisibilityChecker() {
@@ -54,14 +58,13 @@ abstract class FirVisibilityChecker : FirSessionComponent {
val session = callInfo.session val session = callInfo.session
val provider = session.firProvider val provider = session.firProvider
return when (declaration.visibility) { return when (declaration.visibility) {
Visibilities.Internal -> { Visibilities.Internal -> {
declaration.session == callInfo.session declaration.session == session || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
} }
Visibilities.Private, Visibilities.PrivateToThis -> { Visibilities.Private, Visibilities.PrivateToThis -> {
val ownerId = symbol.getOwnerId() val ownerId = symbol.getOwnerId()
if (declaration.session == callInfo.session) { if (declaration.session == session) {
if (ownerId == null || declaration is FirConstructor && declaration.isFromSealedClass) { if (ownerId == null || declaration is FirConstructor && declaration.isFromSealedClass) {
val candidateFile = when (symbol) { val candidateFile = when (symbol) {
is FirClassLikeSymbol<*> -> provider.getFirClassifierContainerFileIfAny(symbol) is FirClassLikeSymbol<*> -> provider.getFirClassifierContainerFileIfAny(symbol)
@@ -194,6 +197,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
} }
} }
val FirSession.moduleVisibilityChecker: FirModuleVisibilityChecker? by FirSession.nullableSessionComponentAccessor()
val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComponentAccessor() val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComponentAccessor()
fun AbstractFirBasedSymbol<*>.getOwnerId(): ClassId? { fun AbstractFirBasedSymbol<*>.getOwnerId(): ClassId? {
@@ -132,6 +132,13 @@ fun FirRegularClass.addDeclaration(declaration: FirDeclaration) {
private object SourceElementKey : FirDeclarationDataKey() private object SourceElementKey : FirDeclarationDataKey()
var FirRegularClass.sourceElement: SourceElement? by FirDeclarationDataRegistry.data(SourceElementKey) var FirRegularClass.sourceElement: SourceElement? by FirDeclarationDataRegistry.data(SourceElementKey)
val FirMemberDeclaration.containerSource: SourceElement?
get() = when (this) {
is FirCallableMemberDeclaration<*> -> containerSource
is FirRegularClass -> sourceElement
else -> null
}
private object IsFromVarargKey : FirDeclarationDataKey() private object IsFromVarargKey : FirDeclarationDataKey()
var FirProperty.isFromVararg: Boolean? by FirDeclarationDataRegistry.data(IsFromVarargKey) var FirProperty.isFromVararg: Boolean? by FirDeclarationDataRegistry.data(IsFromVarargKey)
private object IsReferredViaField : FirDeclarationDataKey() private object IsReferredViaField : FirDeclarationDataKey()
@@ -0,0 +1,15 @@
package a
internal interface InternalInterface
public class PublicClass internal constructor() {
internal fun internalMemberFun() {}
internal companion object {}
}
internal val internalVal = ""
internal fun internalFun(s: String): String = s
internal typealias InternalTypealias = InternalInterface
@@ -0,0 +1,10 @@
import a.*
private fun test(i: InternalInterface): InternalTypealias {
PublicClass().internalMemberFun()
PublicClass.Companion
internalFun(internalVal)
return i
}
@@ -27,16 +27,13 @@ class FirModuleInfoProvider(
module.dependencies.mapTo(dependencies) { module.dependencies.mapTo(dependencies) {
convertToFirModuleInfo(testServices.dependencyProvider.getTestModule(it.moduleName)) convertToFirModuleInfo(testServices.dependencyProvider.getTestModule(it.moduleName))
} }
FirJvmModuleInfo( FirJvmModuleInfo(Name.identifier(module.name), dependencies)
module.name,
dependencies
)
} }
} }
fun builtinsModuleInfoForModule(module: TestModule): FirJvmModuleInfo { fun builtinsModuleInfoForModule(module: TestModule): FirJvmModuleInfo {
return builtinsByModule.getOrPut(module) { return builtinsByModule.getOrPut(module) {
FirJvmModuleInfo(Name.special("<built-ins>"), emptyList()) FirJvmModuleInfo(Name.special("<built-ins>"))
} }
} }
} }
@@ -626,6 +626,11 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xfriend-paths=${library.path}")) compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xfriend-paths=${library.path}"))
} }
fun testInternalFromFriendModuleFir() {
val library = compileLibrary("library")
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xfriend-paths=${library.path}", "-Xuse-fir"))
}
fun testJvmDefaultClashWithOld() { fun testJvmDefaultClashWithOld() {
val library = compileLibrary("library", additionalOptions = listOf("-Xjvm-default=disable")) val library = compileLibrary("library", additionalOptions = listOf("-Xjvm-default=disable"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-jvm-target", "1.8", "-Xjvm-default=all")) compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-jvm-target", "1.8", "-Xjvm-default=all"))