Optimization to not fetch objects in separate pass

This commit is contained in:
Valentin Kipyatkov
2014-11-03 12:25:37 +03:00
parent 19f9f27675
commit c040c53f51
3 changed files with 49 additions and 32 deletions
@@ -42,6 +42,8 @@ public class KotlinIndicesHelper(private val project: Project,
private val resolveSession: ResolveSessionForBodies,
private val scope: GlobalSearchScope,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
private val moduleDescriptor = resolveSession.getModuleDescriptor()
public fun getTopLevelObjects(nameFilter: (String) -> Boolean): Collection<ClassDescriptor> {
val allObjectNames = JetTopLevelObjectShortNameIndex.getInstance().getAllKeys(project).stream() +
JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, scope).stream()
@@ -57,13 +59,13 @@ public class KotlinIndicesHelper(private val project: Project,
val topObjects = JetTopLevelObjectShortNameIndex.getInstance().get(name, project, scope)
for (objectDeclaration in topObjects) {
val fqName = objectDeclaration.getFqName() ?: error("Local object declaration in JetTopLevelShortObjectNameIndex:${objectDeclaration.getText()}")
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession.getModuleDescriptor(), fqName, ResolveSessionUtils.SINGLETON_FILTER))
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(moduleDescriptor, fqName, ResolveSessionUtils.SINGLETON_FILTER))
}
for (psiClass in JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, scope)) {
val qualifiedName = psiClass.getQualifiedName()
if (qualifiedName != null) {
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession.getModuleDescriptor(), FqName(qualifiedName), ResolveSessionUtils.SINGLETON_FILTER))
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(moduleDescriptor, FqName(qualifiedName), ResolveSessionUtils.SINGLETON_FILTER))
}
}
@@ -99,7 +101,7 @@ public class KotlinIndicesHelper(private val project: Project,
.toSet()
for (affectedPackage in affectedPackages) {
val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage)
val packageDescriptor = moduleDescriptor.getPackage(affectedPackage)
?: error("There's a function in stub index with invalid package: $affectedPackage")
addAll(packageDescriptor.getMemberScope().getFunctions(identifier))
}
@@ -115,7 +117,7 @@ public class KotlinIndicesHelper(private val project: Project,
.toSet()
for (affectedPackage in affectedPackages) {
val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage)
val packageDescriptor = moduleDescriptor.getPackage(affectedPackage)
?: error("There's a property in stub index with invalid package: $affectedPackage")
addAll(packageDescriptor.getMemberScope().getProperties(identifier))
}
@@ -153,7 +155,7 @@ public class KotlinIndicesHelper(private val project: Project,
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
return matchingFqNames.flatMap {
findSuitableExtensions(it, receiverValue, dataFlowInfo, isInfixCall, resolutionScope, resolveSession.getModuleDescriptor(), bindingContext)
findSuitableExtensions(it, receiverValue, dataFlowInfo, isInfixCall, resolutionScope, moduleDescriptor, bindingContext)
}
}
else {
@@ -162,7 +164,7 @@ public class KotlinIndicesHelper(private val project: Project,
val result = HashSet<CallableDescriptor>()
for (receiver in resolutionScope.getImplicitReceiversHierarchy()) {
matchingFqNames.flatMapTo(result) {
findSuitableExtensions(it, receiver.getValue(), dataFlowInfo, false, resolutionScope, resolveSession.getModuleDescriptor(), bindingContext)
findSuitableExtensions(it, receiver.getValue(), dataFlowInfo, false, resolutionScope, moduleDescriptor, bindingContext)
}
}
return result
@@ -190,29 +192,30 @@ public class KotlinIndicesHelper(private val project: Project,
ExpressionTypingUtils.checkIsExtensionCallable(receiverValue, it, isInfixCall, bindingContext, dataFlowInfo) }
}
public fun getClassDescriptors(nameFilter: (String) -> Boolean): Collection<ClassDescriptor> {
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
return JetFullClassNameIndex.getInstance().getAllKeys(project).stream()
.map { FqName(it) }
.filter { nameFilter(it.shortName().asString()) }
.toList()
.flatMap { getClassDescriptorsByFQName(it) }
.flatMap { getClassDescriptorsByFQName(it, kindFilter) }
}
private fun getClassDescriptorsByFQName(classFQName: FqName): Collection<ClassDescriptor> {
val jetClassOrObjects = JetFullClassNameIndex.getInstance().get(classFQName.asString(), project, scope)
private fun getClassDescriptorsByFQName(classFQName: FqName, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
val declarations = JetFullClassNameIndex.getInstance()[classFQName.asString(), project, scope]
if (jetClassOrObjects.isEmpty()) {
if (declarations.isEmpty()) {
// This fqn is absent in caches, dead or not in scope
return listOf()
}
// Note: Can't search with psi element as analyzer could be built over temp files
return ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession.getModuleDescriptor(), classFQName).filter(visibilityFilter)
return ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(moduleDescriptor, classFQName) { kindFilter(it.getKind()) }
.filter(visibilityFilter)
}
private fun findTopLevelCallables(fqName: FqName, context: JetExpression, jetScope: JetScope): Collection<CallableDescriptor> {
val importDirective = JetPsiFactory(context.getProject()).createImportDirective(ImportPath(fqName, false))
val allDescriptors = analyzeImportReference(importDirective, jetScope, BindingTraceContext(), resolveSession.getModuleDescriptor())
val allDescriptors = analyzeImportReference(importDirective, jetScope, BindingTraceContext(), moduleDescriptor)
return allDescriptors.filterIsInstance(javaClass<CallableDescriptor>()).filter { it.getExtensionReceiverParameter() == null }
}
@@ -31,18 +31,20 @@ import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
class TypesCompletion(val parameters: CompletionParameters,
val resolveSession: ResolveSessionForBodies,
val prefixMatcher: PrefixMatcher,
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
fun addAllTypes(result: LookupElementsCollector) {
result.addDescriptorElements(KotlinBuiltIns.getInstance().getNonPhysicalClasses().filter { prefixMatcher.prefixMatches(it.getName().asString()) },
suppressAutoInsertion = true)
class AllClassesCompletion(val parameters: CompletionParameters,
val resolveSession: ResolveSessionForBodies,
val prefixMatcher: PrefixMatcher,
val kindFilter: (ClassKind) -> Boolean,
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
fun collect(result: LookupElementsCollector) {
val builtIns = KotlinBuiltIns.getInstance().getNonPhysicalClasses().filter { kindFilter(it.getKind()) && prefixMatcher.prefixMatches(it.getName().asString()) }
result.addDescriptorElements(builtIns, suppressAutoInsertion = true)
val file = parameters.getOriginalFile()
val project = file.getProject()
val searchScope = file.getResolveScope()
result.addDescriptorElements(KotlinIndicesHelper(project, resolveSession, searchScope, visibilityFilter).getClassDescriptors { prefixMatcher.prefixMatches(it) },
val helper = KotlinIndicesHelper(project, resolveSession, searchScope, visibilityFilter)
result.addDescriptorElements(helper.getClassDescriptors({ prefixMatcher.prefixMatches(it) }, kindFilter),
suppressAutoInsertion = true)
if (!ProjectStructureUtil.isJsKotlinModule(file as JetFile)) {
@@ -60,14 +62,22 @@ class TypesCompletion(val parameters: CompletionParameters,
addLookupElementForCompiledKotlinClass(psiClass, collector)
}
else if (!JavaResolverUtils.isCompiledKotlinPackageClass(psiClass)) {
collector.addElementWithAutoInsertionSuppressed(KotlinLookupElementFactory.createLookupElementForJavaClass(psiClass))
val kind = when {
psiClass.isAnnotationType() -> ClassKind.ANNOTATION_CLASS
psiClass.isInterface() -> ClassKind.TRAIT
psiClass.isEnum() -> ClassKind.ENUM_CLASS
else -> ClassKind.CLASS
}
if (kindFilter(kind)) {
collector.addElementWithAutoInsertionSuppressed(KotlinLookupElementFactory.createLookupElementForJavaClass(psiClass))
}
}
}
})
}
private fun addLookupElementForCompiledKotlinClass(aClass: PsiClass, collector: LookupElementsCollector) {
if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) {
if (kindFilter(JetFromJavaDescriptorHelper.getCompiledClassKind(aClass))) {
val qualifiedName = aClass.getQualifiedName()
if (qualifiedName != null) {
val descriptors = ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession.getModuleDescriptor(), FqName(qualifiedName)).filter(visibilityFilter)
@@ -110,17 +110,20 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
return configuration.completeNonImportedDeclarations || prefixMatcher.getPrefix().length >= 3
}
protected fun getKotlinTopLevelDeclarations(): Collection<DeclarationDescriptor> {
val filter = { (name: String) -> prefixMatcher.prefixMatches(name) }
return indicesHelper.getTopLevelCallables(filter, jetReference!!.expression) + indicesHelper.getTopLevelObjects(filter)
protected fun getKotlinTopLevelCallables(): Collection<DeclarationDescriptor> {
return indicesHelper.getTopLevelCallables({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression)
}
protected fun getKotlinTopLevelObjects(): Collection<DeclarationDescriptor> {
return indicesHelper.getTopLevelObjects({ prefixMatcher.prefixMatches(it) })
}
protected fun getKotlinExtensions(): Collection<CallableDescriptor> {
return indicesHelper.getCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression)
}
protected fun addAllTypes() {
TypesCompletion(parameters, resolveSession, prefixMatcher, { isVisibleDescriptor(it) }).addAllTypes(collector)
protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) {
AllClassesCompletion(parameters, resolveSession, prefixMatcher, kindFilter, { isVisibleDescriptor(it) }).collect(collector)
}
}
@@ -138,7 +141,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
if (completeReference) {
if (shouldRunOnlyTypeCompletion()) {
if (configuration.completeNonImportedDeclarations) {
addAllTypes()
addAllClasses { !it.isSingleton() }
}
else {
addReferenceVariants(JetScope.TYPE or JetScope.PACKAGE)
@@ -164,8 +167,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
private fun addNonImported() {
if (shouldRunTopLevelCompletion()) {
addAllTypes()
collector.addDescriptorElements(getKotlinTopLevelDeclarations(), suppressAutoInsertion = true)
addAllClasses { it != ClassKind.ENUM_ENTRY }
collector.addDescriptorElements(getKotlinTopLevelCallables(), suppressAutoInsertion = true)
}
if (shouldRunExtensionsCompletion()) {
@@ -223,7 +226,8 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) {
if (shouldRunTopLevelCompletion()) {
getKotlinTopLevelDeclarations().forEach(processor)
getKotlinTopLevelCallables().forEach(processor)
getKotlinTopLevelObjects().forEach(processor) //TODO: shouldn't it work via inheritors search?
}
if (shouldRunExtensionsCompletion()) {