blob: 94bf809dd43a943e08e6b35dfc31dd3b5dfea28e [file] [log] [blame]
/*
* Copyright 2000-2012 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 com.intellij.psi.impl;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.indexing.IdFilter;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Set;
public class CompositeShortNamesCache extends PsiShortNamesCache {
private final PsiShortNamesCache[] myCaches;
public CompositeShortNamesCache(Project project) {
myCaches = project.isDefault() ? new PsiShortNamesCache[0] : project.getExtensions(PsiShortNamesCache.EP_NAME);
}
@Override
@NotNull
public PsiFile[] getFilesByName(@NotNull String name) {
Merger<PsiFile> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiFile[] classes = cache.getFilesByName(name);
if (classes.length != 0) {
if (merger == null) merger = new Merger<PsiFile>();
merger.add(classes);
}
}
PsiFile[] result = merger == null ? null : merger.getResult();
return result != null ? result : PsiFile.EMPTY_ARRAY;
}
@Override
@NotNull
public String[] getAllFileNames() {
Merger<String> merger = new Merger<String>();
for (PsiShortNamesCache cache : myCaches) {
merger.add(cache.getAllFileNames());
}
String[] result = merger.getResult();
return result != null ? result : ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
@NotNull
public PsiClass[] getClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
Merger<PsiClass> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiClass[] classes = cache.getClassesByName(name, scope);
if (classes.length != 0) {
if (merger == null) merger = new Merger<PsiClass>();
merger.add(classes);
}
}
PsiClass[] result = merger == null ? null : merger.getResult();
return result != null ? result : PsiClass.EMPTY_ARRAY;
}
@Override
@NotNull
public String[] getAllClassNames() {
Merger<String> merger = new Merger<String>();
for (PsiShortNamesCache cache : myCaches) {
String[] names = cache.getAllClassNames();
merger.add(names);
}
String[] result = merger.getResult();
return result != null ? result : ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
public boolean processAllClassNames(Processor<String> processor) {
CommonProcessors.UniqueProcessor<String> uniqueProcessor = new CommonProcessors.UniqueProcessor<String>(processor);
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processAllClassNames(uniqueProcessor)) {
return false;
}
}
return true;
}
@Override
public boolean processAllClassNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processAllClassNames(processor, scope, filter)) {
return false;
}
}
return true;
}
@Override
public boolean processAllMethodNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processAllMethodNames(processor, scope, filter)) {
return false;
}
}
return true;
}
@Override
public boolean processAllFieldNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processAllFieldNames(processor, scope, filter)) {
return false;
}
}
return true;
}
@Override
public void getAllClassNames(@NotNull HashSet<String> dest) {
for (PsiShortNamesCache cache : myCaches) {
cache.getAllClassNames(dest);
}
}
@Override
@NotNull
public PsiMethod[] getMethodsByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
Merger<PsiMethod> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiMethod[] methods = cache.getMethodsByName(name, scope);
if (methods.length != 0) {
if (merger == null) merger = new Merger<PsiMethod>();
merger.add(methods);
}
}
PsiMethod[] result = merger == null ? null : merger.getResult();
return result == null ? PsiMethod.EMPTY_ARRAY : result;
}
@Override
@NotNull
public PsiMethod[] getMethodsByNameIfNotMoreThan(@NonNls @NotNull final String name, @NotNull final GlobalSearchScope scope, final int maxCount) {
Merger<PsiMethod> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiMethod[] methods = cache.getMethodsByNameIfNotMoreThan(name, scope, maxCount);
if (methods.length == maxCount) return methods;
if (methods.length != 0) {
if (merger == null) merger = new Merger<PsiMethod>();
merger.add(methods);
}
}
PsiMethod[] result = merger == null ? null : merger.getResult();
return result == null ? PsiMethod.EMPTY_ARRAY : result;
}
@NotNull
@Override
public PsiField[] getFieldsByNameIfNotMoreThan(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, int maxCount) {
Merger<PsiField> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiField[] fields = cache.getFieldsByNameIfNotMoreThan(name, scope, maxCount);
if (fields.length == maxCount) return fields;
if (fields.length != 0) {
if (merger == null) merger = new Merger<PsiField>();
merger.add(fields);
}
}
PsiField[] result = merger == null ? null : merger.getResult();
return result == null ? PsiField.EMPTY_ARRAY : result;
}
@Override
public boolean processMethodsWithName(@NonNls @NotNull String name,
@NotNull GlobalSearchScope scope,
@NotNull Processor<PsiMethod> processor) {
return processMethodsWithName(name, processor, scope, null);
}
@Override
public boolean processMethodsWithName(@NonNls @NotNull String name,
@NotNull Processor<? super PsiMethod> processor,
@NotNull GlobalSearchScope scope,
@Nullable IdFilter idFilter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processMethodsWithName(name, processor, scope, idFilter)) return false;
}
return true;
}
@Override
@NotNull
public String[] getAllMethodNames() {
Merger<String> merger = new Merger<String>();
for (PsiShortNamesCache cache : myCaches) {
merger.add(cache.getAllMethodNames());
}
String[] result = merger.getResult();
return result != null ? result : ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
public void getAllMethodNames(@NotNull HashSet<String> set) {
for (PsiShortNamesCache cache : myCaches) {
cache.getAllMethodNames(set);
}
}
@Override
@NotNull
public PsiField[] getFieldsByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
Merger<PsiField> merger = null;
for (PsiShortNamesCache cache : myCaches) {
PsiField[] classes = cache.getFieldsByName(name, scope);
if (classes.length != 0) {
if (merger == null) merger = new Merger<PsiField>();
merger.add(classes);
}
}
PsiField[] result = merger == null ? null : merger.getResult();
return result == null ? PsiField.EMPTY_ARRAY : result;
}
@Override
@NotNull
public String[] getAllFieldNames() {
Merger<String> merger = null;
for (PsiShortNamesCache cache : myCaches) {
String[] classes = cache.getAllFieldNames();
if (classes.length != 0) {
if (merger == null) merger = new Merger<String>();
merger.add(classes);
}
}
String[] result = merger == null ? null : merger.getResult();
return result == null ? ArrayUtil.EMPTY_STRING_ARRAY : result;
}
@Override
public void getAllFieldNames(@NotNull HashSet<String> set) {
for (PsiShortNamesCache cache : myCaches) {
cache.getAllFieldNames(set);
}
}
@Override
public boolean processFieldsWithName(@NotNull String key,
@NotNull Processor<? super PsiField> processor,
@NotNull GlobalSearchScope scope,
@Nullable IdFilter filter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processFieldsWithName(key, processor, scope, filter)) return false;
}
return true;
}
@Override
public boolean processClassesWithName(@NotNull String key,
@NotNull Processor<? super PsiClass> processor,
@NotNull GlobalSearchScope scope,
@Nullable IdFilter filter) {
for (PsiShortNamesCache cache : myCaches) {
if (!cache.processClassesWithName(key, processor, scope, filter)) return false;
}
return true;
}
private static class Merger<T> {
private T[] mySingleItem;
private Set<T> myAllItems;
public void add(@NotNull T[] items) {
if (items.length == 0) return;
if (mySingleItem == null) {
mySingleItem = items;
return;
}
if (myAllItems == null) {
T[] elements = mySingleItem;
myAllItems = ContainerUtil.addAll(new THashSet<T>(elements.length), elements);
}
ContainerUtil.addAll(myAllItems, items);
}
public T[] getResult() {
if (myAllItems == null) return mySingleItem;
return myAllItems.toArray(mySingleItem);
}
}
@SuppressWarnings({"HardCodedStringLiteral"})
@Override
public String toString() {
return "Composite cache: " + Arrays.asList(myCaches);
}
}