diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/IdeSampleResolutionService.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/IdeSampleResolutionService.kt index fa3828dfbfd..0a5aab47622 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/IdeSampleResolutionService.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/IdeSampleResolutionService.kt @@ -18,43 +18,116 @@ package org.jetbrains.kotlin.idea.kdoc import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.collectAllModuleInfosFromIdeaModel -import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.stubindex.KotlinClassShortNameIndex -import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex +import org.jetbrains.kotlin.idea.stubindex.* +import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.isChildOf +import org.jetbrains.kotlin.name.isOneSegmentFQN import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.utils.Printer class IdeSampleResolutionService(val project: Project) : SampleResolutionService { override fun resolveSample(context: BindingContext, fromDescriptor: DeclarationDescriptor, resolutionFacade: ResolutionFacade, qualifiedName: List): Collection { - val allScope = GlobalSearchScope.projectScope(project) + val scope = KotlinSourceFilterScope.projectAndLibrariesSources(GlobalSearchScope.projectScope(project), project) val shortName = qualifiedName.lastOrNull() ?: return emptyList() val targetFqName = FqName.fromSegments(qualifiedName) - val functions = KotlinFunctionShortNameIndex.getInstance().get(shortName, project, allScope).asSequence() - val classes = KotlinClassShortNameIndex.getInstance().get(shortName, project, allScope).asSequence() + val functions = KotlinFunctionShortNameIndex.getInstance().get(shortName, project, scope).asSequence() + val classes = KotlinClassShortNameIndex.getInstance().get(shortName, project, scope).asSequence() val descriptors = (functions + classes) .filter { it.fqName == targetFqName } .map { it.resolveToDescriptor(BodyResolveMode.PARTIAL) } // TODO Filter out not visible due dependencies config descriptors .toList() - if(descriptors.isNotEmpty()) + if (descriptors.isNotEmpty()) return descriptors - val packageDescriptors = collectAllModuleInfosFromIdeaModel(project) - .asSequence() - .map { resolutionFacade.findModuleDescriptor(it)?.getPackage(targetFqName) } - .filterNotNull() - .filterNot { it.isEmpty() } - - return packageDescriptors.toList() + if (!targetFqName.isRoot && PackageIndexUtil.packageExists(targetFqName, scope, project)) + return listOf(GlobalSyntheticPackageViewDescriptor(targetFqName, project, scope)) + return emptyList() } +} + +private fun shouldNotBeCalled(): Nothing = throw UnsupportedOperationException("Synthetic PVD for KDoc link resolution") + +private class GlobalSyntheticPackageViewDescriptor(override val fqName: FqName, private val project: Project, private val scope: GlobalSearchScope) : PackageViewDescriptor { + override fun getContainingDeclaration(): PackageViewDescriptor? = + if (fqName.isOneSegmentFQN()) null else GlobalSyntheticPackageViewDescriptor(fqName.parent(), project, scope) + + + override val memberScope: MemberScope = object : MemberScope { + + override fun getContributedVariables(name: Name, location: LookupLocation): Collection = shouldNotBeCalled() + + override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = shouldNotBeCalled() + + override fun getFunctionNames(): Set = shouldNotBeCalled() + + override fun getVariableNames(): Set = shouldNotBeCalled() + + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = shouldNotBeCalled() + + override fun printScopeStructure(p: Printer) { + p.printIndent() + p.print("GlobalSyntheticPackageViewDescriptorMemberScope (INDEX)") + } + + + fun getClassesByNameFilter(nameFilter: (Name) -> Boolean) = KotlinFullClassNameIndex.getInstance() + .getAllKeys(project) + .asSequence() + .filter { it.startsWith(fqName.asString()) } + .map(::FqName) + .filter { it.isChildOf(fqName) } + .filter { nameFilter(it.shortName()) } + .flatMap { KotlinFullClassNameIndex.getInstance()[it.asString(), project, scope].asSequence() } + .map { it.resolveToDescriptorIfAny() } + + fun getFunctionsByNameFilter(nameFilter: (Name) -> Boolean) = KotlinTopLevelFunctionFqnNameIndex.getInstance() + .getAllKeys(project) + .asSequence() + .filter { it.startsWith(fqName.asString()) } + .map(::FqName) + .filter { it.isChildOf(fqName) } + .filter { nameFilter(it.shortName()) } + .flatMap { KotlinTopLevelFunctionFqnNameIndex.getInstance()[it.asString(), project, scope].asSequence() } + .map { it.resolveToDescriptorIfAny() } + + fun getSubpackages(nameFilter: (Name) -> Boolean) = + PackageIndexUtil.getSubPackageFqNames(fqName, scope, project, nameFilter) + .map { GlobalSyntheticPackageViewDescriptor(it, project, scope) } + + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection + = (getClassesByNameFilter(nameFilter) + + getFunctionsByNameFilter(nameFilter) + + getSubpackages(nameFilter)).filterNotNull().toList() + + } + override val module: ModuleDescriptor + get() = shouldNotBeCalled() + override val fragments: List + get() = shouldNotBeCalled() + + override fun getOriginal() = this + + override fun getName(): Name = fqName.shortName() + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R = shouldNotBeCalled() + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) = shouldNotBeCalled() + + override val annotations = Annotations.EMPTY } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt index fbb00f3d577..28e155c6e22 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt @@ -101,6 +101,9 @@ class KotlinSourceFilterScope private constructor( @JvmStatic fun libraryClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, false, false, true, true, project) + @JvmStatic + fun projectAndLibrariesSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, false, false, project) + private fun create( delegate: GlobalSearchScope, includeProjectSourceFiles: Boolean,