diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt index 4b8f63723f8..b2069f5ef7b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt @@ -10,12 +10,13 @@ import org.jetbrains.kotlin.analysis.api.components.KtScopeContext import org.jetbrains.kotlin.analysis.api.components.KtScopeKind import org.jetbrains.kotlin.analysis.api.scopes.KtScope import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType -import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.name.CallableId +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import kotlin.reflect.KClass @@ -82,6 +83,7 @@ internal object KDocReferenceResolver { getExtensionReceiverSymbolByThisQualifier(fqName, contextElement).ifNotEmpty { return this } (getSymbolsFromScopes(fqName, contextElement) + listOfNotNull(getPackageSymbolIfPackageExists(fqName))).ifNotEmpty { return this } getNonImportedSymbolsByFullyQualifiedName(fqName).ifNotEmpty { return this } + AdditionalKDocResolutionProvider.resolveKdocFqName(fqName, contextElement).ifNotEmpty { return this } return emptyList() } diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt index 3f5fe0c387f..f5f7e3e23de 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt +++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSource import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider +import org.jetbrains.kotlin.analysis.api.symbols.AdditionalKDocResolutionProvider import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProvider import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProviderCliImpl import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache @@ -141,15 +142,26 @@ object StandaloneProjectFactory { ) { val applicationArea = applicationEnvironment.application.extensionArea - if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return - KotlinCoreEnvironment.underApplicationLock { - if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return@underApplicationLock - CoreApplicationEnvironment.registerApplicationExtensionPoint( - ClassTypePointerFactory.EP_NAME, - ClassTypePointerFactory::class.java - ) - applicationArea.getExtensionPoint(ClassTypePointerFactory.EP_NAME) - .registerExtension(PsiClassReferenceTypePointerFactory(), applicationDisposable) + if (!applicationArea.hasExtensionPoint(AdditionalKDocResolutionProvider.EP_NAME)) { + KotlinCoreEnvironment.underApplicationLock { + if (applicationArea.hasExtensionPoint(AdditionalKDocResolutionProvider.EP_NAME)) return@underApplicationLock + CoreApplicationEnvironment.registerApplicationExtensionPoint( + AdditionalKDocResolutionProvider.EP_NAME, + AdditionalKDocResolutionProvider::class.java + ) + } + } + + if (!applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) { + KotlinCoreEnvironment.underApplicationLock { + if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return@underApplicationLock + CoreApplicationEnvironment.registerApplicationExtensionPoint( + ClassTypePointerFactory.EP_NAME, + ClassTypePointerFactory::class.java + ) + applicationArea.getExtensionPoint(ClassTypePointerFactory.EP_NAME) + .registerExtension(PsiClassReferenceTypePointerFactory(), applicationDisposable) + } } } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt new file mode 100644 index 00000000000..81270e6ed9c --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2023 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.analysis.api.symbols + +import com.intellij.openapi.extensions.ExtensionPointName +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtElement + +/** + * An extension point to provide additional symbols for a KDoc reference. KDoc link resolution will use symbols returned by this EP + * only if the real resolution was unsuccessful. You can use this EP by creating a class implementing this interface. + * For example, let's assume that you want to return symbol `fun foo() = 3` for the following KDoc resolution: + * + * ``` + * package com.example + * fun foo() = 3 + * /** + * * [this.is.not.com.example.foo] is not the above `com.example.foo`, but you want to resolve it to the above `com.example.foo`. + * */ + * fun bar() = 7 + * ``` + * + * You can create + * + * ``` + * class AdditionalKDocResolutionProviderBasedOnNameMatch : AdditionalKDocResolutionProvider { + * context(KtAnalysisSession) + * override fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection = + * contextElement.containingKtFile.declarations.filter { it.name == fqName.shortName().asString() }.map { it.getSymbol() } + * } + * ``` + */ +public interface AdditionalKDocResolutionProvider { + /** + * This function must return additional symbols for [contextElement] in KDoc. + */ + context(KtAnalysisSession) + public fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection + + public companion object { + public val EP_NAME: ExtensionPointName = + ExtensionPointName("org.jetbrains.kotlin.analysis.additionalKDocResolutionProvider") + + context(KtAnalysisSession) + public fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection = + EP_NAME.extensions.flatMap { it.resolveKdocFqName(fqName, contextElement) } + } +} \ No newline at end of file