Refactor: refine API of LightClassGenerationSupport

Move some specific code to IDELightClassGenerationSupport
This commit is contained in:
Pavel V. Talanov
2014-12-03 16:24:15 +03:00
parent 33fc241158
commit 15b2977b85
5 changed files with 99 additions and 94 deletions
@@ -22,6 +22,7 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.util.Function;
@@ -31,6 +32,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
import org.jetbrains.jet.asJava.KotlinLightClassForPackage;
import org.jetbrains.jet.asJava.LightClassConstructionContext;
import org.jetbrains.jet.asJava.LightClassGenerationSupport;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
@@ -40,12 +42,14 @@ import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import org.jetbrains.jet.utils.UtilsPackage;
import java.util.Collection;
import java.util.Collections;
@@ -68,10 +72,12 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
return ServiceManager.getService(project, CliLightClassGenerationSupport.class);
}
private final PsiManager psiManager;
private BindingContext bindingContext = null;
private ModuleDescriptor module = null;
public CliLightClassGenerationSupport() {
public CliLightClassGenerationSupport(@NotNull Project project) {
this.psiManager = PsiManager.getInstance(project);
}
@Override
@@ -179,14 +185,6 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
return result;
}
@NotNull
@Override
public List<KotlinLightPackageClassInfo> findPackageClassesInfos(
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
) {
return Collections.singletonList(new KotlinLightPackageClassInfo(findFilesForPackage(fqName, wholeScope), wholeScope));
}
@Override
public boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope) {
return getModule().getPackage(fqName) != null;
@@ -213,7 +211,17 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
@Nullable
@Override
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
return KotlinLightClassForExplicitDeclaration.create(classOrObject.getManager(), classOrObject);
return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject);
}
@NotNull
@Override
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
Collection<JetFile> filesInPackage = findFilesForPackage(packageFqName, scope);
if (PackagePartClassUtils.getPackageFilesWithCallables(filesInPackage).isEmpty()) return Collections.emptyList();
return UtilsPackage.<PsiClass>emptyOrSingletonList(KotlinLightClassForPackage.create(psiManager, packageFqName, scope, filesInPackage));
}
@NotNull
@@ -267,7 +275,7 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
}
}
}
return super.get(slice, key);
}
@@ -256,7 +256,7 @@ public class JetCoreEnvironment {
private static void registerProjectServicesForCLI(@NotNull JavaCoreProjectEnvironment projectEnvironment) {
MockProject project = projectEnvironment.getProject();
project.registerService(CoreJavaFileManager.class, (CoreJavaFileManager) ServiceManager.getService(project, JavaFileManager.class));
CliLightClassGenerationSupport cliLightClassGenerationSupport = new CliLightClassGenerationSupport();
CliLightClassGenerationSupport cliLightClassGenerationSupport = new CliLightClassGenerationSupport(project);
project.registerService(LightClassGenerationSupport.class, cliLightClassGenerationSupport);
project.registerService(CliLightClassGenerationSupport.class, cliLightClassGenerationSupport);
project.registerService(CodeAnalyzerInitializer.class, cliLightClassGenerationSupport);
@@ -36,10 +36,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetEnumEntry;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.JavaPsiFacadeKotlinHacks;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.NamePackage;
@@ -121,7 +119,7 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
findClassesAndObjects(qualifiedName, scope, answer);
if (PackageClassUtils.isPackageClassFqName(qualifiedName)) {
findPackageClass(qualifiedName.parent(), scope, answer);
answer.addAll(lightClassGenerationSupport.getPackageClasses(qualifiedName.parent(), scope));
}
return answer.toArray(new PsiClass[answer.size()]);
@@ -142,26 +140,6 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
}
}
private void findPackageClass(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) {
List<LightClassGenerationSupport.KotlinLightPackageClassInfo>
packageClassesInfos = lightClassGenerationSupport.findPackageClassesInfos(qualifiedName, scope);
for (LightClassGenerationSupport.KotlinLightPackageClassInfo info : packageClassesInfos) {
Collection<JetFile> files = info.getFiles();
if (PackagePartClassUtils.getPackageFilesWithCallables(files).isEmpty()) continue;
KotlinLightClassForPackage lightClass =
KotlinLightClassForPackage.create(psiManager, qualifiedName, info.getScope(), files);
if (lightClass == null) continue;
answer.add(lightClass);
if (files.size() > 1) {
for (JetFile file : files) {
answer.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file));
}
}
}
}
@NotNull
@Override
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
@@ -222,7 +200,7 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
List<PsiClass> answer = new SmartList<PsiClass>();
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
findPackageClass(packageFQN, scope, answer);
answer.addAll(lightClassGenerationSupport.getPackageClasses(packageFQN, scope));
Collection<JetClassOrObject> declarations = lightClassGenerationSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope);
for (JetClassOrObject declaration : declarations) {
@@ -27,7 +27,6 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection;
import java.util.List;
public abstract class LightClassGenerationSupport {
@@ -55,12 +54,6 @@ public abstract class LightClassGenerationSupport {
@NotNull
public abstract Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope);
@NotNull
public abstract List<KotlinLightPackageClassInfo> findPackageClassesInfos(
@NotNull FqName fqName,
@NotNull GlobalSearchScope wholeScope
);
// Returns only immediately declared classes/objects, package classes are not included (they have no declarations)
@NotNull
public abstract Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@@ -76,23 +69,6 @@ public abstract class LightClassGenerationSupport {
@Nullable
public abstract PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject);
public final class KotlinLightPackageClassInfo {
private final Collection<JetFile> files;
private final GlobalSearchScope scope;
public KotlinLightPackageClassInfo(@NotNull Collection<JetFile> files, @NotNull GlobalSearchScope scope) {
this.files = files;
this.scope = scope;
}
@NotNull
public Collection<JetFile> getFiles() {
return files;
}
@NotNull
public GlobalSearchScope getScope() {
return scope;
}
}
@NotNull
public abstract Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope);
}
@@ -21,20 +21,20 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
import org.jetbrains.jet.asJava.LightClassConstructionContext;
import org.jetbrains.jet.asJava.LightClassGenerationSupport;
import org.jetbrains.jet.asJava.*;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
import org.jetbrains.jet.lang.resolve.lazy.BodyResolveMode;
import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
@@ -57,10 +57,12 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
private final Project project;
private final Comparator<JetFile> jetFileComparator;
private final PsiManager psiManager;
public IDELightClassGenerationSupport(@NotNull Project project) {
this.project = project;
this.jetFileComparator = byScopeComparator(GlobalSearchScope.allScope(project));
this.psiManager = PsiManager.getInstance(project);
}
@@ -156,21 +158,6 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSources(searchScope, project), project);
}
@NotNull
@Override
public List<KotlinLightPackageClassInfo> findPackageClassesInfos(
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
) {
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = groupByModuleInfo(allFiles);
List<KotlinLightPackageClassInfo> result = new ArrayList<KotlinLightPackageClassInfo>();
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
result.add(new KotlinLightPackageClassInfo(entry.getValue(), entry.getKey().contentScope()));
}
sortByClasspath(wholeScope, result);
return result;
}
@NotNull
private static Map<IdeaModuleInfo, List<JetFile>> groupByModuleInfo(@NotNull Collection<JetFile> allFiles) {
return KotlinPackage.groupByTo(
@@ -184,19 +171,6 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
});
}
private static void sortByClasspath(@NotNull GlobalSearchScope wholeScope, @NotNull List<KotlinLightPackageClassInfo> result) {
final Comparator<JetFile> byScopeComparator = byScopeComparator(wholeScope);
Collections.sort(result, new Comparator<KotlinLightPackageClassInfo>() {
@Override
public int compare(@NotNull KotlinLightPackageClassInfo info1, @NotNull KotlinLightPackageClassInfo info2) {
JetFile file1 = info1.getFiles().iterator().next();
JetFile file2 = info2.getFiles().iterator().next();
//classes earlier that would appear earlier on classpath should go first
return -byScopeComparator.compare(file1, file2);
}
});
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@@ -224,7 +198,43 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
return JetSourceNavigationHelper.getOriginalClass(classOrObject);
}
return KotlinLightClassForExplicitDeclaration.create(classOrObject.getManager(), classOrObject);
return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject);
}
@NotNull
@Override
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
List<PsiClass> result = new ArrayList<PsiClass>();
List<KotlinLightPackageClassInfo> packageClassesInfos = findPackageClassesInfos(packageFqName, scope);
for (KotlinLightPackageClassInfo info : packageClassesInfos) {
Collection<JetFile> files = info.getFiles();
if (PackagePartClassUtils.getPackageFilesWithCallables(files).isEmpty()) continue;
KotlinLightClassForPackage lightClass = KotlinLightClassForPackage.create(psiManager, packageFqName, info.getScope(), files);
if (lightClass == null) continue;
result.add(lightClass);
if (files.size() > 1) {
for (JetFile file : files) {
result.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file));
}
}
}
return result;
}
@NotNull
private List<KotlinLightPackageClassInfo> findPackageClassesInfos(
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
) {
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = groupByModuleInfo(allFiles);
List<KotlinLightPackageClassInfo> result = new ArrayList<KotlinLightPackageClassInfo>();
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
result.add(new KotlinLightPackageClassInfo(entry.getValue(), entry.getKey().contentScope()));
}
sortByClasspath(wholeScope, result);
return result;
}
@NotNull
@@ -241,4 +251,37 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
}
};
}
private static void sortByClasspath(@NotNull GlobalSearchScope wholeScope, @NotNull List<KotlinLightPackageClassInfo> result) {
final Comparator<JetFile> byScopeComparator = byScopeComparator(wholeScope);
Collections.sort(result, new Comparator<KotlinLightPackageClassInfo>() {
@Override
public int compare(@NotNull KotlinLightPackageClassInfo info1, @NotNull KotlinLightPackageClassInfo info2) {
JetFile file1 = info1.getFiles().iterator().next();
JetFile file2 = info2.getFiles().iterator().next();
//classes earlier that would appear earlier on classpath should go first
return -byScopeComparator.compare(file1, file2);
}
});
}
private static final class KotlinLightPackageClassInfo {
private final Collection<JetFile> files;
private final GlobalSearchScope scope;
public KotlinLightPackageClassInfo(@NotNull Collection<JetFile> files, @NotNull GlobalSearchScope scope) {
this.files = files;
this.scope = scope;
}
@NotNull
public Collection<JetFile> getFiles() {
return files;
}
@NotNull
public GlobalSearchScope getScope() {
return scope;
}
}
}