Call Hierarchy: Add support of local declarations
This commit is contained in:
@@ -1029,4 +1029,16 @@ public class JetPsiUtil {
|
||||
|
||||
return header != null ? header.getQualifiedName() : null;
|
||||
}
|
||||
|
||||
public static JetElement getLocalizingCodeBlock(@NotNull JetNamedDeclaration declaration) {
|
||||
//noinspection unchecked
|
||||
JetDeclaration container =
|
||||
PsiTreeUtil.getParentOfType(declaration, JetNamedFunction.class, JetPropertyAccessor.class, JetClassInitializer.class);
|
||||
|
||||
if (container == null) return null;
|
||||
|
||||
return (container instanceof JetClassInitializer)
|
||||
? ((JetClassInitializer) container).getBody()
|
||||
: ((JetDeclarationWithBody) container).getBodyExpression();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ public class HierarchyUtils {
|
||||
return input instanceof PsiMethod ||
|
||||
input instanceof PsiClass ||
|
||||
input instanceof JetFile ||
|
||||
(input instanceof JetNamedFunction && !((JetNamedFunction) input).isLocal()) ||
|
||||
input instanceof JetNamedFunction ||
|
||||
input instanceof JetClassOrObject ||
|
||||
(input instanceof JetProperty && !((JetProperty) input).isLocal());
|
||||
input instanceof JetProperty;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.hierarchy.calls;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
|
||||
public abstract class CalleeReferenceVisitorBase extends JetTreeVisitorVoid {
|
||||
private final BindingContext bindingContext;
|
||||
private final boolean deepTraversal;
|
||||
|
||||
protected CalleeReferenceVisitorBase(BindingContext bindingContext, boolean deepTraversal) {
|
||||
this.bindingContext = bindingContext;
|
||||
this.deepTraversal = deepTraversal;
|
||||
}
|
||||
|
||||
protected abstract void processDeclaration(JetReferenceExpression reference, PsiElement declaration);
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
if (deepTraversal || !(element instanceof JetClassOrObject || element instanceof JetNamedFunction)) {
|
||||
super.visitJetElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
|
||||
if (descriptor == null) return;
|
||||
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
|
||||
if (declaration == null) return;
|
||||
|
||||
if (isProperty(descriptor, declaration) || isCallable(descriptor, declaration, expression)) {
|
||||
processDeclaration(expression, declaration);
|
||||
}
|
||||
}
|
||||
|
||||
// Accept callees of JetCallElement which refer to Kotlin function, Kotlin class or Java method
|
||||
private static boolean isCallable(DeclarationDescriptor descriptor, PsiElement declaration, JetSimpleNameExpression reference) {
|
||||
JetCallElement callElement = PsiTreeUtil.getParentOfType(reference, JetCallElement.class);
|
||||
if (callElement == null || !PsiTreeUtil.isAncestor(callElement.getCalleeExpression(), reference, false)) return false;
|
||||
|
||||
return descriptor instanceof FunctionDescriptor
|
||||
&& (declaration instanceof JetClassOrObject
|
||||
|| declaration instanceof JetNamedFunction
|
||||
|| declaration instanceof PsiMethod);
|
||||
}
|
||||
|
||||
// Accept only properties (not local variables or references to Java fields)
|
||||
private static boolean isProperty(DeclarationDescriptor descriptor, PsiElement declaration) {
|
||||
return descriptor instanceof PropertyDescriptor && declaration instanceof JetProperty;
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -12,8 +12,10 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.presentation.java.ClassPresentationUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.LayeredIcon;
|
||||
import com.intellij.util.Function;
|
||||
|
||||
@@ -8,14 +8,48 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
public KotlinCallTreeStructure(@NotNull Project project, HierarchyNodeDescriptor baseDescriptor) {
|
||||
super(project, baseDescriptor);
|
||||
protected final String scopeType;
|
||||
protected final JetElement localizingCodeBlock;
|
||||
protected final PsiMethod basePsiMethod;
|
||||
protected final PsiClass basePsiClass;
|
||||
|
||||
public KotlinCallTreeStructure(@NotNull Project project, PsiElement element, String scopeType) {
|
||||
super(project, createNodeDescriptor(project, element, null));
|
||||
|
||||
this.scopeType = scopeType;
|
||||
|
||||
localizingCodeBlock = element instanceof JetNamedDeclaration
|
||||
? JetPsiUtil.getLocalizingCodeBlock((JetNamedDeclaration) element)
|
||||
: null;
|
||||
|
||||
if (localizingCodeBlock == null) {
|
||||
basePsiMethod = getPsiMethod(element);
|
||||
assert basePsiMethod != null;
|
||||
|
||||
basePsiClass = basePsiMethod.getContainingClass();
|
||||
assert basePsiClass != null;
|
||||
}
|
||||
else {
|
||||
basePsiMethod = null;
|
||||
basePsiClass = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static HierarchyNodeDescriptor createNodeDescriptor(Project project, PsiElement element, HierarchyNodeDescriptor parent) {
|
||||
boolean root = (parent == null);
|
||||
return element instanceof JetElement
|
||||
? new KotlinCallHierarchyNodeDescriptor(project, parent, element, root, false)
|
||||
: new CallHierarchyNodeDescriptor(project, parent, element, root, false);
|
||||
}
|
||||
|
||||
protected static PsiElement getTargetElement(HierarchyNodeDescriptor descriptor) {
|
||||
@@ -24,17 +58,6 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
: ((KotlinCallHierarchyNodeDescriptor)descriptor).getTargetElement();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiMethod getBasePsiMethod() {
|
||||
return getPsiMethod(((KotlinCallHierarchyNodeDescriptor) getBaseDescriptor()).getTargetElement());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiClass getBasePsiClass() {
|
||||
PsiMethod method = getBasePsiMethod();
|
||||
return method != null ? method.getContainingClass() : null;
|
||||
}
|
||||
|
||||
private static PsiMethod getClosestContainingClassConstructor(PsiElement element) {
|
||||
while (element != null) {
|
||||
JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class, false);
|
||||
@@ -53,7 +76,9 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static PsiMethod getPsiMethod(PsiElement element) {
|
||||
protected final PsiMethod getPsiMethod(PsiElement element) {
|
||||
assert localizingCodeBlock == null : "Can't build light method for local declaration";
|
||||
|
||||
if (element instanceof PsiMethod) {
|
||||
return (PsiMethod) element;
|
||||
}
|
||||
@@ -77,12 +102,6 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
return method != null ? method : getClosestContainingClassConstructor(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static PsiClass getPsiClass(PsiElement element) {
|
||||
PsiMethod method = getPsiMethod(element);
|
||||
return method != null ? method.getContainingClass() : null;
|
||||
}
|
||||
|
||||
protected static CallHierarchyNodeDescriptor getJavaNodeDescriptor(HierarchyNodeDescriptor originalDescriptor) {
|
||||
if (originalDescriptor instanceof CallHierarchyNodeDescriptor) return (CallHierarchyNodeDescriptor) originalDescriptor;
|
||||
|
||||
@@ -90,6 +109,36 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
return ((KotlinCallHierarchyNodeDescriptor) originalDescriptor).getJavaDelegate();
|
||||
}
|
||||
|
||||
protected final Object[] collectNodeDescriptors(HierarchyNodeDescriptor descriptor, List<? extends PsiElement> calleeElements) {
|
||||
HashMap<PsiElement, HierarchyNodeDescriptor> declarationToDescriptorMap = new HashMap<PsiElement, HierarchyNodeDescriptor>();
|
||||
for (PsiElement callee : calleeElements) {
|
||||
if (basePsiClass != null && !isInScope(basePsiClass, callee, scopeType)) continue;
|
||||
|
||||
addNodeDescriptorForElement(callee, declarationToDescriptorMap, descriptor);
|
||||
}
|
||||
return declarationToDescriptorMap.values().toArray(new Object[declarationToDescriptorMap.size()]);
|
||||
}
|
||||
|
||||
protected final void addNodeDescriptorForElement(
|
||||
PsiElement element,
|
||||
Map<PsiElement, HierarchyNodeDescriptor> declarationToDescriptorMap,
|
||||
HierarchyNodeDescriptor descriptor
|
||||
) {
|
||||
HierarchyNodeDescriptor d = declarationToDescriptorMap.get(element);
|
||||
if (d == null) {
|
||||
d = createNodeDescriptor(myProject, element, descriptor);
|
||||
declarationToDescriptorMap.put(element, d);
|
||||
}
|
||||
else {
|
||||
if (d instanceof CallHierarchyNodeDescriptor) {
|
||||
((CallHierarchyNodeDescriptor) d).incrementUsageCount();
|
||||
}
|
||||
else if (d instanceof KotlinCallHierarchyNodeDescriptor) {
|
||||
((KotlinCallHierarchyNodeDescriptor) d).incrementUsageCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysShowPlus() {
|
||||
return true;
|
||||
|
||||
+13
-114
@@ -24,13 +24,9 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
|
||||
@@ -38,87 +34,21 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
private final String scopeType;
|
||||
private final CalleeMethodsTreeStructure javaTreeStucture;
|
||||
private final CalleeMethodsTreeStructure javaTreeStructure;
|
||||
|
||||
public KotlinCalleeMethodsTreeStructure(@NotNull Project project, @NotNull PsiElement element, String scopeType) {
|
||||
super(project, new KotlinCallHierarchyNodeDescriptor(project, null, element, true, false));
|
||||
this.scopeType = scopeType;
|
||||
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
assert psiMethod != null;
|
||||
|
||||
this.javaTreeStucture = new CalleeMethodsTreeStructure(project, psiMethod, scopeType);
|
||||
}
|
||||
|
||||
private static class VisitorBase extends JetTreeVisitorVoid {
|
||||
final BindingContext bindingContext;
|
||||
final ArrayList<PsiElement> result;
|
||||
|
||||
private VisitorBase(BindingContext bindingContext, ArrayList<PsiElement> result) {
|
||||
this.bindingContext = bindingContext;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
if (!(element instanceof JetClassOrObject || element instanceof JetNamedFunction)) {
|
||||
super.visitJetElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(JetCallExpression expression) {
|
||||
super.visitCallExpression(expression);
|
||||
processCallElement(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
|
||||
if (declaration instanceof JetProperty) {
|
||||
result.add(declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationSpecifier(JetDelegationSpecifier specifier) {
|
||||
if (specifier instanceof JetCallElement) {
|
||||
processCallElement((JetCallElement) specifier);
|
||||
}
|
||||
}
|
||||
|
||||
private void processCallElement(JetCallElement element) {
|
||||
JetExpression callee = element.getCalleeExpression();
|
||||
|
||||
JetReferenceExpression referenceExpression = null;
|
||||
if (callee instanceof JetReferenceExpression) {
|
||||
referenceExpression = (JetReferenceExpression) callee;
|
||||
}
|
||||
else if (callee instanceof JetConstructorCalleeExpression) {
|
||||
referenceExpression = ((JetConstructorCalleeExpression) callee).getConstructorReferenceExpression();
|
||||
}
|
||||
|
||||
if (referenceExpression != null) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression);
|
||||
if (descriptor == null) return;
|
||||
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
|
||||
if (declaration instanceof JetClassOrObject
|
||||
|| (declaration instanceof JetNamedFunction && !((JetNamedFunction) declaration).isLocal())
|
||||
|| declaration instanceof PsiMethod ) {
|
||||
result.add(declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
super(project, element, scopeType);
|
||||
this.javaTreeStructure = basePsiMethod != null ? new CalleeMethodsTreeStructure(project, basePsiMethod, scopeType) : null;
|
||||
}
|
||||
|
||||
private static List<? extends PsiElement> getCalleeElements(@NotNull JetElement rootElement, BindingContext bindingContext) {
|
||||
ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||
JetVisitorVoid visitor = new VisitorBase(bindingContext, result);
|
||||
final ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||
JetVisitorVoid visitor = new CalleeReferenceVisitorBase(bindingContext, false) {
|
||||
@Override
|
||||
protected void processDeclaration(JetReferenceExpression reference, PsiElement declaration) {
|
||||
result.add(declaration);
|
||||
}
|
||||
};
|
||||
|
||||
if (rootElement instanceof JetNamedFunction) {
|
||||
JetExpression body = ((JetNamedFunction) rootElement).getBodyExpression();
|
||||
@@ -157,33 +87,6 @@ public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
return result;
|
||||
}
|
||||
|
||||
// copied from Java
|
||||
private Object[] collectNodeDescriptors(
|
||||
HierarchyNodeDescriptor descriptor,
|
||||
List<? extends PsiElement> calleeElements,
|
||||
PsiElement baseElement
|
||||
) {
|
||||
HashMap<PsiElement, KotlinCallHierarchyNodeDescriptor> declarationToDescriptorMap =
|
||||
new HashMap<PsiElement, KotlinCallHierarchyNodeDescriptor>();
|
||||
|
||||
ArrayList<KotlinCallHierarchyNodeDescriptor> result = new ArrayList<KotlinCallHierarchyNodeDescriptor>();
|
||||
|
||||
for (PsiElement callee : calleeElements) {
|
||||
if (!isInScope(baseElement, callee, scopeType)) continue;
|
||||
|
||||
KotlinCallHierarchyNodeDescriptor d = declarationToDescriptorMap.get(callee);
|
||||
if (d == null) {
|
||||
d = new KotlinCallHierarchyNodeDescriptor(myProject, descriptor, callee, false, false);
|
||||
declarationToDescriptorMap.put(callee, d);
|
||||
result.add(d);
|
||||
}
|
||||
else {
|
||||
d.incrementUsageCount();
|
||||
}
|
||||
}
|
||||
return ArrayUtil.toObjectArray(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] buildChildren(HierarchyNodeDescriptor descriptor) {
|
||||
PsiElement targetElement = getTargetElement(descriptor);
|
||||
@@ -209,24 +112,20 @@ public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
return buildChildrenByKotlinTarget(descriptor, (JetElement) targetElement);
|
||||
}
|
||||
|
||||
if (javaTreeStucture != null) {
|
||||
if (javaTreeStructure != null) {
|
||||
CallHierarchyNodeDescriptor javaDescriptor = descriptor instanceof CallHierarchyNodeDescriptor
|
||||
? (CallHierarchyNodeDescriptor) descriptor
|
||||
: ((KotlinCallHierarchyNodeDescriptor)descriptor).getJavaDelegate();
|
||||
return javaTreeStucture.getChildElements(javaDescriptor);
|
||||
return javaTreeStructure.getChildElements(javaDescriptor);
|
||||
}
|
||||
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
private Object[] buildChildrenByKotlinTarget(HierarchyNodeDescriptor descriptor, JetElement targetElement) {
|
||||
PsiClass baseClass = getBasePsiClass();
|
||||
if (baseClass == null) return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
|
||||
BindingContext bindingContext =
|
||||
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) targetElement.getContainingFile()).getBindingContext();
|
||||
List<? extends PsiElement> calleeDescriptors = getCalleeElements((JetElement) targetElement, bindingContext);
|
||||
|
||||
return collectNodeDescriptors(descriptor, calleeDescriptors, baseClass);
|
||||
return collectNodeDescriptors(descriptor, calleeDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
+36
-13
@@ -34,38 +34,61 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.plugin.findUsages.FindUsagesUtils;
|
||||
import org.jetbrains.jet.plugin.hierarchy.HierarchyUtils;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
import org.jetbrains.jet.plugin.references.JetPsiReference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
private final String scopeType;
|
||||
private final CallerMethodsTreeStructure javaTreeStructure;
|
||||
|
||||
public KotlinCallerMethodsTreeStructure(@NotNull Project project, @NotNull PsiElement element, String scopeType) {
|
||||
super(project, new KotlinCallHierarchyNodeDescriptor(project, null, element, true, false));
|
||||
this.scopeType = scopeType;
|
||||
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
assert psiMethod != null;
|
||||
|
||||
this.javaTreeStructure = new CallerMethodsTreeStructure(project, psiMethod, scopeType);
|
||||
super(project, element, scopeType);
|
||||
this.javaTreeStructure = basePsiMethod != null ? new CallerMethodsTreeStructure(project, basePsiMethod, scopeType) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] buildChildren(HierarchyNodeDescriptor descriptor) {
|
||||
PsiElement targetElement = getTargetElement(descriptor);
|
||||
|
||||
PsiClass baseClass = getBasePsiClass();
|
||||
if (baseClass == null) return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
if (localizingCodeBlock != null) {
|
||||
return buildLocalizedChildren(targetElement, (KotlinCallHierarchyNodeDescriptor) descriptor);
|
||||
}
|
||||
|
||||
return processCallers(targetElement, descriptor, baseClass);
|
||||
return processCallers(targetElement, descriptor);
|
||||
}
|
||||
|
||||
private Object[] processCallers(PsiElement element, HierarchyNodeDescriptor descriptor, PsiClass baseClass) {
|
||||
SearchScope searchScope = getSearchScope(scopeType, baseClass);
|
||||
private Object[] buildLocalizedChildren(final PsiElement element, KotlinCallHierarchyNodeDescriptor descriptor) {
|
||||
BindingContext bindingContext =
|
||||
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext();
|
||||
|
||||
final ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||
localizingCodeBlock.accept(new CalleeReferenceVisitorBase(bindingContext, true) {
|
||||
@Override
|
||||
protected void processDeclaration(JetReferenceExpression reference, PsiElement declaration) {
|
||||
if (!declaration.equals(element)) return;
|
||||
|
||||
//noinspection unchecked
|
||||
PsiElement container =
|
||||
PsiTreeUtil.getParentOfType(reference, JetNamedFunction.class, JetPropertyAccessor.class, JetClassOrObject.class);
|
||||
if (container instanceof JetPropertyAccessor) {
|
||||
container = PsiTreeUtil.getParentOfType(container, JetProperty.class);
|
||||
}
|
||||
|
||||
if (container != null) {
|
||||
result.add(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
return collectNodeDescriptors(descriptor, result);
|
||||
}
|
||||
|
||||
private Object[] processCallers(PsiElement element, HierarchyNodeDescriptor descriptor) {
|
||||
SearchScope searchScope = getSearchScope(scopeType, basePsiClass);
|
||||
Map<PsiElement, KotlinCallHierarchyNodeDescriptor> methodToDescriptorMap =
|
||||
new HashMap<PsiElement, KotlinCallHierarchyNodeDescriptor>();
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<node text="client.[anonymous] ()" base="true">
|
||||
<node text="JA.JA()(2 usages) ()"/>
|
||||
<node text="JA.foo(String) ()">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KA(2 usages) ()"/>
|
||||
<node text="KA.foo(String) ()"/>
|
||||
<node text="KA.name ()"/>
|
||||
<node text="packageFun(String)(2 usages) ()"/>
|
||||
</node>
|
||||
@@ -0,0 +1,32 @@
|
||||
class KA {
|
||||
val name = "A"
|
||||
fun foo(s: String): String = "A: $s"
|
||||
}
|
||||
|
||||
fun packageFun(s: String): String = s
|
||||
|
||||
val packageVal = ""
|
||||
|
||||
fun client() {
|
||||
val obj = <caret>object {
|
||||
val bar = run {
|
||||
val localVal = packageFun("")
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
packageFun(localVal)
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
}
|
||||
}
|
||||
|
||||
fun localFun(s: String): String = packageFun(s)
|
||||
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
localFun(packageVal)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class JA {
|
||||
public String name = "A";
|
||||
|
||||
public JA() {
|
||||
|
||||
}
|
||||
|
||||
public String foo(String s) {
|
||||
System.out.println(s);
|
||||
return "A " + s;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
<node text="KClient" base="true">
|
||||
<node text="KClientBase"/>
|
||||
<node text="KA(4 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="KA.foo(String)(2 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="JA.JA()(4 usages)"/>
|
||||
<node text="JA.foo(String)(2 usages)">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KClient.localFun(String)">
|
||||
<node text="packageFun(String)"/>
|
||||
</node>
|
||||
<node text="packageVal"/>
|
||||
<node text="packageFun(String)(2 usages)"/>
|
||||
</node>
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
<node text="KClient.bar()" base="true">
|
||||
<node text="bar.localFun(String)(2 usages)">
|
||||
<node text="packageFun(String)"/>
|
||||
</node>
|
||||
<node text="KA(4 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="KA.foo(String)(2 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="JA.JA()(4 usages)"/>
|
||||
<node text="JA.foo(String)(2 usages)">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<node text="client.T ()" base="true">
|
||||
<node text="JA.JA()(2 usages) ()"/>
|
||||
<node text="JA.foo(String) ()">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KA(2 usages) ()"/>
|
||||
<node text="KA.foo(String) ()"/>
|
||||
<node text="KA.name ()"/>
|
||||
<node text="packageFun(String)(2 usages) ()"/>
|
||||
</node>
|
||||
@@ -0,0 +1,32 @@
|
||||
class KA {
|
||||
val name = "A"
|
||||
fun foo(s: String): String = "A: $s"
|
||||
}
|
||||
|
||||
fun packageFun(s: String): String = s
|
||||
|
||||
val packageVal = ""
|
||||
|
||||
fun client() {
|
||||
class <caret>T {
|
||||
val bar = run {
|
||||
val localVal = packageFun("")
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
packageFun(localVal)
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
}
|
||||
}
|
||||
|
||||
fun localFun(s: String): String = packageFun(s)
|
||||
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
localFun(packageVal)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class JA {
|
||||
public String name = "A";
|
||||
|
||||
public JA() {
|
||||
|
||||
}
|
||||
|
||||
public String foo(String s) {
|
||||
System.out.println(s);
|
||||
return "A " + s;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<node text="client.localFun(String) ()" base="true">
|
||||
<node text="JA.JA()(2 usages) ()"/>
|
||||
<node text="JA.foo(String) ()">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KA(2 usages) ()"/>
|
||||
<node text="KA.foo(String) ()"/>
|
||||
<node text="KA.name ()"/>
|
||||
<node text="localFun.bar() ()">
|
||||
<node text="KA.name ()"/>
|
||||
<node text="JA.foo(String) ()">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KA(2 usages) ()"/>
|
||||
<node text="JA.JA()(2 usages) ()"/>
|
||||
<node text="KA.foo(String) ()"/>
|
||||
</node>
|
||||
<node text="packageFun(String)(2 usages) ()"/>
|
||||
</node>
|
||||
@@ -0,0 +1,31 @@
|
||||
class KA {
|
||||
val name = "A"
|
||||
fun foo(s: String): String = "A: $s"
|
||||
}
|
||||
|
||||
fun packageFun(s: String): String = s
|
||||
|
||||
val packageVal = ""
|
||||
|
||||
fun client() {
|
||||
fun <caret>localFun(s: String): String {
|
||||
val bar = run {
|
||||
val localVal = packageFun("")
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
packageFun(localVal)
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
}
|
||||
|
||||
bar()
|
||||
}
|
||||
|
||||
KA().foo(KA().name)
|
||||
JA().foo(JA().name)
|
||||
localFun(packageVal)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class JA {
|
||||
public String name = "A";
|
||||
|
||||
public JA() {
|
||||
|
||||
}
|
||||
|
||||
public String foo(String s) {
|
||||
System.out.println(s);
|
||||
return "A " + s;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
<node text="KClient" base="true">
|
||||
<node text="KClientBase"/>
|
||||
<node text="KA(4 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="KA.foo(String)(2 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="JA.JA()(4 usages)"/>
|
||||
<node text="JA.foo(String)(2 usages)">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
</node>
|
||||
<node text="KClient.localFun(String)">
|
||||
<node text="packageFun(String)"/>
|
||||
</node>
|
||||
<node text="packageVal"/>
|
||||
<node text="packageFun(String)(2 usages)"/>
|
||||
</node>
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
<node text="KClient.bar" base="true">
|
||||
<node text="KClient.localFun(String)(2 usages)">
|
||||
<node text="packageFun(String)"/>
|
||||
</node>
|
||||
<node text="KA(4 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="KA.foo(String)(2 usages)"/>
|
||||
<node text="KA.name(2 usages)"/>
|
||||
<node text="JA.JA()(4 usages)"/>
|
||||
<node text="JA.foo(String)(2 usages)">
|
||||
<node text="PrintStream.println(String) (java.io)"/>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<node text="KA" base="true">
|
||||
<node text="JA"/>
|
||||
<node text="JA.newKA()"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient.bar"/>
|
||||
<node text="KClient.bar()(2 usages)"/>
|
||||
<node text="KClientObj"/>
|
||||
<node text="main0.kt"/>
|
||||
<node text="bar.localFun()"/>
|
||||
<node text="packageFun(String)"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient.bar()"/>
|
||||
<node text="main0.kt"/>
|
||||
<node text="JA.newKA()"/>
|
||||
<node text="JA"/>
|
||||
<node text="KClient.bar"/>
|
||||
<node text="KClient"/>
|
||||
</node>
|
||||
|
||||
+8
-7
@@ -1,11 +1,12 @@
|
||||
<node text="KA.foo(String)" base="true">
|
||||
<node text="JA"/>
|
||||
<node text="JA.foo()"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient.bar"/>
|
||||
<node text="KClient.bar()(2 usages)"/>
|
||||
<node text="KClientObj"/>
|
||||
<node text="main0.kt"/>
|
||||
<node text="bar.localFun()"/>
|
||||
<node text="packageFun(String)"/>
|
||||
<node text="KClientObj"/>
|
||||
<node text="KClient.bar"/>
|
||||
<node text="main0.kt"/>
|
||||
<node text="JA.foo()"/>
|
||||
<node text="JA"/>
|
||||
<node text="KClient"/>
|
||||
<node text="KClient.bar()"/>
|
||||
</node>
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<node text="client.KA ()" base="true">
|
||||
<node text="bar.localFun() ()"/>
|
||||
<node text="client.bar() ()"/>
|
||||
<node text="client.KClientObj ()"/>
|
||||
<node text="KClient.client() ()"/>
|
||||
</node>
|
||||
@@ -0,0 +1,20 @@
|
||||
class KClient {
|
||||
fun client() {
|
||||
class <caret>KA {
|
||||
val name = "A"
|
||||
fun foo(s: String): String = "A: $s"
|
||||
}
|
||||
|
||||
val bar: String = KA().name
|
||||
|
||||
fun bar() {
|
||||
fun localFun() = KA()
|
||||
|
||||
KA()
|
||||
}
|
||||
|
||||
object KClientObj {
|
||||
val a = KA()
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<node text="client.foo(String) ()" base="true">
|
||||
<node text="client.bar() ()"/>
|
||||
<node text="bar.localFun() ()"/>
|
||||
<node text="client.KClientObj ()"/>
|
||||
<node text="KClient.client() ()"/>
|
||||
</node>
|
||||
@@ -0,0 +1,17 @@
|
||||
class KClient {
|
||||
fun client() {
|
||||
fun <caret>foo(s: String): String = ""
|
||||
|
||||
val bar: String = foo("")
|
||||
|
||||
fun bar() {
|
||||
fun localFun() = foo("")
|
||||
|
||||
foo("")
|
||||
}
|
||||
|
||||
object KClientObj {
|
||||
val a = foo("")
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -1,11 +1,12 @@
|
||||
<node text="KA.name" base="true">
|
||||
<node text="JA"/>
|
||||
<node text="JA.getName()"/>
|
||||
<node text="KClient(2 usages)"/>
|
||||
<node text="KClient(2 usages)"/>
|
||||
<node text="KClient.bar()(4 usages)"/>
|
||||
<node text="packageFun(String)(2 usages)"/>
|
||||
<node text="KClient.bar()(2 usages)"/>
|
||||
<node text="KClient.bar(4 usages)"/>
|
||||
<node text="bar.localFun()(2 usages)"/>
|
||||
<node text="JA.getName()"/>
|
||||
<node text="JA"/>
|
||||
<node text="KClient(2 usages)"/>
|
||||
<node text="KClient(2 usages)"/>
|
||||
<node text="KClientObj(4 usages)"/>
|
||||
<node text="main0.kt(2 usages)"/>
|
||||
<node text="packageFun(String)(2 usages)"/>
|
||||
</node>
|
||||
|
||||
@@ -217,6 +217,16 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
||||
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinFunction");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalClass")
|
||||
public void testKotlinLocalClass() throws Exception {
|
||||
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinLocalClass");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalFunction")
|
||||
public void testKotlinLocalFunction() throws Exception {
|
||||
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinLocalFunction");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinNestedClass")
|
||||
public void testKotlinNestedClass() throws Exception {
|
||||
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinNestedClass");
|
||||
@@ -250,6 +260,11 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/javaMethod");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAnonymousObject")
|
||||
public void testKotlinAnonymousObject() throws Exception {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinAnonymousObject");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinClass")
|
||||
public void testKotlinClass() throws Exception {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinClass");
|
||||
@@ -270,6 +285,16 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinFunction");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalClass")
|
||||
public void testKotlinLocalClass() throws Exception {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinLocalClass");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalFunction")
|
||||
public void testKotlinLocalFunction() throws Exception {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinLocalFunction");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinNestedClass")
|
||||
public void testKotlinNestedClass() throws Exception {
|
||||
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinNestedClass");
|
||||
|
||||
Reference in New Issue
Block a user