J2K JavaElementFinder: autoconvert and fix compilation errors

This commit is contained in:
Pavel V. Talanov
2018-06-01 17:33:55 +02:00
parent 00b1e9281b
commit 6cea843461
2 changed files with 128 additions and 153 deletions
@@ -14,230 +14,205 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.asJava.finder; package org.jetbrains.kotlin.asJava.finder
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2
import com.google.common.collect.Sets; import com.google.common.collect.Sets
import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Condition
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*
import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtilCore
import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.SmartList
import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.ContainerUtil; import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport; import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.name.isValidJavaFqName
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.name.FqNamesUtilKt; import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtClass; import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.resolve.jvm.KotlinFinderMarker
import org.jetbrains.kotlin.psi.KtEnumEntry; import java.util.*
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.jvm.KotlinFinderMarker;
import java.util.Collection; class JavaElementFinder(
import java.util.Comparator; private val project: Project,
import java.util.List; private val kotlinAsJavaSupport: KotlinAsJavaSupport
import java.util.Set; ) : PsiElementFinder(), KotlinFinderMarker {
private val psiManager: PsiManager
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass; init {
this.psiManager = PsiManager.getInstance(project)
public class JavaElementFinder extends PsiElementFinder implements KotlinFinderMarker {
@NotNull
public static JavaElementFinder getInstance(@NotNull Project project) {
PsiElementFinder[] extensions = Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).getExtensions();
for (PsiElementFinder extension : extensions) {
if (extension instanceof JavaElementFinder) {
return (JavaElementFinder) extension;
}
}
throw new IllegalStateException(JavaElementFinder.class.getSimpleName() + " is not found for project " + project);
} }
private final Project project; override fun findClass(qualifiedName: String, scope: GlobalSearchScope): PsiClass? {
private final PsiManager psiManager; val allClasses = findClasses(qualifiedName, scope)
private final KotlinAsJavaSupport kotlinAsJavaSupport; return if (allClasses.size > 0) allClasses[0] else null
public JavaElementFinder(
@NotNull Project project,
@NotNull KotlinAsJavaSupport kotlinAsJavaSupport
) {
this.project = project;
this.psiManager = PsiManager.getInstance(project);
this.kotlinAsJavaSupport = kotlinAsJavaSupport;
} }
@Override override fun findClasses(qualifiedNameString: String, scope: GlobalSearchScope): Array<PsiClass> {
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { if (!isValidJavaFqName(qualifiedNameString)) {
PsiClass[] allClasses = findClasses(qualifiedName, scope); return PsiClass.EMPTY_ARRAY
return allClasses.length > 0 ? allClasses[0] : null;
}
@NotNull
@Override
public PsiClass[] findClasses(@NotNull String qualifiedNameString, @NotNull GlobalSearchScope scope) {
if (!FqNamesUtilKt.isValidJavaFqName(qualifiedNameString)) {
return PsiClass.EMPTY_ARRAY;
} }
List<PsiClass> answer = new SmartList<>(); val answer = SmartList<PsiClass>()
FqName qualifiedName = new FqName(qualifiedNameString); val qualifiedName = FqName(qualifiedNameString)
findClassesAndObjects(qualifiedName, scope, answer); findClassesAndObjects(qualifiedName, scope, answer)
answer.addAll(kotlinAsJavaSupport.getFacadeClasses(qualifiedName, scope)); answer.addAll(kotlinAsJavaSupport.getFacadeClasses(qualifiedName, scope))
answer.addAll(kotlinAsJavaSupport.getKotlinInternalClasses(qualifiedName, scope)); answer.addAll(kotlinAsJavaSupport.getKotlinInternalClasses(qualifiedName, scope))
return sortByClasspath(answer, scope).toArray(new PsiClass[answer.size()]); return sortByClasspath(answer, scope).toTypedArray()
} }
// Finds explicitly declared classes and objects, not package classes // Finds explicitly declared classes and objects, not package classes
// Also DefaultImpls classes of interfaces // Also DefaultImpls classes of interfaces
private void findClassesAndObjects(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) { private fun findClassesAndObjects(qualifiedName: FqName, scope: GlobalSearchScope, answer: MutableList<PsiClass>) {
findInterfaceDefaultImpls(qualifiedName, scope, answer); findInterfaceDefaultImpls(qualifiedName, scope, answer)
Collection<KtClassOrObject> classOrObjectDeclarations = val classOrObjectDeclarations = kotlinAsJavaSupport.findClassOrObjectDeclarations(qualifiedName, scope)
kotlinAsJavaSupport.findClassOrObjectDeclarations(qualifiedName, scope);
for (KtClassOrObject declaration : classOrObjectDeclarations) { for (declaration in classOrObjectDeclarations) {
if (!(declaration instanceof KtEnumEntry)) { if (declaration !is KtEnumEntry) {
PsiClass lightClass = toLightClass(declaration); val lightClass = declaration.toLightClass()
if (lightClass != null) { if (lightClass != null) {
answer.add(lightClass); answer.add(lightClass)
} }
} }
} }
} }
private void findInterfaceDefaultImpls(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) { private fun findInterfaceDefaultImpls(qualifiedName: FqName, scope: GlobalSearchScope, answer: MutableList<PsiClass>) {
if (qualifiedName.isRoot()) return; if (qualifiedName.isRoot) return
if (!qualifiedName.shortName().asString().equals(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)) return; if (qualifiedName.shortName().asString() != JvmAbi.DEFAULT_IMPLS_CLASS_NAME) return
for (KtClassOrObject classOrObject : kotlinAsJavaSupport.findClassOrObjectDeclarations(qualifiedName.parent(), scope)) { for (classOrObject in kotlinAsJavaSupport.findClassOrObjectDeclarations(qualifiedName.parent(), scope)) {
//NOTE: can't filter out more interfaces right away because decompiled declarations do not have member bodies //NOTE: can't filter out more interfaces right away because decompiled declarations do not have member bodies
if (classOrObject instanceof KtClass && ((KtClass) classOrObject).isInterface()) { if (classOrObject is KtClass && classOrObject.isInterface()) {
PsiClass interfaceClass = toLightClass(classOrObject); val interfaceClass = classOrObject.toLightClass()
if (interfaceClass != null) { if (interfaceClass != null) {
PsiClass implsClass = interfaceClass.findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false); val implsClass = interfaceClass!!.findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false)
if (implsClass != null) { if (implsClass != null) {
answer.add(implsClass); answer.add(implsClass)
} }
} }
} }
} }
} }
@NotNull override fun getClassNames(psiPackage: PsiPackage, scope: GlobalSearchScope): Set<String> {
@Override val packageFQN = FqName(psiPackage.qualifiedName)
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
Collection<KtClassOrObject> declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope); val declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope)
Set<String> answer = Sets.newHashSet(); val answer = Sets.newHashSet<String>()
answer.addAll(kotlinAsJavaSupport.getFacadeNames(packageFQN, scope)); answer.addAll(kotlinAsJavaSupport.getFacadeNames(packageFQN, scope))
for (KtClassOrObject declaration : declarations) { for (declaration in declarations) {
String name = declaration.getName(); val name = declaration.name
if (name != null) { if (name != null) {
answer.add(name); answer.add(name)
} }
} }
return answer; return answer
} }
@Override override fun findPackage(qualifiedNameString: String): PsiPackage? {
public PsiPackage findPackage(@NotNull String qualifiedNameString) { if (!isValidJavaFqName(qualifiedNameString)) {
if (!FqNamesUtilKt.isValidJavaFqName(qualifiedNameString)) { return null
return null;
} }
FqName fqName = new FqName(qualifiedNameString); val fqName = FqName(qualifiedNameString)
// allScope() because the contract says that the whole project // allScope() because the contract says that the whole project
GlobalSearchScope allScope = GlobalSearchScope.allScope(project); val allScope = GlobalSearchScope.allScope(project)
if (kotlinAsJavaSupport.packageExists(fqName, allScope)) { return if (kotlinAsJavaSupport.packageExists(fqName, allScope)) {
return new KtLightPackage(psiManager, fqName, allScope); KtLightPackage(psiManager, fqName, allScope)
} } else null
return null;
} }
@NotNull override fun getSubPackages(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiPackage> {
@Override val packageFQN = FqName(psiPackage.qualifiedName)
public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
Collection<FqName> subpackages = kotlinAsJavaSupport.getSubPackages(packageFQN, scope); val subpackages = kotlinAsJavaSupport.getSubPackages(packageFQN, scope)
Collection<PsiPackage> answer = Collections2.transform(subpackages, input -> new KtLightPackage(psiManager, input, scope)); val answer = Collections2.transform<FqName, PsiPackage>(subpackages) { input -> KtLightPackage(psiManager, input, scope) }
return answer.toArray(new PsiPackage[answer.size()]); return answer.toTypedArray()
} }
@NotNull override fun getClasses(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiClass> {
@Override val answer = SmartList<PsiClass>()
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { val packageFQN = FqName(psiPackage.qualifiedName)
List<PsiClass> answer = new SmartList<>();
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
answer.addAll(kotlinAsJavaSupport.getFacadeClassesInPackage(packageFQN, scope)); answer.addAll(kotlinAsJavaSupport.getFacadeClassesInPackage(packageFQN, scope))
Collection<KtClassOrObject> declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope); val declarations = kotlinAsJavaSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope)
for (KtClassOrObject declaration : declarations) { for (declaration in declarations) {
PsiClass aClass = toLightClass(declaration); val aClass = declaration.toLightClass()
if (aClass != null) { if (aClass != null) {
answer.add(aClass); answer.add(aClass)
} }
} }
return sortByClasspath(answer, scope).toArray(new PsiClass[answer.size()]); return sortByClasspath(answer, scope).toTypedArray()
} }
@Override override fun getPackageFiles(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiFile> {
@NotNull val packageFQN = FqName(psiPackage.qualifiedName)
public PsiFile[] getPackageFiles(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
// TODO: this does not take into account JvmPackageName annotation // TODO: this does not take into account JvmPackageName annotation
Collection<KtFile> result = kotlinAsJavaSupport.findFilesForPackage(packageFQN, scope); val result = kotlinAsJavaSupport.findFilesForPackage(packageFQN, scope)
return result.toArray(new PsiFile[result.size()]); return result.toTypedArray()
} }
@Override override fun getPackageFilesFilter(psiPackage: PsiPackage, scope: GlobalSearchScope): Condition<PsiFile>? {
@Nullable return Condition { input ->
public Condition<PsiFile> getPackageFilesFilter(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { if (input !is KtFile) {
return input -> { true
if (!(input instanceof KtFile)) {
return true;
} }
return psiPackage.getQualifiedName().equals(((KtFile) input).getPackageFqName().asString()); else {
}; psiPackage.qualifiedName == (input as KtFile).packageFqName.asString()
}
}
} }
@NotNull companion object {
public static Comparator<PsiElement> byClasspathComparator(@NotNull GlobalSearchScope searchScope) {
return (o1, o2) -> {
VirtualFile f1 = PsiUtilCore.getVirtualFile(o1);
VirtualFile f2 = PsiUtilCore.getVirtualFile(o2);
if (f1 == f2) return 0;
if (f1 == null) return -1;
if (f2 == null) return 1;
return searchScope.compare(f2, f1);
};
}
private static Collection<PsiClass> sortByClasspath(@NotNull List<PsiClass> classes, @NotNull GlobalSearchScope searchScope) { fun getInstance(project: Project): JavaElementFinder {
if (classes.size() > 1) { val extensions = Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).extensions
ContainerUtil.quickSort(classes, byClasspathComparator(searchScope)); for (extension in extensions) {
if (extension is JavaElementFinder) {
return extension
}
}
throw IllegalStateException(JavaElementFinder::class.java.simpleName + " is not found for project " + project)
} }
return classes; fun byClasspathComparator(searchScope: GlobalSearchScope): Comparator<PsiElement> {
return Comparator { o1, o2 ->
val f1 = PsiUtilCore.getVirtualFile(o1)
val f2 = PsiUtilCore.getVirtualFile(o2)
when {
f1 === f2 -> 0
f1 == null -> -1
f2 == null -> 1
else -> searchScope.compare(f2!!, f1!!)
}
}
}
private fun sortByClasspath(classes: List<PsiClass>, searchScope: GlobalSearchScope): Collection<PsiClass> {
if (classes.size > 1) {
ContainerUtil.quickSort(classes, byClasspathComparator(searchScope))
}
return classes
}
} }
} }
@@ -56,7 +56,7 @@ public abstract class KotlinAsJavaTestBase extends KotlinTestWithEnvironment {
super.setUp(); super.setUp();
KotlinCoreEnvironment environment = getEnvironment(); KotlinCoreEnvironment environment = getEnvironment();
KotlinTestUtils.resolveAllKotlinFiles(environment); KotlinTestUtils.resolveAllKotlinFiles(environment);
finder = JavaElementFinder.getInstance(environment.getProject()); finder = JavaElementFinder.Companion.getInstance(environment.getProject());
} }
@Override @Override