KDocCompletionContributor code review: use resolution facade instead of KotlinCodeAnalyzer; inherit CompletionSessionBase

This commit is contained in:
Dmitry Jemerov
2015-04-08 18:07:25 +02:00
parent 4f412f77d1
commit 2aba59cbec
3 changed files with 37 additions and 41 deletions
@@ -20,12 +20,13 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.references.JetMultiReference
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
@@ -33,12 +34,9 @@ import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.utils.Printer
public class KDocReference(element: KDocName): JetMultiReference<KDocName>(element) {
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val cacheService = KotlinCacheService.getInstance(getElement().getProject())
val session = cacheService.getLazyResolveSession(getElement())
val declaration = getElement().getContainingDoc().getOwner()
if (declaration == null) {
return arrayListOf()
@@ -48,7 +46,10 @@ public class KDocReference(element: KDocName): JetMultiReference<KDocName>(eleme
return arrayListOf()
}
val kdocLink = getElement().getStrictParentOfType<KDocLink>()!!
return resolveKDocLink(session, declarationDescriptor, kdocLink.getTagIfSubject(), getElement().getQualifiedName())
return resolveKDocLink(getElement().getResolutionFacade(),
declarationDescriptor,
kdocLink.getTagIfSubject(),
getElement().getQualifiedName())
}
override fun getRangeInElement(): TextRange = getElement().getNameTextRange()
@@ -65,7 +66,7 @@ public class KDocReference(element: KDocName): JetMultiReference<KDocName>(eleme
override fun getCanonicalText(): String = getElement().getNameText()
}
public fun resolveKDocLink(session: KotlinCodeAnalyzer,
public fun resolveKDocLink(resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
fromSubjectOfTag: KDocTag?,
qualifiedName: List<String>): Collection<DeclarationDescriptor> {
@@ -75,7 +76,7 @@ public fun resolveKDocLink(session: KotlinCodeAnalyzer,
// Try to find a matching local descriptor (parameter or type parameter) first.
if (qualifiedName.size() == 1) {
val localResult = resolveInLocalScope(fromDescriptor, qualifiedName.single(), session)
val localResult = resolveInLocalScope(fromDescriptor, qualifiedName.single(), resolutionFacade)
if (!localResult.isEmpty()) {
return localResult
}
@@ -84,7 +85,7 @@ public fun resolveKDocLink(session: KotlinCodeAnalyzer,
var result: Collection<DeclarationDescriptor> = listOf(fromDescriptor)
qualifiedName.forEach { nameComponent ->
if (result.size() != 1) return listOf()
val scope = getResolutionScope(session, result.first())
val scope = getResolutionScope(resolutionFacade, result.first())
result = scope.getDescriptors().filter { it.getName().asString() == nameComponent }
}
@@ -93,8 +94,8 @@ public fun resolveKDocLink(session: KotlinCodeAnalyzer,
private fun resolveInLocalScope(fromDescriptor: DeclarationDescriptor,
name: String,
session: KotlinCodeAnalyzer): List<DeclarationDescriptor> {
val scope = getResolutionScope(session, fromDescriptor)
resolutionFacade: ResolutionFacade): List<DeclarationDescriptor> {
val scope = getResolutionScope(resolutionFacade, fromDescriptor)
return scope.getDescriptors().filter {
it.getName().asString() == name && it.getContainingDeclaration() == fromDescriptor
}
@@ -148,7 +149,7 @@ private fun getClassInnerScope(outerScope: JetScope, descriptor: ClassDescriptor
return classScope
}
public fun getResolutionScope(session: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor): JetScope {
public fun getResolutionScope(resolutionFacade: ResolutionFacade, descriptor: DeclarationDescriptor): JetScope {
return when (descriptor) {
is PackageFragmentDescriptor ->
getPackageInnerScope(descriptor)
@@ -157,31 +158,31 @@ public fun getResolutionScope(session: KotlinCodeAnalyzer, descriptor: Declarati
descriptor.getMemberScope()
is ClassDescriptor ->
getClassInnerScope(getOuterScope(descriptor, session), descriptor)
getClassInnerScope(getOuterScope(descriptor, resolutionFacade), descriptor)
is FunctionDescriptor ->
FunctionDescriptorUtil.getFunctionInnerScope(getOuterScope(descriptor, session),
FunctionDescriptorUtil.getFunctionInnerScope(getOuterScope(descriptor, resolutionFacade),
descriptor, RedeclarationHandler.DO_NOTHING)
is PropertyDescriptor ->
JetScopeUtils.getPropertyDeclarationInnerScope(descriptor,
getOuterScope(descriptor, session),
getOuterScope(descriptor, resolutionFacade),
RedeclarationHandler.DO_NOTHING)
is DeclarationDescriptorNonRoot ->
getOuterScope(descriptor, session)
getOuterScope(descriptor, resolutionFacade)
else -> throw IllegalArgumentException("Cannot find resolution scope for root $descriptor")
}
}
private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, session: KotlinCodeAnalyzer): JetScope {
private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, resolutionFacade: ResolutionFacade): JetScope {
val parent = descriptor.getContainingDeclaration()
if (parent is PackageFragmentDescriptor) {
val containingFile = (descriptor.getSource() as? PsiSourceElement)?.psi?.getContainingFile() as? JetFile
if (containingFile != null) {
return session.getScopeProvider().getFileScope(containingFile)
return resolutionFacade.getFileTopLevelScope(containingFile)
}
}
return getResolutionScope(session, parent)
return getResolutionScope(resolutionFacade, parent)
}
@@ -57,46 +57,43 @@ class KDocCompletionContributor(): CompletionContributor() {
object KDocNameCompletionProvider: CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
KDocNameCompletionSession(parameters, result).complete()
}
}
class KDocNameCompletionSession(parameters: CompletionParameters,
resultSet: CompletionResultSet): CompletionSessionBase(CompletionSessionConfiguration(parameters), parameters, resultSet) {
override fun doComplete() {
val position = parameters.getPosition().getParentOfType<KDocName>(false) ?: return
val declaration = position.getContainingDoc().getOwner() ?: return
val bindingContext = declaration.analyze()
val kdocLink = position.getStrictParentOfType<KDocLink>()!!
val declarationDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
if (kdocLink.getTagIfSubject()?.knownTag == KDocKnownTag.PARAM) {
addParamCompletions(position, declarationDescriptor, result)
addParamCompletions(position, declarationDescriptor)
} else {
val session = KotlinCacheService.getInstance(parameters.getPosition().getProject()).getLazyResolveSession(position)
addLinkCompletions(session, position, declarationDescriptor, result)
addLinkCompletions(declarationDescriptor)
}
}
private fun addParamCompletions(position: KDocName,
declarationDescriptor: DeclarationDescriptor,
result: CompletionResultSet) {
declarationDescriptor: DeclarationDescriptor) {
val section = position.getContainingSection()
val documentedParameters = section.findTagsByName("param").map { it.getSubjectName() }.toSet()
val descriptors = getParamDescriptors(declarationDescriptor)
.filter { it.getName().asString() !in documentedParameters }
val resolutionFacade = position.getResolutionFacade()
val factory = LookupElementFactory(listOf())
descriptors.forEach {
result.addElement(factory.createLookupElement(resolutionFacade, it, false))
resultSet.addElement(lookupElementFactory.createLookupElement(resolutionFacade, it, false))
}
}
private fun addLinkCompletions(session: KotlinCodeAnalyzer,
position: KDocName,
declarationDescriptor: DeclarationDescriptor,
result: CompletionResultSet) {
val scope = getResolutionScope(session, declarationDescriptor)
val resolutionFacade = position.getResolutionFacade()
val factory = LookupElementFactory(listOf())
scope.getAllDescriptors().forEach {
val element = factory.createLookupElement(resolutionFacade, it, false)
result.addElement(object: LookupElementDecorator<LookupElement>(element) {
private fun addLinkCompletions(declarationDescriptor: DeclarationDescriptor) {
val scope = getResolutionScope(resolutionFacade, declarationDescriptor)
scope.getDescriptors(nameFilter = {name -> prefixMatcher.prefixMatches(name.asString())}).forEach {
val element = lookupElementFactory.createLookupElement(resolutionFacade, it, false)
resultSet.addElement(object: LookupElementDecorator<LookupElement>(element) {
override fun handleInsert(context: InsertionContext?) {
// don't insert any qualified name here
// insert only plain name here, no qualifier/parentheses/etc.
}
})
}
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.kdoc.KDocFinder;
import org.jetbrains.kotlin.idea.kdoc.KDocRenderer;
import org.jetbrains.kotlin.idea.kdoc.KdocPackage;
import org.jetbrains.kotlin.idea.project.ResolveSessionForBodies;
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag;
import org.jetbrains.kotlin.psi.JetDeclaration;
import org.jetbrains.kotlin.psi.JetElement;
@@ -130,7 +129,6 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider
JetElement jetElement = (JetElement) context;
Project project = psiManager.getProject();
KotlinCacheService cacheService = KotlinCacheService.getInstance(project);
ResolveSessionForBodies session = cacheService.getLazyResolveSession(jetElement);
ResolutionFacade facade = cacheService.getResolutionFacade(Collections.singletonList(jetElement));
BindingContext bindingContext = facade.analyze(jetElement, BodyResolveMode.PARTIAL);
DeclarationDescriptor contextDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, context);
@@ -138,7 +136,7 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider
return null;
}
Collection<DeclarationDescriptor> descriptors =
KdocPackage.resolveKDocLink(session, contextDescriptor, null, StringUtil.split(link, ","));
KdocPackage.resolveKDocLink(facade, contextDescriptor, null, StringUtil.split(link, ","));
if (!descriptors.isEmpty()) {
DeclarationDescriptor target = descriptors.iterator().next();
if (target instanceof DeclarationDescriptorWithSource) {