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
@@ -58,6 +58,7 @@ fun FirSession.registerResolveComponents() {
@OptIn(SessionConfiguration::class)
fun FirSession.registerJavaSpecificResolveComponents() {
register(FirVisibilityChecker::class, FirJavaVisibilityChecker)
register(FirModuleVisibilityChecker::class, FirJvmModuleVisibilityChecker(this))
register(ConeCallConflictResolverFactory::class, JvmCallConflictResolverFactory)
register(FirEffectiveVisibilityResolver::class, FirJvmEffectiveVisibilityResolver(this))
register(FirPlatformClassMapper::class, FirJavaClassMapper(this))
@@ -6,23 +6,30 @@
package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
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 {
val LIBRARIES_MODULE_NAME = Name.special("<dependencies>")
fun createForLibraries(mainModuleName: String? = null): FirJvmModuleInfo {
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
get() = JvmPlatforms.unspecifiedJvmPlatform
@@ -30,7 +37,6 @@ class FirJvmModuleInfo(override val name: Name, val dependencies: List<ModuleInf
override val analyzerServices: PlatformDependentAnalyzerServices
get() = JvmPlatformAnalyzerServices
override fun dependencies(): List<ModuleInfo> {
return dependencies
}
override fun dependencies(): List<ModuleInfo> =
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 +=
c.annotationDeserializer.loadConstructorAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
containerSource = c.containerSource
}.build().apply {
containingClassAttr = c.dispatchReceiver!!.lookupTag
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.FqName
interface FirModuleVisibilityChecker : FirSessionComponent {
fun isInFriendModule(declaration: FirMemberDeclaration): Boolean
}
abstract class FirVisibilityChecker : FirSessionComponent {
@NoMutableState
object Default : FirVisibilityChecker() {
@@ -54,14 +58,13 @@ abstract class FirVisibilityChecker : FirSessionComponent {
val session = callInfo.session
val provider = session.firProvider
return when (declaration.visibility) {
Visibilities.Internal -> {
declaration.session == callInfo.session
declaration.session == session || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
}
Visibilities.Private, Visibilities.PrivateToThis -> {
val ownerId = symbol.getOwnerId()
if (declaration.session == callInfo.session) {
if (declaration.session == session) {
if (ownerId == null || declaration is FirConstructor && declaration.isFromSealedClass) {
val candidateFile = when (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()
fun AbstractFirBasedSymbol<*>.getOwnerId(): ClassId? {
@@ -132,6 +132,13 @@ fun FirRegularClass.addDeclaration(declaration: FirDeclaration) {
private object SourceElementKey : FirDeclarationDataKey()
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()
var FirProperty.isFromVararg: Boolean? by FirDeclarationDataRegistry.data(IsFromVarargKey)
private object IsReferredViaField : FirDeclarationDataKey()