diff options
Diffstat (limited to 'subprojects')
23 files changed, 1239 insertions, 72 deletions
diff --git a/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api b/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api index 6c642ad6..0ad66c33 100644 --- a/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api +++ b/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api @@ -55,7 +55,7 @@ public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/ } public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment : com/intellij/openapi/Disposable { - public fun <init> (Lorg/jetbrains/kotlin/cli/common/messages/MessageCollector;Lorg/jetbrains/dokka/Platform;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService;)V + public fun <init> (Lorg/jetbrains/kotlin/cli/common/messages/MessageCollector;Lorg/jetbrains/dokka/Platform;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService;)V public fun dispose ()V } diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt index 89ae8810..c0a0212a 100644 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt +++ b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt @@ -48,7 +48,6 @@ internal fun createAnalysisContext( val analysisEnvironment = AnalysisEnvironment( DokkaMessageCollector(context.logger), sourceSet.analysisPlatform, - context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { compilerExtensionPointProvider }, context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { mockApplicationHack }, context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { klibService }, ).apply { diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt index 611d1325..0fb07412 100644 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt +++ b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt @@ -91,7 +91,6 @@ internal const val JAR_SEPARATOR = "!/" class AnalysisEnvironment( private val messageCollector: MessageCollector, internal val analysisPlatform: Platform, - private val compilerExtensionPointProvider: CompilerExtensionPointProvider, private val mockApplicationHack: MockApplicationHack, private val kLibService: KLibService, ) : Disposable { @@ -148,9 +147,6 @@ class AnalysisEnvironment( CustomJavadocTagProvider { emptyList() } ) - compilerExtensionPointProvider.get().forEach { extension -> - registerExtensionPoint(extension.extensionDescriptor, extension.extensions, this) - } return environment } diff --git a/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts b/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts index 79777256..363f0475 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts +++ b/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts @@ -8,14 +8,6 @@ dependencies { implementation(projects.subprojects.analysisKotlinDescriptors.compiler) - api(libs.kotlin.idePlugin.common) - api(libs.kotlin.idePlugin.idea) - api(libs.kotlin.idePlugin.core) - api(libs.kotlin.idePlugin.native) - - // TODO [beresnev] needed for CommonIdePlatformKind, describe - implementation(libs.kotlin.jps.common) - // TODO [beresnev] get rid of it compileOnly(libs.kotlinx.coroutines.core) } diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt index e2253b99..efcd7240 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt +++ b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt @@ -108,6 +108,7 @@ internal class DokkaResolutionFacade( 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) } diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeCompilerExtensionPointProvider.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeCompilerExtensionPointProvider.kt deleted file mode 100644 index 73d908e9..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeCompilerExtensionPointProvider.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerExtensionPointProvider -import org.jetbrains.kotlin.caches.resolve.CommonPlatformKindResolution -import org.jetbrains.kotlin.caches.resolve.IdePlatformKindResolution -import org.jetbrains.kotlin.caches.resolve.JsPlatformKindResolution -import org.jetbrains.kotlin.caches.resolve.JvmPlatformKindResolution -import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor -import org.jetbrains.kotlin.ide.konan.NativePlatformKindResolution -import org.jetbrains.kotlin.platform.IdePlatformKind -import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind -import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind -import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind -import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind - -internal class IdeCompilerExtensionPointProvider : CompilerExtensionPointProvider { - override fun get(): List<CompilerExtensionPointProvider.CompilerExtensionPoint> { - - @Suppress("UNCHECKED_CAST") - val idePlatformKind = CompilerExtensionPointProvider.CompilerExtensionPoint( - ApplicationExtensionDescriptor( - "org.jetbrains.kotlin.idePlatformKind", - IdePlatformKind::class.java - ) as ApplicationExtensionDescriptor<Any>, - listOf( - CommonIdePlatformKind, - JvmIdePlatformKind, - JsIdePlatformKind, - NativeIdePlatformKind - ) - ) - - @Suppress("UNCHECKED_CAST") - val resolution = CompilerExtensionPointProvider.CompilerExtensionPoint( - IdePlatformKindResolution as ApplicationExtensionDescriptor<Any>, - listOf( - CommonPlatformKindResolution(), - JvmPlatformKindResolution(), - JsPlatformKindResolution(), - NativePlatformKindResolution() - ) - ) - - return listOf(idePlatformKind, resolution) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt index 930e4a3f..18c7dc55 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt +++ b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt @@ -21,10 +21,6 @@ class IdeDescriptorAnalysisPlugin : DokkaPlugin() { plugin<CompilerDescriptorAnalysisPlugin>().klibService providing { IdeKLibService() } } - internal val ideCompilerExtensionPointProvider by extending { - plugin<CompilerDescriptorAnalysisPlugin>().compilerExtensionPointProvider providing { IdeCompilerExtensionPointProvider() } - } - internal val ideApplicationHack by extending { plugin<CompilerDescriptorAnalysisPlugin>().mockApplicationHack providing { IdeMockApplicationHack() } } diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt index bc591151..f520be6d 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt +++ b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt @@ -2,11 +2,19 @@ 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.search.usagesSearch.descriptor +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 this.descriptor + return if (this is KtParameter) this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) else this.resolveToDescriptorIfAny( + BodyResolveMode.FULL + ) } + } + + diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt index c3422f56..a0416375 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt +++ b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt @@ -5,10 +5,11 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider -import org.jetbrains.kotlin.idea.klib.getCompatibilityInfo +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 { @@ -25,6 +26,29 @@ internal class IdeKLibService : KLibService { } override fun isAnalysisCompatible(kotlinLibrary: KotlinLibrary): Boolean { - return kotlinLibrary.getCompatibilityInfo().isCompatible + 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 + ) +}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt index d0d217f6..c5bb7fda 100644 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt +++ b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt @@ -10,6 +10,7 @@ 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 @@ -20,11 +21,11 @@ internal class IdePluginKDocFinder( ) : KDocFinder { override fun KtElement.findKDoc(): KDocTag? { - return this.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) } + return this.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) }?.contentTag } override fun DeclarationDescriptor.find(descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement?): KDocTag? { - return this.findKDoc(descriptorToPsi) + return this.findKDoc(descriptorToPsi)?.contentTag } override fun resolveKDocLink( @@ -42,7 +43,8 @@ internal class IdePluginKDocFinder( resolutionFacade = facadeAnalysisContext.facade, fromDescriptor = fromDescriptor, fromSubjectOfTag = null, - qualifiedName = qualifiedName.split('.') + qualifiedName = qualifiedName.split('.'), + contextElement = fromDescriptor.findPsi() ) } } diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt b/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/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/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt b/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/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/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt b/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/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/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt b/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/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/subprojects/analysis-kotlin-descriptors/ide/src/main/ko |
