aboutsummaryrefslogtreecommitdiff
path: root/dokka-subprojects/analysis-kotlin-descriptors-ide
diff options
context:
space:
mode:
Diffstat (limited to 'dokka-subprojects/analysis-kotlin-descriptors-ide')
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/README.md11
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/api/analysis-kotlin-descriptors-ide.api4
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/build.gradle.kts17
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt58
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt128
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt33
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt38
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt24
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt58
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt16
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt54
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt34
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt45
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt22
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt78
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt129
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt311
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt56
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt48
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt114
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt61
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt96
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt51
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt154
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt30
-rw-r--r--dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin5
26 files changed, 1675 insertions, 0 deletions
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/README.md b/dokka-subprojects/analysis-kotlin-descriptors-ide/README.md
new file mode 100644
index 00000000..14ed5baa
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/README.md
@@ -0,0 +1,11 @@
+# Descriptors: IDE
+
+An internal module that encapsulates external IDE (`org.jetbrains.kotlin:idea`) dependencies.
+
+IDE artifacts are reused for things that are not possible to do with the Kotlin compiler API, such
+as KDoc or KLib parsing/processing, because Dokka is very similar to an IDE when it comes to analyzing
+source code and docs.
+
+Exists primarily to make sure that unreliable and coupled external dependencies are somewhat abstracted away,
+otherwise everything gets tangled together and breaking changes in such dependencies become very
+difficult to resolve.
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/api/analysis-kotlin-descriptors-ide.api b/dokka-subprojects/analysis-kotlin-descriptors-ide/api/analysis-kotlin-descriptors-ide.api
new file mode 100644
index 00000000..a59658a3
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/api/analysis-kotlin-descriptors-ide.api
@@ -0,0 +1,4 @@
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+ public fun <init> ()V
+}
+
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/build.gradle.kts b/dokka-subprojects/analysis-kotlin-descriptors-ide/build.gradle.kts
new file mode 100644
index 00000000..76a88353
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/build.gradle.kts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("dokkabuild.kotlin-jvm")
+}
+
+dependencies {
+ compileOnly(projects.dokkaSubprojects.dokkaCore)
+ compileOnly(projects.dokkaSubprojects.analysisKotlinApi)
+
+ implementation(projects.dokkaSubprojects.analysisKotlinDescriptorsCompiler)
+
+ // TODO [beresnev] get rid of it
+ compileOnly(libs.kotlinx.coroutines.core)
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt
new file mode 100644
index 00000000..2a299009
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.analyzer.ModuleInfo
+import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
+import org.jetbrains.kotlin.caches.resolve.PlatformAnalysisSettings
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.platform.TargetPlatform
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
+
+
+internal class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService {
+ override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getResolutionFacade(element: KtElement): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getResolutionFacadeByFile(
+ file: PsiFile,
+ platform: TargetPlatform
+ ): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getResolutionFacadeByModuleInfo(
+ moduleInfo: ModuleInfo,
+ settings: PlatformAnalysisSettings
+ ): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getResolutionFacadeByModuleInfo(
+ moduleInfo: ModuleInfo,
+ platform: TargetPlatform
+ ): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getResolutionFacadeWithForcedPlatform(
+ elements: List<KtElement>,
+ platform: TargetPlatform
+ ): ResolutionFacade {
+ return resolutionFacade
+ }
+
+ override fun getSuppressionCache(): KotlinSuppressCache {
+ throw UnsupportedOperationException()
+ }
+
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt
new file mode 100644
index 00000000..1ded0495
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:OptIn(FrontendInternals::class)
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.google.common.collect.ImmutableMap
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.analyzer.AnalysisResult
+import org.jetbrains.kotlin.analyzer.ModuleInfo
+import org.jetbrains.kotlin.analyzer.ResolverForModule
+import org.jetbrains.kotlin.analyzer.ResolverForProject
+import org.jetbrains.kotlin.container.getService
+import org.jetbrains.kotlin.container.tryGetService
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.diagnostics.DiagnosticSink
+import org.jetbrains.kotlin.idea.FrontendInternals
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingTrace
+import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
+import org.jetbrains.kotlin.util.slicedMap.WritableSlice
+
+internal class DokkaResolutionFacade(
+ override val project: Project,
+ override val moduleDescriptor: ModuleDescriptor,
+ val resolverForModule: ResolverForModule
+) : ResolutionFacade {
+ override fun analyzeWithAllCompilerChecks(
+ elements: Collection<KtElement>,
+ callback: DiagnosticSink.DiagnosticsCallback?
+ ): AnalysisResult {
+ throw UnsupportedOperationException()
+ }
+
+ @OptIn(FrontendInternals::class)
+ override fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T? {
+ return resolverForModule.componentProvider.tryGetService(serviceClass)
+ }
+
+ override fun resolveToDescriptor(
+ declaration: KtDeclaration,
+ bodyResolveMode: BodyResolveMode
+ ): DeclarationDescriptor {
+ return resolveSession.resolveToDescriptor(declaration)
+ }
+
+ override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext {
+ throw UnsupportedOperationException()
+ }
+
+ val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java)
+
+ override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext {
+ if (element is KtDeclaration) {
+ val descriptor = resolveToDescriptor(element)
+ return object : BindingContext {
+ override fun <K : Any?, V : Any?> getKeys(p0: WritableSlice<K, V>?): Collection<K> {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getType(p0: KtExpression): KotlinType? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun <K : Any?, V : Any?> get(slice: ReadOnlySlice<K, V>?, key: K): V? {
+ if (key != element) {
+ throw UnsupportedOperationException()
+ }
+ @Suppress("UNCHECKED_CAST")
+ return when {
+ slice == BindingContext.DECLARATION_TO_DESCRIPTOR -> descriptor as V
+ slice == BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER && (element as KtParameter).hasValOrVar() -> descriptor as V
+ else -> null
+ }
+ }
+
+ override fun getDiagnostics(): Diagnostics {
+ throw UnsupportedOperationException()
+ }
+
+ override fun addOwnDataTo(p0: BindingTrace, p1: Boolean) {
+ throw UnsupportedOperationException()
+ }
+
+ override fun <K : Any?, V : Any?> getSliceContents(p0: ReadOnlySlice<K, V>): ImmutableMap<K, V> {
+ throw UnsupportedOperationException()
+ }
+
+ }
+ }
+ throw UnsupportedOperationException()
+ }
+
+ override fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T {
+ throw UnsupportedOperationException()
+ }
+
+ override fun <T : Any> getFrontendService(serviceClass: Class<T>): T {
+ return resolverForModule.componentProvider.getService(serviceClass)
+ }
+
+ @Deprecated("DO NOT USE IT AS IT IS A ROOT CAUSE OF KTIJ-17649")
+ override fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T {
+ return resolverForModule.componentProvider.getService(serviceClass)
+ }
+
+ override fun <T : Any> getIdeService(serviceClass: Class<T>): T {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getResolverForProject(): ResolverForProject<out ModuleInfo> {
+ throw UnsupportedOperationException()
+ }
+
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt
new file mode 100644
index 00000000..252fbd55
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.mock.MockComponentManager
+import com.intellij.mock.MockProject
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.AnalysisContextCreator
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment
+import org.jetbrains.kotlin.analyzer.ResolverForModule
+import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+
+internal class IdeAnalysisContextCreator : AnalysisContextCreator {
+ override fun create(
+ project: MockProject,
+ moduleDescriptor: ModuleDescriptor,
+ moduleResolver: ResolverForModule,
+ kotlinEnvironment: KotlinCoreEnvironment,
+ analysisEnvironment: AnalysisEnvironment,
+ ): AnalysisContext {
+ val facade = DokkaResolutionFacade(project, moduleDescriptor, moduleResolver)
+ val projectComponentManager = project as MockComponentManager
+ projectComponentManager.registerService(
+ KotlinCacheService::class.java,
+ CoreKotlinCacheService(facade)
+ )
+ return ResolutionFacadeAnalysisContext(facade, kotlinEnvironment, analysisEnvironment)
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt
new file mode 100644
index 00000000..e170b740
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
+
+@InternalDokkaApi
+public class IdeDescriptorAnalysisPlugin : DokkaPlugin() {
+
+ internal val ideKdocFinder by extending {
+ plugin<CompilerDescriptorAnalysisPlugin>().kdocFinder providing ::IdePluginKDocFinder
+ }
+
+ internal val ideDescriptorFinder by extending {
+ plugin<CompilerDescriptorAnalysisPlugin>().descriptorFinder providing { IdeDescriptorFinder() }
+ }
+
+ internal val ideKlibService by extending {
+ plugin<CompilerDescriptorAnalysisPlugin>().klibService providing { IdeKLibService() }
+ }
+
+ internal val ideApplicationHack by extending {
+ plugin<CompilerDescriptorAnalysisPlugin>().mockApplicationHack providing { IdeMockApplicationHack() }
+ }
+
+ internal val ideAnalysisContextCreator by extending {
+ plugin<CompilerDescriptorAnalysisPlugin>().analysisContextCreator providing { IdeAnalysisContextCreator() }
+ }
+
+ @OptIn(DokkaPluginApiPreview::class)
+ override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt
new file mode 100644
index 00000000..7a1e04e4
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.DescriptorFinder
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+internal class IdeDescriptorFinder : DescriptorFinder {
+ override fun KtDeclaration.findDescriptor(): DeclarationDescriptor? {
+ return if (this is KtParameter) this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) else this.resolveToDescriptorIfAny(
+ BodyResolveMode.FULL
+ )
+ }
+
+}
+
+
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt
new file mode 100644
index 00000000..e1c0eb31
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KLibService
+import org.jetbrains.kotlin.library.metadata.KlibMetadataModuleDescriptorFactory
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
+import org.jetbrains.kotlin.idea.klib.CachingIdeKlibMetadataLoader
+import org.jetbrains.kotlin.idea.klib.compatibilityInfo
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
+import org.jetbrains.kotlin.storage.StorageManager
+
+internal class IdeKLibService : KLibService {
+ override fun KotlinLibrary.createPackageFragmentProvider(
+ storageManager: StorageManager,
+ metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory,
+ languageVersionSettings: LanguageVersionSettings,
+ moduleDescriptor: ModuleDescriptor,
+ lookupTracker: LookupTracker,
+ ): PackageFragmentProvider? {
+ return this.createKlibPackageFragmentProvider(
+ storageManager, metadataModuleDescriptorFactory, languageVersionSettings, moduleDescriptor, lookupTracker
+ )
+ }
+
+ override fun isAnalysisCompatible(kotlinLibrary: KotlinLibrary): Boolean {
+ return kotlinLibrary.compatibilityInfo.isCompatible
+ }
+}
+
+internal fun KotlinLibrary.createKlibPackageFragmentProvider(
+ storageManager: StorageManager,
+ metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory,
+ languageVersionSettings: LanguageVersionSettings,
+ moduleDescriptor: ModuleDescriptor,
+ lookupTracker: LookupTracker
+): PackageFragmentProvider? {
+ if (!compatibilityInfo.isCompatible) return null
+
+ val packageFragmentNames = CachingIdeKlibMetadataLoader.loadModuleHeader(this).packageFragmentNameList
+
+ return metadataModuleDescriptorFactory.createPackageFragmentProvider(
+ library = this,
+ packageAccessHandler = CachingIdeKlibMetadataLoader,
+ packageFragmentNames = packageFragmentNames,
+ storageManager = storageManager,
+ moduleDescriptor = moduleDescriptor,
+ configuration = CompilerDeserializationConfiguration(languageVersionSettings),
+ compositePackageFragmentAddend = null,
+ lookupTracker = lookupTracker
+ )
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt
new file mode 100644
index 00000000..2bc83504
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.mock.MockApplication
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.MockApplicationHack
+import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache
+
+internal class IdeMockApplicationHack : MockApplicationHack {
+ override fun hack(mockApplication: MockApplication) {
+ if (mockApplication.getService(KlibLoadingMetadataCache::class.java) == null)
+ mockApplication.registerService(KlibLoadingMetadataCache::class.java, KlibLoadingMetadataCache())
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt
new file mode 100644
index 00000000..13119602
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.psi.PsiElement
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.idea.kdoc.findKDoc
+import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+
+internal class IdePluginKDocFinder(
+ private val context: DokkaContext
+) : KDocFinder {
+
+ override fun KtElement.findKDoc(): KDocTag? {
+ return this.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) }?.contentTag
+ }
+
+ override fun DeclarationDescriptor.find(descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement?): KDocTag? {
+ return this.findKDoc(descriptorToPsi)?.contentTag
+ }
+
+ override fun resolveKDocLink(
+ fromDescriptor: DeclarationDescriptor,
+ qualifiedName: String,
+ sourceSet: DokkaConfiguration.DokkaSourceSet,
+ emptyBindingContext: Boolean
+ ): Collection<DeclarationDescriptor> {
+ val facadeAnalysisContext = context
+ .plugin<CompilerDescriptorAnalysisPlugin>()
+ .querySingle { kotlinAnalysis }[sourceSet] as ResolutionFacadeAnalysisContext
+
+ return org.jetbrains.kotlin.idea.kdoc.resolveKDocLink(
+ context = if (emptyBindingContext) BindingContext.EMPTY else facadeAnalysisContext.resolveSession.bindingContext,
+ resolutionFacade = facadeAnalysisContext.facade,
+ fromDescriptor = fromDescriptor,
+ fromSubjectOfTag = null,
+ qualifiedName = qualifiedName.split('.'),
+ contextElement = fromDescriptor.findPsi()
+ )
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt
new file mode 100644
index 00000000..d70aeb99
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.openapi.project.Project
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+
+internal class ResolutionFacadeAnalysisContext(
+ val facade: DokkaResolutionFacade,
+
+ private val kotlinEnvironment: KotlinCoreEnvironment,
+ private val analysisEnvironment: AnalysisEnvironment
+) : AnalysisContext {
+ private var isClosed: Boolean = false
+
+ override val environment: KotlinCoreEnvironment
+ get() = kotlinEnvironment.takeUnless { isClosed }
+ ?: throw IllegalStateException("AnalysisEnvironment is already closed")
+
+ override val resolveSession: ResolveSession = facade.resolveSession
+ override val moduleDescriptor: ModuleDescriptor = facade.moduleDescriptor
+ override val project: Project = facade.project
+
+ override fun close() {
+ isClosed = true
+ analysisEnvironment.dispose()
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt
new file mode 100644
index 00000000..0f1b3ccf
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt
@@ -0,0 +1,45 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+package org.jetbrains.kotlin.caches.resolve
+
+import com.intellij.openapi.components.ComponentManager
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.analyzer.ModuleInfo
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.platform.TargetPlatform
+import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
+
+internal interface KotlinCacheService {
+ companion object {
+ inline fun <reified T : Any> ComponentManager.service(): T {
+ val serviceClass = T::class.java
+ return getService(serviceClass)
+ ?: error("Cannot find service ${serviceClass.name} in $this (classloader=${serviceClass.classLoader}")
+ }
+
+ fun getInstance(project: Project): KotlinCacheService = project.service()
+ }
+
+ /**
+ * Provides resolution facade for [elements], guaranteeing that the resolution will be seen from the [platform]-perspective.
+ *
+ * This allows to get resolution for common sources in MPP from the perspective of given platform (with expects substituted to actuals,
+ * declarations resolved from platform-specific artifacts, ModuleDescriptors will contain only platform dependencies, etc.)
+ *
+ * It is equivalent to usual [getResolutionFacade]-overloads if platform(s) of module(s) containing [elements] are equal to [platform]
+ *
+ * Doesn't support scripts or any other 'special' files.
+ */
+ fun getResolutionFacadeWithForcedPlatform(elements: List<KtElement>, platform: TargetPlatform): ResolutionFacade
+
+ fun getResolutionFacade(element: KtElement): ResolutionFacade
+ fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade
+ fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade?
+
+ fun getSuppressionCache(): KotlinSuppressCache
+ fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade?
+
+ fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade?
+} \ No newline at end of file
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt
new file mode 100644
index 00000000..f828580c
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.caches.resolve
+
+/**
+ * Regulates which sources should be analyzed together.
+ *
+ * There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning
+ * that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type):
+ * - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate
+ * facade for each platforms, sdk, builtIns settings and other stuff.
+ * This is the old and stable mode, which should be used by default.
+ *
+ * - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources
+ * together, in one facade.
+ * This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend.
+ * This mode is currently enabled only for HMPP projects
+ */
+internal interface PlatformAnalysisSettings \ No newline at end of file
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt
new file mode 100644
index 00000000..3d93093f
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt
@@ -0,0 +1,78 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+
+package org.jetbrains.kotlin.idea.caches.resolve
+
+import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
+
+
+internal fun KtElement.getResolutionFacade(): ResolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacade(this)
+
+/**
+ * This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent),
+ * and then takes the relevant descriptor from binding context.
+ * The exact set of declarations to resolve depends on bodyResolveMode
+ */
+internal fun KtDeclaration.resolveToDescriptorIfAny(
+ resolutionFacade: ResolutionFacade,
+ bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
+): DeclarationDescriptor? {
+ //TODO: BodyResolveMode.PARTIAL is not quite safe!
+ val context = safeAnalyze(resolutionFacade, bodyResolveMode)
+ return if (this is KtParameter && hasValOrVar()) {
+ context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this)
+ // It is incorrect to have `val/var` parameters outside the primary constructor (e.g., `fun foo(val x: Int)`)
+ // but we still want to try to resolve in such cases.
+ ?: context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
+ } else {
+ context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
+ }
+}
+
+internal fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
+ resolveToParameterDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
+
+internal fun KtParameter.resolveToParameterDescriptorIfAny(
+ resolutionFacade: ResolutionFacade,
+ bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
+): ValueParameterDescriptor? {
+ val context = safeAnalyze(resolutionFacade, bodyResolveMode)
+ return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor
+}
+
+internal fun KtDeclaration.resolveToDescriptorIfAny(
+ bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
+): DeclarationDescriptor? =
+ resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
+
+internal fun KtElement.analyze(
+ resolutionFacade: ResolutionFacade,
+ bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
+): BindingContext = resolutionFacade.analyze(this, bodyResolveMode)
+
+internal fun KtElement.safeAnalyze(
+ resolutionFacade: ResolutionFacade,
+ bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
+): BindingContext = try {
+ analyze(resolutionFacade, bodyResolveMode)
+} catch (e: Exception) {
+ e.returnIfNoDescriptorForDeclarationException { BindingContext.EMPTY }
+}
+
+internal inline fun <T> Exception.returnIfNoDescriptorForDeclarationException(
+ crossinline condition: (Boolean) -> Boolean = { v -> v },
+ crossinline computable: () -> T
+): T =
+ if (condition(this.isItNoDescriptorForDeclarationException)) {
+ computable()
+ } else {
+ throw this
+ }
+
+internal val Exception.isItNoDescriptorForDeclarationException: Boolean
+ get() = this is NoDescriptorForDeclarationException || (cause as? Exception)?.isItNoDescriptorForDeclarationException == true
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt
new file mode 100644
index 00000000..1accf430
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt
@@ -0,0 +1,129 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+
+package org.jetbrains.kotlin.idea.kdoc
+
+import com.intellij.psi.PsiElement
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
+import org.jetbrains.kotlin.kdoc.psi.api.KDoc
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
+import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
+import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
+import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
+
+internal data class KDocContent(
+ val contentTag: KDocTag,
+ val sections: List<KDocSection>
+)
+
+internal fun DeclarationDescriptor.findKDoc(
+ descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { DescriptorToSourceUtils.descriptorToDeclaration(it) }
+): KDocContent? {
+ if (this is DeclarationDescriptorWithSource) {
+ val psiDeclaration = descriptorToPsi(this)?.navigationElement
+ return (psiDeclaration as? KtElement)?.findKDoc(descriptorToPsi)
+ }
+ return null
+}
+
+private typealias DescriptorToPsi = (DeclarationDescriptorWithSource) -> PsiElement?
+
+internal fun KtElement.findKDoc(descriptorToPsi: DescriptorToPsi): KDocContent? {
+ return findKDoc()
+ ?: this.lookupInheritedKDoc(descriptorToPsi)
+}
+
+internal fun KtElement.findKDoc(): KDocContent? {
+ return this.lookupOwnedKDoc()
+ ?: this.lookupKDocInContainer()
+}
+
+private fun KtElement.lookupOwnedKDoc(): KDocContent? {
+ // KDoc for primary constructor is located inside of its class KDoc
+ val psiDeclaration = when (this) {
+ is KtPrimaryConstructor -> getContainingClassOrObject()
+ else -> this
+ }
+
+ if (psiDeclaration is KtDeclaration) {
+ val kdoc = psiDeclaration.docComment
+ if (kdoc != null) {
+ if (this is KtConstructor<*>) {
+ // ConstructorDescriptor resolves to the same JetDeclaration
+ val constructorSection = kdoc.findSectionByTag(KDocKnownTag.CONSTRUCTOR)
+ if (constructorSection != null) {
+ // if annotated with @constructor tag and the caret is on constructor definition,
+ // then show @constructor description as the main content, and additional sections
+ // that contain @param tags (if any), as the most relatable ones
+ // practical example: val foo = Fo<caret>o("argument") -- show @constructor and @param content
+ val paramSections = kdoc.findSectionsContainingTag(KDocKnownTag.PARAM)
+ return KDocContent(constructorSection, paramSections)
+ }
+ }
+ return KDocContent(kdoc.getDefaultSection(), kdoc.getAllSections())
+ }
+ }
+ return null
+}
+
+/**
+ * Looks for sections that have a deeply nested [tag],
+ * as opposed to [KDoc.findSectionByTag], which only looks among the top level
+ */
+private fun KDoc.findSectionsContainingTag(tag: KDocKnownTag): List<KDocSection> {
+ return getChildrenOfType<KDocSection>()
+ .filter { it.findTagByName(tag.name.toLowerCaseAsciiOnly()) != null }
+}
+
+private fun KtElement.lookupKDocInContainer(): KDocContent? {
+ val subjectName = name
+ val containingDeclaration =
+ PsiTreeUtil.findFirstParent(this, true) {
+ it is KtDeclarationWithBody && it !is KtPrimaryConstructor
+ || it is KtClassOrObject
+ }
+
+ val containerKDoc = containingDeclaration?.getChildOfType<KDoc>()
+ if (containerKDoc == null || subjectName == null) return null
+ val propertySection = containerKDoc.findSectionByTag(KDocKnownTag.PROPERTY, subjectName)
+ val paramTag = containerKDoc.findDescendantOfType<KDocTag> { it.knownTag == KDocKnownTag.PARAM && it.getSubjectName() == subjectName }
+
+ val primaryContent = when {
+ // class Foo(val <caret>s: String)
+ this is KtParameter && this.isPropertyParameter() -> propertySection ?: paramTag
+ // fun some(<caret>f: String) || class Some<<caret>T: Base> || Foo(<caret>s = "argument")
+ this is KtParameter || this is KtTypeParameter -> paramTag
+ // if this property is declared separately (outside primary constructor), but it's for some reason
+ // annotated as @property in class's description, instead of having its own KDoc
+ this is KtProperty && containingDeclaration is KtClassOrObject -> propertySection
+ else -> null
+ }
+ return primaryContent?.let {
+ // makes little sense to include any other sections, since we found
+ // documentation for a very specific element, like a property/param
+ KDocContent(it, sections = emptyList())
+ }
+}
+
+private fun KtElement.lookupInheritedKDoc(descriptorToPsi: DescriptorToPsi): KDocContent? {
+ if (this is KtCallableDeclaration) {
+ val descriptor = this.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null
+
+ for (baseDescriptor in descriptor.overriddenDescriptors) {
+ val baseKDoc = baseDescriptor.original.findKDoc(descriptorToPsi)
+ if (baseKDoc != null) {
+ return baseKDoc
+ }
+ }
+ }
+ return null
+} \ No newline at end of file
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt
new file mode 100644
index 00000000..7e4e0bb5
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt
@@ -0,0 +1,311 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+
+package org.jetbrains.kotlin.idea.kdoc
+
+import com.intellij.openapi.components.ComponentManager
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.idea.FrontendInternals
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.idea.resolve.frontendService
+import org.jetbrains.kotlin.idea.util.CallType
+import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
+import org.jetbrains.kotlin.incremental.components.LookupLocation
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.KtQualifiedExpression
+import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
+import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
+import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
+import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
+import org.jetbrains.kotlin.resolve.scopes.*
+import org.jetbrains.kotlin.resolve.scopes.utils.*
+import org.jetbrains.kotlin.resolve.source.PsiSourceElement
+import org.jetbrains.kotlin.utils.Printer
+import org.jetbrains.kotlin.utils.SmartList
+import org.jetbrains.kotlin.utils.addIfNotNull
+
+/**
+ * Returns `null` if the service cannot be found in [this] component manager,
+ * otherwise initializes a service if not yet initialized, and returns the service instance.
+ * @see ComponentManager.getService
+ */
+internal inline fun <reified T : Any> ComponentManager.serviceOrNull(): T? {
+ return getService(T::class.java)
+}
+
+@OptIn(FrontendInternals::class)
+internal fun ResolutionFacade.getFileResolutionScope(file: KtFile): LexicalScope {
+ return frontendService<FileScopeProvider>().getFileResolutionScope(file)
+}
+
+internal fun resolveKDocLink(
+ context: BindingContext,
+ resolutionFacade: ResolutionFacade,
+ fromDescriptor: DeclarationDescriptor,
+ contextElement: PsiElement?,
+ fromSubjectOfTag: KDocTag?,
+ qualifiedName: List<String>
+): Collection<DeclarationDescriptor> {
+ val tag = fromSubjectOfTag?.knownTag
+ if (tag == KDocKnownTag.PARAM) {
+ return resolveParamLink(fromDescriptor, qualifiedName)
+ }
+ val contextScope = getKDocLinkResolutionScope(resolutionFacade, fromDescriptor)
+ if (qualifiedName.size == 1) {
+ val localDescriptors = resolveLocal(qualifiedName.single(), contextScope, fromDescriptor)
+ if (localDescriptors.isNotEmpty()) {
+ return localDescriptors
+ }
+ }
+
+ // [IdeKDocLinkResolutionService] is omitted
+
+ return resolveDefaultKDocLink(context, resolutionFacade, contextElement, qualifiedName, contextScope)
+}
+
+internal fun getParamDescriptors(fromDescriptor: DeclarationDescriptor): List<DeclarationDescriptor> {
+ // TODO resolve parameters of functions passed as parameters
+ when (fromDescriptor) {
+ is CallableDescriptor -> {
+ return fromDescriptor.valueParameters + fromDescriptor.typeParameters
+ }
+
+ is ClassifierDescriptor -> {
+ val typeParams = fromDescriptor.typeConstructor.parameters
+ if (fromDescriptor is ClassDescriptor) {
+ val constructorDescriptor = fromDescriptor.unsubstitutedPrimaryConstructor
+ if (constructorDescriptor != null) {
+ return typeParams + constructorDescriptor.valueParameters
+ }
+ }
+ return typeParams
+ }
+
+ else -> {
+ return emptyList()
+ }
+ }
+}
+
+private fun resolveParamLink(fromDescriptor: DeclarationDescriptor, qualifiedName: List<String>): List<DeclarationDescriptor> {
+ val name = qualifiedName.singleOrNull() ?: return emptyList()
+ return getParamDescriptors(fromDescriptor).filter { it.name.asString() == name }
+}
+
+private fun resolveLocal(
+ nameToResolve: String,
+ contextScope: LexicalScope,
+ fromDescriptor: DeclarationDescriptor
+): List<DeclarationDescriptor> {
+ val shortName = Name.identifier(nameToResolve)
+
+ val descriptorsByName = SmartList<DeclarationDescriptor>()
+ descriptorsByName.addIfNotNull(contextScope.findClassifier(shortName, NoLookupLocation.FROM_IDE))
+ descriptorsByName.addIfNotNull(contextScope.findPackage(shortName))
+ descriptorsByName.addAll(contextScope.collectFunctions(shortName, NoLookupLocation.FROM_IDE))
+ descriptorsByName.addAll(contextScope.collectVariables(shortName, NoLookupLocation.FROM_IDE))
+
+ if (fromDescriptor is FunctionDescriptor && fromDescriptor.isExtension && shortName.asString() == "this") {
+ return listOfNotNull(fromDescriptor.extensionReceiverParameter)
+ }
+
+ // Try to find a matching local descriptor (parameter or type parameter) first
+ val localDescriptors = descriptorsByName.filter { it.containingDeclaration == fromDescriptor }
+ if (localDescriptors.isNotEmpty()) return localDescriptors
+
+ return descriptorsByName
+}
+
+private fun resolveDefaultKDocLink(
+ context: BindingContext,
+ resolutionFacade: ResolutionFacade,
+ contextElement: PsiElement?,
+ qualifiedName: List<String>,
+ contextScope: LexicalScope
+): Collection<DeclarationDescriptor> {
+ @OptIn(FrontendInternals::class)
+ val qualifiedExpressionResolver = resolutionFacade.getFrontendService(QualifiedExpressionResolver::class.java)
+
+ val factory = KtPsiFactory(resolutionFacade.project)
+ // TODO escape identifiers
+ val codeFragment = factory.createExpressionCodeFragment(qualifiedName.joinToString("."), contextElement)
+ val qualifiedExpression =
+ codeFragment.findElementAt(codeFragment.textLength - 1)?.getStrictParentOfType<KtQualifiedExpression>() ?: return emptyList()
+ val (descriptor, memberName) = qualifiedExpressionResolver.resolveClassOrPackageInQualifiedExpression(
+ qualifiedExpression,
+ contextScope,
+ context
+ )
+ if (descriptor == null) return emptyList()
+ if (memberName != null) {
+ val memberScope = getKDocLinkMemberScope(descriptor, contextScope)
+ return memberScope.getContributedFunctions(memberName, NoLookupLocation.FROM_IDE) +
+ memberScope.getContributedVariables(memberName, NoLookupLocation.FROM_IDE) +
+ listOfNotNull(memberScope.getContributedClassifier(memberName, NoLookupLocation.FROM_IDE))
+ }
+ return listOf(descriptor)
+}
+
+private fun getPackageInnerScope(descriptor: PackageFragmentDescriptor): MemberScope {
+ return descriptor.containingDeclaration.getPackage(descriptor.fqName).memberScope
+}
+
+private fun getClassInnerScope(outerScope: LexicalScope, descriptor: ClassDescriptor): LexicalScope {
+
+ val headerScope = LexicalScopeImpl(
+ outerScope, descriptor, false, descriptor.thisAsReceiverParameter,
+ descriptor.contextReceivers, LexicalScopeKind.SYNTHETIC
+ ) {
+ descriptor.declaredTypeParameters.forEach { addClassifierDescriptor(it) }
+ descriptor.constructors.forEach { addFunctionDescriptor(it) }
+ }
+
+ return LexicalChainedScope.create(
+ headerScope, descriptor, false, null, emptyList(), LexicalScopeKind.SYNTHETIC,
+ descriptor.defaultType.memberScope,
+ descriptor.staticScope,
+ descriptor.companionObjectDescriptor?.defaultType?.memberScope
+ )
+}
+
+internal fun getKDocLinkResolutionScope(resolutionFacade: ResolutionFacade, contextDescriptor: DeclarationDescriptor): LexicalScope {
+ return when (contextDescriptor) {
+ is PackageFragmentDescriptor ->
+ LexicalScope.Base(getPackageInnerScope(contextDescriptor).memberScopeAsImportingScope(), contextDescriptor)
+
+ is PackageViewDescriptor ->
+ LexicalScope.Base(contextDescriptor.memberScope.memberScopeAsImportingScope(), contextDescriptor)
+
+ is ClassDescriptor ->
+ getClassInnerScope(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
+
+ is FunctionDescriptor -> FunctionDescriptorUtil.getFunctionInnerScope(
+ getOuterScope(contextDescriptor, resolutionFacade),
+ contextDescriptor, LocalRedeclarationChecker.DO_NOTHING
+ )
+
+ is PropertyDescriptor ->
+ ScopeUtils.makeScopeForPropertyHeader(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
+
+ is DeclarationDescriptorNonRoot ->
+ getOuterScope(contextDescriptor, resolutionFacade)
+
+ else -> throw IllegalArgumentException("Cannot find resolution scope for root $contextDescriptor")
+ }
+}
+
+private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, resolutionFacade: ResolutionFacade): LexicalScope {
+ val parent = descriptor.containingDeclaration!!
+ if (parent is PackageFragmentDescriptor) {
+ val containingFile = (descriptor.source as? PsiSourceElement)?.psi?.containingFile as? KtFile ?: return LexicalScope.Base(
+ ImportingScope.Empty,
+ parent
+ )
+ val kotlinCacheService = containingFile.project.serviceOrNull<KotlinCacheService>()
+ val facadeToUse = kotlinCacheService?.getResolutionFacade(containingFile) ?: resolutionFacade
+ return facadeToUse.getFileResolutionScope(containingFile)
+ } else {
+ return getKDocLinkResolutionScope(resolutionFacade, parent)
+ }
+}
+
+internal fun getKDocLinkMemberScope(descriptor: DeclarationDescriptor, contextScope: LexicalScope): MemberScope {
+ return when (descriptor) {
+ is PackageFragmentDescriptor -> getPackageInnerScope(descriptor)
+
+ is PackageViewDescriptor -> descriptor.memberScope
+
+ is ClassDescriptor -> {
+ ChainedMemberScope.create(
+ "Member scope for KDoc resolve", listOfNotNull(
+ descriptor.unsubstitutedMemberScope,
+ descriptor.staticScope,
+ descriptor.companionObjectDescriptor?.unsubstitutedMemberScope,
+ ExtensionsScope(descriptor, contextScope)
+ )
+ )
+ }
+
+ else -> MemberScope.Empty
+ }
+}
+
+private class ExtensionsScope(
+ private val receiverClass: ClassDescriptor,
+ private val contextScope: LexicalScope
+) : MemberScope {
+ private val receiverTypes = listOf(receiverClass.defaultType)
+
+ override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
+ return contextScope.collectFunctions(name, location).flatMap {
+ if (it is SimpleFunctionDescriptor && it.isExtension) {
+ it.substituteExtensionIfCallable(
+ receiverTypes = receiverTypes,
+ callType = CallType.DOT,
+ ignoreTypeParameters = true,
+ )
+ } else {
+ emptyList()
+ }
+ }
+ }
+
+ override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
+ return contextScope.collectVariables(name, location).flatMap {
+ if (it is PropertyDescriptor && it.isExtension) {
+ it.substituteExtensionIfCallable(
+ receiverTypes = receiverTypes,
+ callType = CallType.DOT,
+ ignoreTypeParameters = true,
+ )
+ } else {
+ emptyList()
+ }
+ }
+ }
+
+ override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
+
+ override fun getContributedDescriptors(
+ kindFilter: DescriptorKindFilter,
+ nameFilter: (Name) -> Boolean
+ ): Collection<DeclarationDescriptor> {
+ if (DescriptorKindExclude.Extensions in kindFilter.excludes) return emptyList()
+ return contextScope.collectDescriptorsFiltered(
+ kindFilter exclude DescriptorKindExclude.NonExtensions,
+ nameFilter,
+ changeNamesForAliased = true
+ ).flatMap {
+ if (it is CallableDescriptor && it.isExtension) {
+ it.substituteExtensionIfCallable(
+ receiverTypes = receiverTypes,
+ callType = CallType.DOT,
+ ignoreTypeParameters = true,
+ )
+ } else {
+ emptyList()
+ }
+ }
+ }
+
+ override fun getFunctionNames(): Set<Name> =
+ getContributedDescriptors(kindFilter = DescriptorKindFilter.FUNCTIONS).map { it.name }.toSet()
+
+ override fun getVariableNames(): Set<Name> =
+ getContributedDescriptors(kindFilter = DescriptorKindFilter.VARIABLES).map { it.name }.toSet()
+
+ override fun getClassifierNames() = null
+
+ override fun printScopeStructure(p: Printer) {
+ p.println("Extensions for ${receiverClass.name} in:")
+ contextScope.printStructure(p)
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt
new file mode 100644
index 00000000..5c7ea8fb
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt
@@ -0,0 +1,56 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package org.jetbrains.kotlin.idea.klib
+
+import com.intellij.openapi.util.io.FileUtilRt
+import com.intellij.openapi.vfs.StandardFileSystems
+import com.intellij.openapi.vfs.VirtualFile
+import org.jetbrains.annotations.Contract
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.library.impl.KotlinLibraryImpl
+import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
+import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
+import org.jetbrains.kotlin.metadata.ProtoBuf
+import org.jetbrains.kotlin.konan.file.File as KFile
+
+
+@Contract("null -> null; !null -> !null")
+internal fun toSystemIndependentName(path: String?): String? {
+ return if (path == null) null else FileUtilRt.toSystemIndependentName(path)
+}
+
+internal object CachingIdeKlibMetadataLoader : PackageAccessHandler {
+ override fun loadModuleHeader(library: KotlinLibrary): KlibMetadataProtoBuf.Header {
+ val virtualFile = getVirtualFile(library, library.moduleHeaderFile)
+ return virtualFile?.let { cache.getCachedModuleHeader(virtualFile) } ?: KlibMetadataProtoBuf.Header.getDefaultInstance()
+ }
+
+ override fun loadPackageFragment(library: KotlinLibrary, packageFqName: String, partName: String): ProtoBuf.PackageFragment {
+ val virtualFile = getVirtualFile(library, library.packageFragmentFile(packageFqName, partName))
+ return virtualFile?.let { cache.getCachedPackageFragment(virtualFile) } ?: ProtoBuf.PackageFragment.getDefaultInstance()
+ }
+
+ private fun getVirtualFile(library: KotlinLibrary, file: KFile): VirtualFile? =
+ if (library.isZipped) asJarFileSystemFile(library.libraryFile, file) else asLocalFile(file)
+
+ private fun asJarFileSystemFile(jarFile: KFile, localFile: KFile): VirtualFile? {
+ val fullPath = jarFile.absolutePath + "!" + toSystemIndependentName(localFile.path)
+ return StandardFileSystems.jar().findFileByPath(fullPath)
+ }
+
+ private fun asLocalFile(localFile: KFile): VirtualFile? {
+ val fullPath = localFile.absolutePath
+ return StandardFileSystems.local().findFileByPath(fullPath)
+ }
+
+ private val cache
+ get() = KlibLoadingMetadataCache.getInstance()
+
+ private val KotlinLibrary.moduleHeaderFile
+ get() = (this as KotlinLibraryImpl).metadata.access.layout.moduleHeaderFile
+
+ private fun KotlinLibrary.packageFragmentFile(packageFqName: String, partName: String) =
+ (this as KotlinLibraryImpl).metadata.access.layout.packageFragmentFile(packageFqName, partName)
+
+ private val KotlinLibrary.isZipped
+ get() = (this as KotlinLibraryImpl).base.access.layout.isZipped
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt
new file mode 100644
index 00000000..4923534d
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt
@@ -0,0 +1,48 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+@file:JvmName("KlibCompatibilityInfoUtils")
+
+package org.jetbrains.kotlin.idea.klib
+
+
+import org.jetbrains.kotlin.library.*
+import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
+import org.jetbrains.kotlin.library.metadata.metadataVersion
+import java.io.IOException
+
+/**
+ * Whether a certain KLIB is compatible for the purposes of IDE: indexation, resolve, etc.
+ */
+internal sealed class KlibCompatibilityInfo(val isCompatible: Boolean) {
+ object Compatible : KlibCompatibilityInfo(true)
+ object Pre14Layout : KlibCompatibilityInfo(false)
+ class IncompatibleMetadata(val isOlder: Boolean) : KlibCompatibilityInfo(false)
+}
+
+
+internal fun <T> KotlinLibrary.safeRead(defaultValue: T, action: KotlinLibrary.() -> T) = try {
+ action()
+} catch (_: IOException) {
+ defaultValue
+}
+internal val KotlinLibrary.compatibilityInfo: KlibCompatibilityInfo
+ get() {
+ val hasPre14Manifest = safeRead(false) { has_pre_1_4_manifest }
+ if (hasPre14Manifest)
+ return KlibCompatibilityInfo.Pre14Layout
+
+ val metadataVersion = safeRead(null) { this.metadataVersion }
+ @Suppress("DEPRECATION")
+ return when {
+ metadataVersion == null -> {
+ // Too old KLIB format, even doesn't have metadata version
+ KlibCompatibilityInfo.IncompatibleMetadata(true)
+ }
+
+ !metadataVersion.isCompatible() -> {
+ val isOlder = metadataVersion.isAtLeast(KlibMetadataVersion.INSTANCE)
+ KlibCompatibilityInfo.IncompatibleMetadata(!isOlder)
+ }
+
+ else -> KlibCompatibilityInfo.Compatible
+ }
+ }
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt
new file mode 100644
index 00000000..55c615f6
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt
@@ -0,0 +1,114 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+package org.jetbrains.kotlin.idea.klib
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.util.containers.ContainerUtil
+import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME
+import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION
+import org.jetbrains.kotlin.library.KLIB_MODULE_METADATA_FILE_NAME
+import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
+import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
+import org.jetbrains.kotlin.library.metadata.parseModuleHeader
+import org.jetbrains.kotlin.library.metadata.parsePackageFragment
+import org.jetbrains.kotlin.library.readKonanLibraryVersioning
+import org.jetbrains.kotlin.metadata.ProtoBuf
+import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
+import java.io.IOException
+import java.util.*
+
+internal class KlibLoadingMetadataCache {
+ // Use special CacheKey class instead of VirtualFile for cache keys. Certain types of VirtualFiles (for example, obtained from JarFileSystem)
+ // do not compare path (url) and modification stamp in equals() method.
+ private data class CacheKey(
+ val url: String,
+ val modificationStamp: Long
+ ) {
+ constructor(virtualFile: VirtualFile) : this(virtualFile.url, virtualFile.modificationStamp)
+ }
+
+ // ConcurrentWeakValueHashMap does not allow null values.
+ private class CacheValue<T : Any>(val value: T?)
+
+ private val packageFragmentCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<ProtoBuf.PackageFragment>>()
+ private val moduleHeaderCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataProtoBuf.Header>>()
+ private val libraryMetadataVersionCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataVersion>>()
+
+ fun getCachedPackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? {
+ check(packageFragmentFile.extension == KLIB_METADATA_FILE_EXTENSION) {
+ "Not a package metadata file: $packageFragmentFile"
+ }
+
+ return packageFragmentCache.computeIfAbsent(
+ CacheKey(packageFragmentFile)
+ ) {
+ CacheValue(computePackageFragment(packageFragmentFile))
+ }.value
+ }
+
+ fun getCachedModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? {
+ check(moduleHeaderFile.name == KLIB_MODULE_METADATA_FILE_NAME) {
+ "Not a module header file: $moduleHeaderFile"
+ }
+
+ return moduleHeaderCache.computeIfAbsent(
+ CacheKey(moduleHeaderFile)
+ ) {
+ CacheValue(computeModuleHeader(moduleHeaderFile))
+ }.value
+ }
+
+ private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean {
+ val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return false
+
+ val metadataVersion = libraryMetadataVersionCache.computeIfAbsent(
+ CacheKey(manifestFile)
+ ) {
+ CacheValue(computeLibraryMetadataVersion(manifestFile))
+ }.value ?: return false
+
+ @Suppress("DEPRECATION")
+ return metadataVersion.isCompatible()
+ }
+
+ private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? {
+ if (!isMetadataCompatible(packageFragmentFile.parent.parent.parent))
+ return null
+
+ return try {
+ parsePackageFragment(packageFragmentFile.contentsToByteArray(false))
+ } catch (_: IOException) {
+ null
+ }
+ }
+
+ private fun computeModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? {
+ if (!isMetadataCompatible(moduleHeaderFile.parent.parent))
+ return null
+
+ return try {
+ parseModuleHeader(moduleHeaderFile.contentsToByteArray(false))
+ } catch (_: IOException) {
+ null
+ }
+ }
+
+ private fun computeLibraryMetadataVersion(manifestFile: VirtualFile): KlibMetadataVersion? = try {
+ val versioning = Properties().apply { manifestFile.inputStream.use { load(it) } }.readKonanLibraryVersioning()
+ versioning.metadataVersion?.let(BinaryVersion.Companion::parseVersionArray)?.let(::KlibMetadataVersion)
+ } catch (_: IOException) {
+ // ignore and cache null value
+ null
+ } catch (_: IllegalArgumentException) {
+ // ignore and cache null value
+ null
+ }
+
+ companion object {
+ @JvmStatic
+ fun getInstance(): KlibLoadingMetadataCache =
+ ApplicationManager.getApplication().getService(KlibLoadingMetadataCache::class.java)
+ }
+
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt
new file mode 100644
index 00000000..c4adb2e3
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt
@@ -0,0 +1,61 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+package org.jetbrains.kotlin.idea.resolve
+
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.analyzer.AnalysisResult
+import org.jetbrains.kotlin.analyzer.ModuleInfo
+import org.jetbrains.kotlin.analyzer.ResolverForProject
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.diagnostics.DiagnosticSink
+import org.jetbrains.kotlin.idea.FrontendInternals
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+internal interface ResolutionFacade {
+ val project: Project
+
+ fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext
+ fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext
+
+ fun analyzeWithAllCompilerChecks(element: KtElement, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult
+ = analyzeWithAllCompilerChecks(listOf(element), callback)
+
+ fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult
+
+ fun fetchWithAllCompilerChecks(element: KtElement): AnalysisResult? = null
+
+ fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor
+
+ val moduleDescriptor: ModuleDescriptor
+
+ // get service for the module this resolution was created for
+ @FrontendInternals
+ fun <T : Any> getFrontendService(serviceClass: Class<T>): T
+
+ fun <T : Any> getIdeService(serviceClass: Class<T>): T
+
+ // get service for the module defined by PsiElement/ModuleDescriptor passed as parameter
+ @FrontendInternals
+ fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T
+
+ @FrontendInternals
+ fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T?
+
+ @Deprecated("DO NOT USE IT AS IT IS A ROOT CAUSE OF KTIJ-17649")
+ @FrontendInternals
+ fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T
+
+ fun getResolverForProject(): ResolverForProject<out ModuleInfo>
+}
+
+@FrontendInternals
+internal inline fun <reified T : Any> ResolutionFacade.frontendService(): T = this.getFrontendService(T::class.java)
+
+internal inline fun <reified T : Any> ResolutionFacade.ideService(): T = this.getIdeService(T::class.java)
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt
new file mode 100644
index 00000000..6d3077e2
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt
@@ -0,0 +1,96 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.kotlin.idea.util
+
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
+import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
+
+
+@Suppress("ClassName")
+internal sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: DescriptorKindFilter) {
+ object UNKNOWN : CallType<Nothing?>(DescriptorKindFilter.ALL)
+
+ object DEFAULT : CallType<Nothing?>(DescriptorKindFilter.ALL)
+
+ object DOT : CallType<KtExpression>(DescriptorKindFilter.ALL)
+
+ object SAFE : CallType<KtExpression>(DescriptorKindFilter.ALL)
+
+ object SUPER_MEMBERS : CallType<KtSuperExpression>(
+ DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude
+ )
+
+ object INFIX : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude)
+
+ object OPERATOR : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
+
+ class CallableReference(settings: LanguageVersionSettings) :
+ CallType<KtExpression?>(DescriptorKindFilter.CALLABLES exclude LocalsAndSyntheticExclude(settings)) {
+ override fun equals(other: Any?): Boolean = other is CallableReference
+ override fun hashCode(): Int = javaClass.hashCode()
+ }
+
+ object IMPORT_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.ALL)
+
+ object PACKAGE_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.PACKAGES)
+
+ object TYPE : CallType<KtExpression?>(
+ DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
+ exclude DescriptorKindExclude.EnumEntry
+ )
+
+ object DELEGATE : CallType<KtExpression?>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
+
+ object ANNOTATION : CallType<KtExpression?>(
+ DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
+ exclude NonAnnotationClassifierExclude
+ )
+
+ private object NonInfixExclude : DescriptorKindExclude() {
+ override fun excludes(descriptor: DeclarationDescriptor) =
+ !(descriptor is SimpleFunctionDescriptor && descriptor.isInfix)
+
+ override val fullyExcludedDescriptorKinds: Int
+ get() = 0
+ }
+
+ private object NonOperatorExclude : DescriptorKindExclude() {
+ override fun excludes(descriptor: DeclarationDescriptor) =
+ !(descriptor is SimpleFunctionDescriptor && descriptor.isOperator)
+
+ override val fullyExcludedDescriptorKinds: Int
+ get() = 0
+ }
+
+ private class LocalsAndSyntheticExclude(private val settings: LanguageVersionSettings) : DescriptorKindExclude() {
+ // Currently, Kotlin doesn't support references to local variables
+ // References to Java synthetic properties are supported only since Kotlin 1.9
+ override fun excludes(descriptor: DeclarationDescriptor): Boolean =
+ descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED &&
+ !settings.supportsFeature(LanguageFeature.ReferencesToSyntheticJavaProperties)
+
+ override val fullyExcludedDescriptorKinds: Int
+ get() = 0
+ }
+
+ private object NonAnnotationClassifierExclude : DescriptorKindExclude() {
+ override fun excludes(descriptor: DeclarationDescriptor): Boolean {
+ if (descriptor !is ClassifierDescriptor) return false
+ return descriptor !is ClassDescriptor || descriptor.kind != ClassKind.ANNOTATION_CLASS
+ }
+
+ override val fullyExcludedDescriptorKinds: Int get() = 0
+ }
+
+ private object AbstractMembersExclude : DescriptorKindExclude() {
+ override fun excludes(descriptor: DeclarationDescriptor) =
+ descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT
+
+ override val fullyExcludedDescriptorKinds: Int
+ get() = 0
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt
new file mode 100644
index 00000000..b8a1ae56
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt
@@ -0,0 +1,51 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+@file:JvmName("ExtensionUtils")
+
+package org.jetbrains.kotlin.idea.util
+
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeSubstitutor
+import org.jetbrains.kotlin.types.typeUtil.TypeNullability
+import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
+import org.jetbrains.kotlin.types.typeUtil.nullability
+
+
+internal fun <TCallable : CallableDescriptor> TCallable.substituteExtensionIfCallable(
+ receiverTypes: Collection<KotlinType>,
+ callType: CallType<*>,
+ ignoreTypeParameters: Boolean = false,
+): Collection<TCallable> {
+ if (!callType.descriptorKindFilter.accepts(this)) return listOf()
+
+ var types = receiverTypes.asSequence()
+ if (callType == CallType.SAFE) {
+ types = types.map { it.makeNotNullable() }
+ }
+
+ val extensionReceiverType = fuzzyExtensionReceiverType()!!
+ val substitutors = types.mapNotNull {
+ // NOTE: this creates a fuzzy type for `it` without type parameters
+ var substitutor = extensionReceiverType.checkIsSuperTypeOf(it)
+
+ // If enabled, we can ignore type parameters in the receiver type, and only check whether the constructors match
+ if (ignoreTypeParameters && substitutor == null && it.constructor == extensionReceiverType.type.constructor) {
+ substitutor = TypeSubstitutor.EMPTY
+ }
+
+ // check if we may fail due to receiver expression being nullable
+ if (substitutor == null && it.nullability() == TypeNullability.NULLABLE && extensionReceiverType.nullability() == TypeNullability.NOT_NULL) {
+ substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable())
+ }
+ substitutor
+ }
+
+ return if (typeParameters.isEmpty()) { // optimization for non-generic callables
+ if (substitutors.any()) listOf(this) else listOf()
+ } else {
+ substitutors
+ .mapNotNull { @Suppress("UNCHECKED_CAST") (substitute(it) as TCallable?) }
+ .toList()
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt
new file mode 100644
index 00000000..de0895e6
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt
@@ -0,0 +1,154 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+@file:JvmName("FuzzyTypeUtils")
+package org.jetbrains.kotlin.idea.util
+
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
+import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
+import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
+import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
+import org.jetbrains.kotlin.types.*
+import org.jetbrains.kotlin.types.error.ErrorUtils
+import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
+import org.jetbrains.kotlin.types.typeUtil.*
+import java.util.*
+
+internal fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters)
+
+internal fun FuzzyType.nullability() = type.nullability()
+
+internal fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters)
+
+internal class FuzzyType(val type: KotlinType, freeParameters: Collection<TypeParameterDescriptor>) {
+ val freeParameters: Set<TypeParameterDescriptor>
+
+ init {
+ if (freeParameters.isNotEmpty()) {
+ // we allow to pass type parameters from another function with the same original in freeParameters
+ val usedTypeParameters = HashSet<TypeParameterDescriptor>().apply { addUsedTypeParameters(type) }
+ if (usedTypeParameters.isNotEmpty()) {
+ val originalFreeParameters = freeParameters.map { it.toOriginal() }.toSet()
+ this.freeParameters = usedTypeParameters.filter { it.toOriginal() in originalFreeParameters }.toSet()
+ } else {
+ this.freeParameters = emptySet()
+ }
+ } else {
+ this.freeParameters = emptySet()
+ }
+ }
+
+ // Diagnostic for EA-109046
+ @Suppress("USELESS_ELVIS")
+ private fun TypeParameterDescriptor.toOriginal(): TypeParameterDescriptor {
+ val callableDescriptor = containingDeclaration as? CallableMemberDescriptor ?: return this
+ val original = callableDescriptor.original ?: error("original = null for $callableDescriptor")
+ val typeParameters = original.typeParameters ?: error("typeParameters = null for $original")
+ return typeParameters[index]
+ }
+
+ override fun equals(other: Any?) = other is FuzzyType && other.type == type && other.freeParameters == freeParameters
+
+ override fun hashCode() = type.hashCode()
+
+ private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(type: KotlinType) {
+ val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor
+ if (typeParameter != null && add(typeParameter)) {
+ typeParameter.upperBounds.forEach { addUsedTypeParameters(it) }
+ }
+
+ for (argument in type.arguments) {
+ if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
+ addUsedTypeParameters(argument.type)
+ }
+ }
+ }
+
+ fun checkIsSubtypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUBTYPE)
+
+ fun checkIsSuperTypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType,
+ MatchKind.IS_SUPERTYPE
+ )
+
+ fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSubtypeOf(otherType.toFuzzyType(emptyList()))
+
+ fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSuperTypeOf(otherType.toFuzzyType(emptyList()))
+
+ private enum class MatchKind {
+ IS_SUBTYPE,
+ IS_SUPERTYPE
+ }
+
+ private fun matchedSubstitutor(otherType: FuzzyType, matchKind: MatchKind): TypeSubstitutor? {
+ if (type.isError) return null
+ if (otherType.type.isError) return null
+ if (otherType.type.isUnit() && matchKind == MatchKind.IS_SUBTYPE) return TypeSubstitutor.EMPTY
+
+ fun KotlinType.checkInheritance(otherType: KotlinType): Boolean {
+ return when (matchKind) {
+ MatchKind.IS_SUBTYPE -> this.isSubtypeOf(otherType)
+ MatchKind.IS_SUPERTYPE -> otherType.isSubtypeOf(this)
+ }
+ }
+
+ if (freeParameters.isEmpty() && otherType.freeParameters.isEmpty()) {
+ return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null
+ }
+
+ val builder = ConstraintSystemBuilderImpl()
+ val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters)
+
+ val typeInSystem = typeVariableSubstitutor.substitute(type, Variance.INVARIANT)
+ val otherTypeInSystem = typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT)
+
+ when (matchKind) {
+ MatchKind.IS_SUBTYPE ->
+ builder.addSubtypeConstraint(typeInSystem, otherTypeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
+ MatchKind.IS_SUPERTYPE ->
+ builder.addSubtypeConstraint(otherTypeInSystem, typeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
+ }
+
+ builder.fixVariables()
+
+ val constraintSystem = builder.build()
+
+ if (constraintSystem.status.hasContradiction()) return null
+
+ // currently ConstraintSystem return successful status in case there are problems with nullability
+ // that's why we have to check subtyping manually
+ val substitutor = constraintSystem.resultingSubstitutor
+ val substitutedType = substitutor.substitute(type, Variance.INVARIANT) ?: return null
+ if (substitutedType.isError) return TypeSubstitutor.EMPTY
+ val otherSubstitutedType = substitutor.substitute(otherType.type, Variance.INVARIANT) ?: return null
+ if (otherSubstitutedType.isError) return TypeSubstitutor.EMPTY
+ if (!substitutedType.checkInheritance(otherSubstitutedType)) return null
+
+ val substitutorToKeepCapturedTypes = object : DelegatedTypeSubstitution(substitutor.substitution) {
+ override fun approximateCapturedTypes() = false
+ }.buildSubstitutor()
+
+ val substitutionMap: Map<TypeConstructor, TypeProjection> = constraintSystem.typeVariables
+ .map { it.originalTypeParameter }
+ .associateBy(
+ keySelector = { it.typeConstructor },
+ valueTransform = { parameterDescriptor ->
+ val typeProjection = TypeProjectionImpl(Variance.INVARIANT, parameterDescriptor.defaultType)
+ val substitutedProjection = substitutorToKeepCapturedTypes.substitute(typeProjection)
+ substitutedProjection?.takeUnless { ErrorUtils.containsUninferredTypeVariable(it.type) } ?: typeProjection
+ })
+ return TypeConstructorSubstitution.createByConstructorsMap(substitutionMap, approximateCapturedTypes = true).buildSubstitutor()
+ }
+}
+
+
+internal fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection<TypeParameterDescriptor>): Boolean {
+ return freeParameters.any { parameter ->
+ val type = parameter.defaultType
+ val substituted1 = this[type] ?: return@any false
+ val substituted2 = other[type] ?: return@any false
+ !StrictEqualityTypeChecker.strictEqualTypes(
+ substituted1.type.unwrap(),
+ substituted2.type.unwrap()
+ ) || substituted1.projectionKind != substituted2.projectionKind
+ }
+} \ No newline at end of file
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt
new file mode 100644
index 00000000..d5c4b745
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt
@@ -0,0 +1,30 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+package org.jetbrains.kotlin.resolve.lazy
+
+import org.jetbrains.kotlin.resolve.BindingTraceFilter
+
+internal enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter, val doControlFlowAnalysis: Boolean, val resolveAdditionals: Boolean = true) {
+ // All body statements are analyzed, diagnostics included
+ FULL(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true),
+
+ // Analyzes only dependent statements, including all declaration statements (difference from PARTIAL_WITH_CFA)
+ PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true),
+
+ // Analyzes only dependent statements, diagnostics included
+ PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true),
+
+ // Analyzes only dependent statements, performs control flow analysis (mostly needed for isUsedAsExpression / AsStatement)
+ PARTIAL_WITH_CFA(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true),
+
+ // Analyzes only dependent statements, including only used declaration statements, does not perform control flow analysis
+ PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false),
+
+ // Resolve mode to resolve only the element itself without the additional elements (annotation resolve would not lead to function resolve or default parameters)
+ PARTIAL_NO_ADDITIONAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false, resolveAdditionals = false)
+ ;
+
+ fun doesNotLessThan(other: BodyResolveMode): Boolean {
+ return this <= other && this.bindingTraceFilter.includesEverythingIn(other.bindingTraceFilter)
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000..ceff7e6c
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-descriptors-ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+org.jetbrains.dokka.analysis.kotlin.descriptors.ide.IdeDescriptorAnalysisPlugin