Fix regression of sample resolution in library sources
Use hack to answer package questions #KT-17448 fixed
This commit is contained in:
+89
-16
@@ -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<String>): Collection<DeclarationDescriptor> {
|
||||
|
||||
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<PropertyDescriptor> = shouldNotBeCalled()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> = shouldNotBeCalled()
|
||||
|
||||
override fun getFunctionNames(): Set<Name> = shouldNotBeCalled()
|
||||
|
||||
override fun getVariableNames(): Set<Name> = 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<DeclarationDescriptor>
|
||||
= (getClassesByNameFilter(nameFilter)
|
||||
+ getFunctionsByNameFilter(nameFilter)
|
||||
+ getSubpackages(nameFilter)).filterNotNull().toList()
|
||||
|
||||
}
|
||||
override val module: ModuleDescriptor
|
||||
get() = shouldNotBeCalled()
|
||||
override val fragments: List<PackageFragmentDescriptor>
|
||||
get() = shouldNotBeCalled()
|
||||
|
||||
override fun getOriginal() = this
|
||||
|
||||
override fun getName(): Name = fqName.shortName()
|
||||
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R = shouldNotBeCalled()
|
||||
|
||||
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) = shouldNotBeCalled()
|
||||
|
||||
override val annotations = Annotations.EMPTY
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user