Move KotlinPsiElementFinderImpl and add wrapper interface to avoid creating many unsupported methods

This commit is contained in:
Nikolay Krasko
2015-01-19 16:38:12 +03:00
parent 4a0e7489dd
commit f5da351e8a
2 changed files with 153 additions and 166 deletions
@@ -16,30 +16,45 @@
package org.jetbrains.kotlin.resolve.jvm;
import com.intellij.core.CoreJavaFileManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.PackageIndex;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementFinder;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.impl.file.impl.JavaFileManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.reference.SoftReference;
import com.intellij.util.CommonProcessors;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Query;
import com.intellij.util.containers.ConcurrentHashMap;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
public abstract class JavaPsiFacadeImpl {
private volatile PsiElementFinder[] myElementFinders;
public class JavaPsiFacadeImpl {
private volatile KotlinPsiElementFinderWrapper[] myElementFinders;
private volatile SoftReference<ConcurrentMap<String, PsiPackage>> myPackageCache;
private final Project myProject;
private final Project Project;
private final GlobalSearchScope searchScope;
public JavaPsiFacadeImpl(Project project) {
myProject = project;
public JavaPsiFacadeImpl(@NotNull Project project, @NotNull GlobalSearchScope searchScope) {
this.Project = project;
this.searchScope = searchScope;
}
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
@@ -53,7 +68,7 @@ public abstract class JavaPsiFacadeImpl {
return null;
}
for (PsiElementFinder finder : finders()) {
for (KotlinPsiElementFinderWrapper finder : finders()) {
PsiClass aClass = finder.findClass(qualifiedName, scope);
if (aClass != null) return aClass;
}
@@ -83,8 +98,8 @@ public abstract class JavaPsiFacadeImpl {
}
@NotNull
private PsiElementFinder[] finders() {
PsiElementFinder[] answer = myElementFinders;
private KotlinPsiElementFinderWrapper[] finders() {
KotlinPsiElementFinderWrapper[] answer = myElementFinders;
if (answer == null) {
answer = calcFinders();
myElementFinders = answer;
@@ -94,7 +109,27 @@ public abstract class JavaPsiFacadeImpl {
}
@NotNull
protected abstract PsiElementFinder[] calcFinders();
protected KotlinPsiElementFinderWrapper[] calcFinders() {
List<KotlinPsiElementFinderWrapper> elementFinders = new ArrayList<KotlinPsiElementFinderWrapper>();
elementFinders.add(new KotlinPsiElementFinderImpl(getProject()));
List<PsiElementFinder> nonKotlinFinders = KotlinPackage.filter(
getProject().getExtensions(PsiElementFinder.EP_NAME), new Function1<PsiElementFinder, Boolean>() {
@Override
public Boolean invoke(PsiElementFinder finder) {
return !(finder instanceof KotlinFinderMarker);
}
});
elementFinders.addAll(KotlinPackage.map(nonKotlinFinders, new Function1<PsiElementFinder, KotlinPsiElementFinderWrapper>() {
@Override
public KotlinPsiElementFinderWrapper invoke(PsiElementFinder finder) {
return wrap(finder);
}
}));
return elementFinders.toArray(new KotlinPsiElementFinderWrapper[elementFinders.size()]);
}
public PsiPackage findPackage(@NotNull String qualifiedName) {
ConcurrentMap<String, PsiPackage> cache = SoftReference.dereference(myPackageCache);
@@ -107,8 +142,8 @@ public abstract class JavaPsiFacadeImpl {
return aPackage;
}
for (PsiElementFinder finder : filteredFinders()) {
aPackage = finder.findPackage(qualifiedName);
for (KotlinPsiElementFinderWrapper finder : filteredFinders()) {
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) {
return ConcurrencyUtil.cacheOrGet(cache, qualifiedName, aPackage);
}
@@ -118,18 +153,116 @@ public abstract class JavaPsiFacadeImpl {
}
@NotNull
private PsiElementFinder[] filteredFinders() {
private KotlinPsiElementFinderWrapper[] filteredFinders() {
DumbService dumbService = DumbService.getInstance(getProject());
PsiElementFinder[] finders = finders();
KotlinPsiElementFinderWrapper[] finders = finders();
if (dumbService.isDumb()) {
List<PsiElementFinder> list = dumbService.filterByDumbAwareness(Arrays.asList(finders));
finders = list.toArray(new PsiElementFinder[list.size()]);
List<KotlinPsiElementFinderWrapper> list = dumbService.filterByDumbAwareness(Arrays.asList(finders));
finders = list.toArray(new KotlinPsiElementFinderWrapper[list.size()]);
}
return finders;
}
@NotNull
public Project getProject() {
return myProject;
return Project;
}
public static KotlinPsiElementFinderWrapper wrap(PsiElementFinder finder) {
return finder instanceof DumbAware
? new KotlinPsiElementFinderWrapperImplDumbAware(finder)
: new KotlinPsiElementFinderWrapperImpl(finder);
}
interface KotlinPsiElementFinderWrapper {
PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
}
private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper {
private final PsiElementFinder finder;
private KotlinPsiElementFinderWrapperImpl(PsiElementFinder finder) {
this.finder = finder;
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
return finder.findClass(qualifiedName, scope);
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
// Original element finder can't search packages with scope
return finder.findPackage(qualifiedName);
}
}
private static class KotlinPsiElementFinderWrapperImplDumbAware extends KotlinPsiElementFinderWrapperImpl implements DumbAware {
private KotlinPsiElementFinderWrapperImplDumbAware(PsiElementFinder finder) {
super(finder);
}
}
static class KotlinPsiElementFinderImpl implements KotlinPsiElementFinderWrapper, DumbAware {
private final JavaFileManager javaFileManager;
private final boolean isCoreJavaFileManager;
private final PsiManager psiManager;
private final PackageIndex packageIndex;
public KotlinPsiElementFinderImpl(Project project) {
this.javaFileManager = findJavaFileManager(project);
this.isCoreJavaFileManager = javaFileManager instanceof CoreJavaFileManager;
this.packageIndex = PackageIndex.getInstance(project);
this.psiManager = PsiManager.getInstance(project);
}
@NotNull
private static JavaFileManager findJavaFileManager(@NotNull Project project) {
JavaFileManager javaFileManager = ServiceManager.getService(project, JavaFileManager.class);
if (javaFileManager == null) {
throw new IllegalStateException("JavaFileManager component is not found in project");
}
return javaFileManager;
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
PsiClass aClass = javaFileManager.findClass(qualifiedName, scope);
if (aClass != null) {
//TODO: (module refactoring) CoreJavaFileManager should check scope
if (!isCoreJavaFileManager || scope.contains(aClass.getContainingFile().getOriginalFile().getVirtualFile())) {
return aClass;
}
}
return null;
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
if (isCoreJavaFileManager) {
return javaFileManager.findPackage(qualifiedName);
}
Query<VirtualFile> dirs = packageIndex.getDirsByPackageName(qualifiedName, true);
return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
}
private static boolean hasDirectoriesInScope(Query<VirtualFile> dirs, final GlobalSearchScope scope) {
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
@Override
protected boolean accept(VirtualFile file) {
return scope.accept(file);
}
};
dirs.forEach(findProcessor);
return findProcessor.isFound();
}
}
}
@@ -16,34 +16,17 @@
package org.jetbrains.kotlin.resolve.jvm;
import com.intellij.core.CoreJavaFileManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.PackageIndex;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.impl.file.impl.JavaFileManager;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class KotlinJavaPsiFacade {
private final KotlinJavaPsiFacadeWrapper javaPsiFacadeWrapper;
private final JavaPsiFacadeImpl javaPsiFacadeWrapper;
public KotlinJavaPsiFacade(Project project, GlobalSearchScope searchScope) {
javaPsiFacadeWrapper = new KotlinJavaPsiFacadeWrapper(project, searchScope);
javaPsiFacadeWrapper = new JavaPsiFacadeImpl(project, searchScope);
}
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
@@ -53,133 +36,4 @@ public class KotlinJavaPsiFacade {
public PsiPackage findPackage(@NotNull String qualifiedName) {
return javaPsiFacadeWrapper.findPackage(qualifiedName);
}
static class KotlinJavaPsiFacadeWrapper extends JavaPsiFacadeImpl {
private final GlobalSearchScope searchScope;
public KotlinJavaPsiFacadeWrapper(Project project, GlobalSearchScope searchScope) {
super(project);
this.searchScope = searchScope;
}
@NotNull
@Override
protected PsiElementFinder[] calcFinders() {
List<PsiElementFinder> elementFinders = new ArrayList<PsiElementFinder>();
elementFinders.add(new KotlinPsiElementFinderImpl(getProject(), searchScope));
ContainerUtil.addAll(elementFinders, KotlinPackage.filter(
getProject().getExtensions(PsiElementFinder.EP_NAME), new Function1<PsiElementFinder, Boolean>() {
@Override
public Boolean invoke(PsiElementFinder finder) {
return !(finder instanceof KotlinFinderMarker);
}
}));
return elementFinders.toArray(new PsiElementFinder[elementFinders.size()]);
}
@NotNull
private static JavaFileManager findJavaFileManager(@NotNull Project project) {
JavaFileManager javaFileManager = ServiceManager.getService(project, JavaFileManager.class);
if (javaFileManager == null) {
throw new IllegalStateException("JavaFileManager component is not found in project");
}
return javaFileManager;
}
static class KotlinPsiElementFinderImpl extends PsiElementFinder implements DumbAware {
private final GlobalSearchScope searchScope;
private final JavaFileManager javaFileManager;
private final boolean isCoreJavaFileManager;
private final PsiManager psiManager;
private final PackageIndex packageIndex;
public KotlinPsiElementFinderImpl(Project project, GlobalSearchScope searchScope) {
this.searchScope = searchScope;
this.javaFileManager = findJavaFileManager(project);
this.isCoreJavaFileManager = javaFileManager instanceof CoreJavaFileManager;
this.packageIndex = PackageIndex.getInstance(project);
this.psiManager = PsiManager.getInstance(project);
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
PsiClass aClass = javaFileManager.findClass(qualifiedName, scope);
if (aClass != null) {
//TODO: (module refactoring) CoreJavaFileManager should check scope
if (!isCoreJavaFileManager || scope.contains(aClass.getContainingFile().getOriginalFile().getVirtualFile())) {
return aClass;
}
}
return null;
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName) {
if (isCoreJavaFileManager) {
return javaFileManager.findPackage(qualifiedName);
}
Query<VirtualFile> dirs = packageIndex.getDirsByPackageName(qualifiedName, true);
return hasDirectoriesInScope(dirs) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
}
private boolean hasDirectoriesInScope(Query<VirtualFile> dirs) {
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
@Override
protected boolean accept(VirtualFile file) {
return searchScope.accept(file);
}
};
dirs.forEach(findProcessor);
return findProcessor.isFound();
}
@Override
@NotNull
public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
throw new UnsupportedOperationException();
}
@Override
@NotNull
public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
throw new UnsupportedOperationException();
}
@Override
@NotNull
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
throw new UnsupportedOperationException();
}
@Override
@NotNull
public PsiClass[] getClasses(@Nullable String shortName, @NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
throw new UnsupportedOperationException();
}
@Override
public boolean processPackageDirectories(@NotNull PsiPackage psiPackage,
@NotNull GlobalSearchScope scope,
@NotNull Processor<PsiDirectory> consumer,
boolean includeLibrarySources) {
throw new UnsupportedOperationException();
}
}
}
}