aboutsummaryrefslogtreecommitdiff
path: root/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis')
-rw-r--r--kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt192
1 files changed, 161 insertions, 31 deletions
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt
index c39621f9..c8b324a0 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt
+++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt
@@ -3,8 +3,10 @@ package org.jetbrains.dokka.analysis
import com.google.common.collect.ImmutableMap
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreModuleManager
+import com.intellij.mock.MockApplication
import com.intellij.mock.MockComponentManager
import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
+import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.caches.resolve.*
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.ContentRoot
@@ -41,21 +44,34 @@ import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
import org.jetbrains.kotlin.config.*
+import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.container.tryGetService
+import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.context.withModule
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
+import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
+import org.jetbrains.kotlin.frontend.di.createContainerForLazyResolve
+import org.jetbrains.kotlin.ide.konan.NativeKlibLibraryInfo
import org.jetbrains.kotlin.ide.konan.NativePlatformKindResolution
import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
+import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache
+import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
+import org.jetbrains.kotlin.idea.klib.getCompatibilityInfo
+import org.jetbrains.kotlin.idea.klib.safeRead
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
-import org.jetbrains.kotlin.library.impl.createKotlinLibrary
+import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
+import org.jetbrains.kotlin.library.*
+import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.name.Name
@@ -71,10 +87,7 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.unspecifiedJvmPlatform
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.BindingTrace
-import org.jetbrains.kotlin.resolve.CompilerEnvironment
-import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
+import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
@@ -82,13 +95,14 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService.Companion.createDeclarationProviderFactory
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import java.io.File
+import org.jetbrains.kotlin.konan.file.File as KFile
const val JAR_SEPARATOR = "!/"
-const val KLIB_EXTENSION = "klib"
/**
* Kotlin as a service entry point
@@ -146,6 +160,13 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
CustomJavadocTagProvider.EP_NAME, CustomJavadocTagProvider::class.java
)
+ // TODO: figure out why compilation fails with unresolved `CoreApplicationEnvironment.registerApplicationService(...)`
+ // call, fix it appropriately
+ with (ApplicationManager.getApplication() as MockApplication) {
+ if (getService(KlibLoadingMetadataCache::class.java) == null)
+ registerService(KlibLoadingMetadataCache::class.java, KlibLoadingMetadataCache())
+ }
+
projectComponentManager.registerService(
ProjectFileIndex::class.java,
projectFileIndex
@@ -202,7 +223,6 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
val projectContext = ProjectContext(environment.project, "Dokka")
val sourceFiles = environment.getSourceFiles()
-
val targetPlatform = when (analysisPlatform) {
Platform.js -> JsPlatforms.defaultJsPlatform
Platform.common -> CommonPlatforms.defaultCommonPlatform
@@ -210,8 +230,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
Platform.jvm -> JvmPlatforms.defaultJvmPlatform
}
- val nativeLibraries = classpath.filter { it.extension == KLIB_EXTENSION }
- .map { createNativeLibraryModuleInfo(it) }
+ val nativeLibraries: Map</* absolute path */String, LibraryModuleInfo> = loadNativeLibraries()
val library = object : LibraryModuleInfo {
override val analyzerServices: PlatformDependentAnalyzerServices =
@@ -219,8 +238,9 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
override val name: Name = Name.special("<library>")
override val platform: TargetPlatform = targetPlatform
override fun dependencies(): List<ModuleInfo> = listOf(this)
- override fun getLibraryRoots(): Collection<String> =
- classpath.filterNot { it.extension == KLIB_EXTENSION }.map { it.absolutePath }
+ override fun getLibraryRoots(): Collection<String> = classpath.mapNotNull { libraryFile ->
+ libraryFile.absolutePath.takeIf { it !in nativeLibraries }
+ }
}
val module = object : ModuleInfo {
@@ -228,7 +248,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
analysisPlatform.analyzerServices()
override val name: Name = Name.special("<module>")
override val platform: TargetPlatform = targetPlatform
- override fun dependencies(): List<ModuleInfo> = listOf(this, library) + nativeLibraries
+ override fun dependencies(): List<ModuleInfo> = listOf(this, library) + nativeLibraries.values
}
val sourcesScope = createSourceModuleSearchScope(environment.project, sourceFiles)
@@ -236,9 +256,13 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
when (it) {
library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
module -> ModuleContent(it, emptyList(), GlobalSearchScope.allScope(environment.project))
- in nativeLibraries -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
- else -> throw IllegalArgumentException("Unexpected module info")
- }
+ is DokkaNativeKlibLibraryInfo -> {
+ if (it.libraryRoot in nativeLibraries)
+ ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
+ else null
+ }
+ else -> null
+ } ?: throw IllegalArgumentException("Unexpected module info")
}
var builtIns: JvmBuiltIns? = null
@@ -303,18 +327,29 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
Platform.jvm -> JvmPlatformAnalyzerServices
}
- private fun createNativeLibraryModuleInfo(libraryFile: File): LibraryModuleInfo {
- val kotlinLibrary = createKotlinLibrary(org.jetbrains.kotlin.konan.file.File(libraryFile.absolutePath), "",false)
- return object : LibraryModuleInfo {
- override val analyzerServices: PlatformDependentAnalyzerServices =
- analysisPlatform.analyzerServices()
- override val name: Name = Name.special("<klib>")
- override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform
- override fun dependencies(): List<ModuleInfo> = listOf(this)
- override fun getLibraryRoots(): Collection<String> = listOf(libraryFile.absolutePath)
- override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
- get() = super.capabilities + (KlibModuleOrigin.CAPABILITY to kotlinLibrary)
+ private fun loadNativeLibraries(): Map<String, LibraryModuleInfo> {
+ if (analysisPlatform != Platform.native) return emptyMap()
+
+ val dependencyResolver = DokkaNativeKlibLibraryDependencyResolver()
+ val analyzerServices = analysisPlatform.analyzerServices()
+
+ val result = mutableMapOf<String, LibraryModuleInfo>()
+
+ classpath.forEach { libraryFile ->
+ val libraryRoot = libraryFile.absolutePath
+
+ val kotlinLibrary: KotlinLibrary = resolveSingleFileKlib(
+ libraryFile = KFile(libraryRoot),
+ strategy = ToolingSingleFileKlibResolveStrategy
+ )
+
+ if (kotlinLibrary.getCompatibilityInfo().isCompatible) {
+ // exists, is KLIB, has compatible format
+ result[libraryRoot] = DokkaNativeKlibLibraryInfo(kotlinLibrary, analyzerServices, dependencyResolver)
+ }
}
+
+ return result
}
private fun createCommonResolverForProject(
@@ -404,11 +439,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
moduleInfo: ModuleInfo
): ResolverForModule {
- return NativeResolverForModuleFactory(
- PlatformAnalysisParameters.Empty,
- CompilerEnvironment,
- NativePlatforms.unspecifiedNativePlatform
- ).createResolverForModule(
+ return DokkaNativeResolverForModuleFactory(CompilerEnvironment).createResolverForModule(
descriptor as ModuleDescriptorImpl,
projectContext.withModule(descriptor),
modulesContent(moduleInfo),
@@ -569,6 +600,105 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
}
}
+/** TODO: replace by [NativeKlibLibraryInfo] after fix of KT-40734 */
+internal class DokkaNativeKlibLibraryDependencyResolver {
+ private val cachedDependencies = mutableMapOf</* libraryName */String, DokkaNativeKlibLibraryInfo>()
+
+ fun registerLibrary(libraryInfo: DokkaNativeKlibLibraryInfo) {
+ cachedDependencies[libraryInfo.kotlinLibrary.uniqueName] = libraryInfo
+ }
+
+ fun resolveDependencies(libraryInfo: DokkaNativeKlibLibraryInfo): List<DokkaNativeKlibLibraryInfo> {
+ return libraryInfo.kotlinLibrary.unresolvedDependencies.mapNotNull { cachedDependencies[it.path] }
+ }
+}
+
+/** TODO: replace by [NativeKlibLibraryInfo] after fix of KT-40734 */
+internal class DokkaNativeKlibLibraryInfo(
+ val kotlinLibrary: KotlinLibrary,
+ override val analyzerServices: PlatformDependentAnalyzerServices,
+ private val dependencyResolver: DokkaNativeKlibLibraryDependencyResolver
+) : LibraryModuleInfo {
+ init {
+ dependencyResolver.registerLibrary(this)
+ }
+
+ internal val libraryRoot: String
+ get() = kotlinLibrary.libraryFile.path
+
+ override val name: Name by lazy {
+ val libraryName = kotlinLibrary.shortName ?: kotlinLibrary.uniqueName
+ Name.special("<$libraryName>")
+ }
+
+ override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform
+ override fun dependencies(): List<ModuleInfo> = listOf(this) + dependencyResolver.resolveDependencies(this)
+ override fun getLibraryRoots(): Collection<String> = listOf(libraryRoot)
+
+ override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
+ get() {
+ val capabilities = super.capabilities.toMutableMap()
+ capabilities += KlibModuleOrigin.CAPABILITY to DeserializedKlibModuleOrigin(kotlinLibrary)
+ capabilities += ImplicitIntegerCoercion.MODULE_CAPABILITY to kotlinLibrary.safeRead(false) { isInterop }
+ return capabilities
+ }
+}
+
+/** TODO: replace by [NativeResolverForModuleFactory] after fix of KT-40734 */
+internal class DokkaNativeResolverForModuleFactory(
+ private val targetEnvironment: TargetEnvironment
+) : ResolverForModuleFactory() {
+ companion object {
+ private val metadataFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer)
+ }
+
+ override fun <M : ModuleInfo> createResolverForModule(
+ moduleDescriptor: ModuleDescriptorImpl,
+ moduleContext: ModuleContext,
+ moduleContent: ModuleContent<M>,
+ resolverForProject: ResolverForProject<M>,
+ languageVersionSettings: LanguageVersionSettings
+ ): ResolverForModule {
+
+ val declarationProviderFactory = createDeclarationProviderFactory(
+ moduleContext.project,
+ moduleContext.storageManager,
+ moduleContent.syntheticFiles,
+ moduleContent.moduleContentScope,
+ moduleContent.moduleInfo
+ )
+
+ val container = createContainerForLazyResolve(
+ moduleContext,
+ declarationProviderFactory,
+ CodeAnalyzerInitializer.getInstance(moduleContext.project).createTrace(),
+ moduleDescriptor.platform!!,
+ NativePlatformAnalyzerServices,
+ targetEnvironment,
+ languageVersionSettings
+ )
+
+ var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
+
+ val klibPackageFragmentProvider = (moduleContent.moduleInfo as? DokkaNativeKlibLibraryInfo)
+ ?.kotlinLibrary
+ ?.createKlibPackageFragmentProvider(
+ storageManager = moduleContext.storageManager,
+ metadataModuleDescriptorFactory = metadataFactories.DefaultDeserializedDescriptorFactory,
+ languageVersionSettings = languageVersionSettings,
+ moduleDescriptor = moduleDescriptor,
+ lookupTracker = LookupTracker.DO_NOTHING
+ )
+
+ if (klibPackageFragmentProvider != null) {
+ packageFragmentProvider =
+ CompositePackageFragmentProvider(listOf(packageFragmentProvider, klibPackageFragmentProvider))
+ }
+
+ return ResolverForModule(packageFragmentProvider, container)
+ }
+}
+
fun contentRootFromPath(path: String): ContentRoot {
val file = File(path)
return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path, false)