Fix regression of sample resolution in library sources

Use hack to answer package questions
 #KT-17448 fixed
This commit is contained in:
Simon Ogorodnik
2017-04-17 21:17:24 +03:00
parent 99504eb753
commit de66f76299
2 changed files with 92 additions and 16 deletions
@@ -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,