From 0cf3cdb01d2a48c8dd414d28b38cc1808da9d4f6 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 20 Aug 2014 15:31:29 +0400 Subject: [PATCH] Introduce SubpackagesIndexService In memory cache which provides faster response to getSubpackages() queries --- .../jet/lang/resolve/name/FqNamesUtil.kt | 12 --- .../plugin/stubindex/PackageIndexUtil.java | 21 +---- .../stubindex/SubpackagesIndexService.kt | 81 +++++++++++++++++++ idea/src/META-INF/plugin.xml | 3 + 4 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/SubpackagesIndexService.kt diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt index c1cbb026f10..baa9fed928d 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt @@ -56,18 +56,6 @@ public fun FqName.tail(headFQN: FqName): FqName { } } -/** - * Add one segment of nesting to given qualified name according to the full qualified name. - * - * @param fullFQN - * @return qualified name with one more segment or null if fqn is not head part of fullFQN or there's no additional segment. - */ -public fun FqName.plusOneSegment(fullFQN: FqName): FqName? { - if (!isParent(fullFQN) || fullFQN == this) return null - - return child(fullFQN.tail(this).pathSegments().first!!) -} - public fun FqName.isImported(importPath: ImportPath, skipAliasedImports: Boolean = true): Boolean { return when { skipAliasedImports && importPath.hasAlias() -> false diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/PackageIndexUtil.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/PackageIndexUtil.java index 38fb2d2c8cd..882438b4cdf 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/PackageIndexUtil.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/PackageIndexUtil.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.stubindex; -import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.search.GlobalSearchScope; @@ -25,10 +24,8 @@ import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.name.NamePackage; import java.util.Collection; -import java.util.Set; public final class PackageIndexUtil { @NotNull @@ -37,23 +34,7 @@ public final class PackageIndexUtil { @NotNull GlobalSearchScope scope, @NotNull Project project ) { - Collection files = JetAllPackagesIndex.getInstance().get(packageFqName.asString(), project, scope); - - Set result = Sets.newHashSet(); - for (JetFile file : files) { - FqName fqName = file.getPackageFqName(); - - assert NamePackage.isSubpackageOf(fqName, packageFqName) : - "Registered package is not a subpackage of actually declared package:\n" + - "in index: " + packageFqName + "\n" + - "declared: " + fqName; - FqName subpackage = NamePackage.plusOneSegment(packageFqName, fqName); - if (subpackage != null) { - result.add(subpackage); - } - } - - return result; + return SubpackagesIndexService.OBJECT$.getInstance(project).getSubpackages(packageFqName, scope); } @NotNull diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/SubpackagesIndexService.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/SubpackagesIndexService.kt new file mode 100644 index 00000000000..17cc44c25fd --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/SubpackagesIndexService.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.stubindex + +import com.intellij.openapi.project.Project +import org.jetbrains.jet.lang.resolve.name.FqName +import com.intellij.psi.search.GlobalSearchScope +import java.util.HashSet +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.util.containers.MultiMap +import org.jetbrains.jet.lang.resolve.name.Name +import com.intellij.openapi.components.ServiceManager + +public class SubpackagesIndexService(private val project: Project) { + + private val cachedValue = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result( + SubpackagesIndex(JetExactPackagesIndex.getInstance().getAllKeys(project)), + PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) + }, + false + ) + + public inner class SubpackagesIndex(allPackageFqNames: Collection) { + // a map from any existing package (in kotlin) to a set of subpackages (not necessarily direct) containing files + private val fqNameByPrefix = MultiMap.createSet(); + + { + for (fqNameAsString in allPackageFqNames) { + val fqName = FqName(fqNameAsString) + var prefix = fqName + while (!prefix.isRoot()) { + prefix = prefix.parent() + fqNameByPrefix.putValue(prefix, fqName) + } + } + } + + public fun getSubpackages(fqName: FqName, scope: GlobalSearchScope): Collection { + val possibleFilesFqNames = fqNameByPrefix[fqName] + val existingSubPackagesShortNames = HashSet() + val len = fqName.pathSegments().size + for (filesFqName in possibleFilesFqNames) { + val candidateSubPackageShortName = filesFqName.pathSegments()[len] + if (candidateSubPackageShortName in existingSubPackagesShortNames) { + continue + } + //TODO: better check + val existsInThisScope = !JetExactPackagesIndex.getInstance().get(filesFqName.asString(), project, scope).isEmpty() + if (existsInThisScope) { + existingSubPackagesShortNames.add(candidateSubPackageShortName) + } + } + + return existingSubPackagesShortNames.map { fqName.child(it) } + } + } + + class object { + public fun getInstance(project: Project): SubpackagesIndex { + return ServiceManager.getService(project, javaClass())!!.cachedValue.getValue()!! + } + } +} \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index e3f3d3c98bf..4c4fdefca56 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -163,6 +163,9 @@ + +