KotlinDefinitionsSearcher: J2K

This commit is contained in:
Dmitry Jemerov
2016-10-27 20:30:04 +02:00
parent 4281c13c28
commit 2fc601832c
@@ -14,166 +14,136 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.idea.search.ideaExtensions; package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.codeInsight.navigation.MethodImplementationsSearch; import com.intellij.codeInsight.navigation.MethodImplementationsSearch
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Computable
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethod; import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.DefinitionsScopedSearch
import com.intellij.psi.search.searches.DefinitionsScopedSearch; import com.intellij.util.Processor
import com.intellij.util.Processor; import com.intellij.util.QueryExecutor
import com.intellij.util.QueryExecutor; import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.ContainerUtil; import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.LightClassUtil; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.asJava.elements.KtLightMethod;
import org.jetbrains.kotlin.psi.*;
import java.util.ArrayList; import java.util.ArrayList
import java.util.List;
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass; import org.jetbrains.kotlin.asJava.toLightClass
public class KotlinDefinitionsSearcher implements QueryExecutor<PsiElement, DefinitionsScopedSearch.SearchParameters> { class KotlinDefinitionsSearcher : QueryExecutor<PsiElement, DefinitionsScopedSearch.SearchParameters> {
@Override override fun execute(queryParameters: DefinitionsScopedSearch.SearchParameters, consumer: Processor<PsiElement>): Boolean {
public boolean execute(@NotNull DefinitionsScopedSearch.SearchParameters queryParameters, @NotNull Processor<PsiElement> consumer) { var consumer = consumer
PsiElement element = queryParameters.getElement(); val element = queryParameters.element
SearchScope scope = queryParameters.getScope(); val scope = queryParameters.scope
consumer = skipDelegatedMethodsConsumer(consumer); consumer = skipDelegatedMethodsConsumer(consumer)
if (element instanceof KtClass) { if (element is KtClass) {
return processClassImplementations((KtClass) element, consumer); return processClassImplementations(element, consumer)
} }
if (element instanceof KtNamedFunction || element instanceof KtSecondaryConstructor) { if (element is KtNamedFunction || element is KtSecondaryConstructor) {
return processFunctionImplementations((KtFunction) element, scope, consumer); return processFunctionImplementations(element as KtFunction, scope, consumer)
} }
if (element instanceof KtProperty) { if (element is KtProperty) {
return processPropertyImplementations((KtProperty) element, scope, consumer); return processPropertyImplementations(element, scope, consumer)
} }
if (element instanceof KtParameter) { if (element is KtParameter) {
KtParameter parameter = (KtParameter) element;
if (isFieldParameter(parameter)) { if (isFieldParameter(element)) {
return processPropertyImplementations((KtParameter) element, scope, consumer); return processPropertyImplementations(element, scope, consumer)
} }
} }
return true; return true
} }
@NotNull companion object {
private static Processor<PsiElement> skipDelegatedMethodsConsumer(@NotNull final Processor<PsiElement> baseConsumer) {
return new Processor<PsiElement>() { private fun skipDelegatedMethodsConsumer(baseConsumer: Processor<PsiElement>): Processor<PsiElement> {
@Override return Processor { element ->
public boolean process(PsiElement element) {
if (isDelegated(element)) { if (isDelegated(element)) {
return true; return@Processor true
}
return baseConsumer.process(element);
}
};
}
private static boolean isDelegated(@NotNull PsiElement element) {
return element instanceof KtLightMethod && ((KtLightMethod) element).isDelegated();
}
private static boolean isFieldParameter(final KtParameter parameter) {
return ApplicationManager.getApplication().runReadAction(
new Computable<Boolean>() {
@Override
public Boolean compute() {
return KtPsiUtil.getClassIfParameterIsProperty(parameter) != null;
}
});
}
private static boolean processClassImplementations(@NotNull final KtClass klass, Processor<PsiElement> consumer) {
PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return toLightClass(klass);
}
});
if (psiClass != null) {
return ContainerUtil.process(ClassInheritorsSearch.search(psiClass, true), consumer);
}
return true;
}
private static boolean processFunctionImplementations(final KtFunction function, SearchScope scope, Processor<PsiElement> consumer) {
PsiMethod psiMethod = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod>() {
@Override
public PsiMethod compute() {
return LightClassUtil.INSTANCE.getLightClassMethod(function);
}
});
if (psiMethod != null) {
MethodImplementationsSearch.processImplementations(psiMethod, consumer, scope);
}
return true;
}
private static boolean processPropertyImplementations(@NotNull final KtParameter parameter, @NotNull SearchScope scope, @NotNull Processor<PsiElement> consumer) {
LightClassUtil.PropertyAccessorsPsiMethods accessorsPsiMethods = ApplicationManager.getApplication().runReadAction(
new Computable<LightClassUtil.PropertyAccessorsPsiMethods>() {
@Override
public LightClassUtil.PropertyAccessorsPsiMethods compute() {
return LightClassUtil.INSTANCE.getLightClassPropertyMethods(parameter);
}
});
return processPropertyImplementationsMethods(accessorsPsiMethods, scope, consumer);
}
private static boolean processPropertyImplementations(@NotNull final KtProperty property, @NotNull SearchScope scope, @NotNull Processor<PsiElement> consumer) {
LightClassUtil.PropertyAccessorsPsiMethods accessorsPsiMethods = ApplicationManager.getApplication().runReadAction(
new Computable<LightClassUtil.PropertyAccessorsPsiMethods>() {
@Override
public LightClassUtil.PropertyAccessorsPsiMethods compute() {
return LightClassUtil.INSTANCE.getLightClassPropertyMethods(property);
}
});
return processPropertyImplementationsMethods(accessorsPsiMethods, scope, consumer);
}
public static boolean processPropertyImplementationsMethods(LightClassUtil.PropertyAccessorsPsiMethods accessors, @NotNull SearchScope scope, @NotNull Processor<PsiElement> consumer) {
for (PsiMethod method : accessors) {
List<PsiMethod> implementations = new ArrayList<PsiMethod>();
MethodImplementationsSearch.getOverridingMethods(method, implementations, scope);
for (PsiMethod implementation : implementations) {
if (isDelegated(implementation)) continue;
PsiElement mirrorElement = implementation instanceof KtLightMethod
? ((KtLightMethod) implementation).getKotlinOrigin() : null;
if (mirrorElement instanceof KtProperty || mirrorElement instanceof KtParameter) {
if (!consumer.process(mirrorElement)) {
return false;
}
}
else if (mirrorElement instanceof KtPropertyAccessor && mirrorElement.getParent() instanceof KtProperty) {
if (!consumer.process(mirrorElement.getParent())) {
return false;
}
}
else {
if (!consumer.process(implementation)) {
return false;
}
} }
baseConsumer.process(element)
} }
} }
return true;
private fun isDelegated(element: PsiElement): Boolean {
return element is KtLightMethod && element.isDelegated
}
private fun isFieldParameter(parameter: KtParameter): Boolean {
return ApplicationManager.getApplication().runReadAction(
Computable { KtPsiUtil.getClassIfParameterIsProperty(parameter) != null })
}
private fun processClassImplementations(klass: KtClass, consumer: Processor<PsiElement>): Boolean {
val psiClass = ApplicationManager.getApplication().runReadAction(Computable<com.intellij.psi.PsiClass> { klass.toLightClass() })
if (psiClass != null) {
return ContainerUtil.process(ClassInheritorsSearch.search(psiClass, true), consumer)
}
return true
}
private fun processFunctionImplementations(function: KtFunction, scope: SearchScope, consumer: Processor<PsiElement>): Boolean {
val psiMethod = ApplicationManager.getApplication().runReadAction(Computable<com.intellij.psi.PsiMethod> { LightClassUtil.getLightClassMethod(function) })
if (psiMethod != null) {
MethodImplementationsSearch.processImplementations(psiMethod, consumer, scope)
}
return true
}
private fun processPropertyImplementations(parameter: KtParameter, scope: SearchScope, consumer: Processor<PsiElement>): Boolean {
val accessorsPsiMethods = ApplicationManager.getApplication().runReadAction<LightClassUtil.PropertyAccessorsPsiMethods> { LightClassUtil.getLightClassPropertyMethods(parameter) }
return processPropertyImplementationsMethods(accessorsPsiMethods, scope, consumer)
}
private fun processPropertyImplementations(property: KtProperty, scope: SearchScope, consumer: Processor<PsiElement>): Boolean {
val accessorsPsiMethods = ApplicationManager.getApplication().runReadAction<LightClassUtil.PropertyAccessorsPsiMethods> { LightClassUtil.getLightClassPropertyMethods(property) }
return processPropertyImplementationsMethods(accessorsPsiMethods, scope, consumer)
}
fun processPropertyImplementationsMethods(accessors: LightClassUtil.PropertyAccessorsPsiMethods, scope: SearchScope, consumer: Processor<PsiElement>): Boolean {
for (method in accessors) {
val implementations = ArrayList<PsiMethod>()
MethodImplementationsSearch.getOverridingMethods(method, implementations, scope)
for (implementation in implementations) {
if (isDelegated(implementation)) continue
val mirrorElement = if (implementation is KtLightMethod)
implementation.kotlinOrigin
else
null
if (mirrorElement is KtProperty || mirrorElement is KtParameter) {
if (!consumer.process(mirrorElement)) {
return false
}
}
else if (mirrorElement is KtPropertyAccessor && mirrorElement.parent is KtProperty) {
if (!consumer.process(mirrorElement.parent)) {
return false
}
}
else {
if (!consumer.process(implementation)) {
return false
}
}
}
}
return true
}
} }
} }