Implement call hierarchy
This commit is contained in:
@@ -102,17 +102,17 @@ public class JetObjectDeclaration extends JetNamedDeclarationStub<PsiJetObjectSt
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public JetModifierList getModifierList() {
|
public JetModifierList getModifierList() {
|
||||||
PsiElement parent = getParent();
|
if (isClassObject()) {
|
||||||
if (isClassObject(parent)) {
|
PsiElement parent = getParent();
|
||||||
assert parent instanceof JetDeclaration;
|
assert parent instanceof JetDeclaration;
|
||||||
return ((JetDeclaration)parent).getModifierList();
|
return ((JetDeclaration)parent).getModifierList();
|
||||||
}
|
}
|
||||||
return (JetModifierList) findChildByType(JetNodeTypes.MODIFIER_LIST);
|
return (JetModifierList) findChildByType(JetNodeTypes.MODIFIER_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClassObject() {
|
||||||
private static boolean isClassObject(@NotNull PsiElement parent) {
|
PsiElement parent = getParent();
|
||||||
return parent.getNode().getElementType().equals(JetNodeTypes.CLASS_OBJECT);
|
return parent != null && parent.getNode().getElementType().equals(JetNodeTypes.CLASS_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1021,4 +1021,12 @@ public class JetPsiUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getPackageName(@NotNull JetElement element) {
|
||||||
|
JetFile file = (JetFile) element.getContainingFile();
|
||||||
|
JetNamespaceHeader header = PsiTreeUtil.findChildOfType(file, JetNamespaceHeader.class);
|
||||||
|
|
||||||
|
return header != null ? header.getQualifiedName() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -395,7 +395,9 @@ public class GenerateTests {
|
|||||||
AbstractHierarchyTest.class,
|
AbstractHierarchyTest.class,
|
||||||
testModelWithDirectories("idea/testData/hierarchy/class/type", "doTypeClassHierarchyTest"),
|
testModelWithDirectories("idea/testData/hierarchy/class/type", "doTypeClassHierarchyTest"),
|
||||||
testModelWithDirectories("idea/testData/hierarchy/class/super", "doSuperClassHierarchyTest"),
|
testModelWithDirectories("idea/testData/hierarchy/class/super", "doSuperClassHierarchyTest"),
|
||||||
testModelWithDirectories("idea/testData/hierarchy/class/sub", "doSubClassHierarchyTest")
|
testModelWithDirectories("idea/testData/hierarchy/class/sub", "doSubClassHierarchyTest"),
|
||||||
|
testModelWithDirectories("idea/testData/hierarchy/calls/callers", "doCallerHierarchyTest"),
|
||||||
|
testModelWithDirectories("idea/testData/hierarchy/calls/callees", "doCalleeHierarchyTest")
|
||||||
);
|
);
|
||||||
|
|
||||||
generateTest(
|
generateTest(
|
||||||
|
|||||||
@@ -263,6 +263,13 @@
|
|||||||
<library.presentationProvider implementation="org.jetbrains.jet.plugin.framework.JsHeaderLibraryPresentationProvider"/>
|
<library.presentationProvider implementation="org.jetbrains.jet.plugin.framework.JsHeaderLibraryPresentationProvider"/>
|
||||||
|
|
||||||
<typeHierarchyProvider language="jet" implementationClass="org.jetbrains.jet.plugin.hierarchy.KotlinTypeHierarchyProvider"/>
|
<typeHierarchyProvider language="jet" implementationClass="org.jetbrains.jet.plugin.hierarchy.KotlinTypeHierarchyProvider"/>
|
||||||
|
<callHierarchyProvider
|
||||||
|
language="jet"
|
||||||
|
implementationClass="org.jetbrains.jet.plugin.hierarchy.calls.KotlinCallHierarchyProvider" />
|
||||||
|
<callHierarchyProvider
|
||||||
|
language="JAVA"
|
||||||
|
implementationClass="org.jetbrains.jet.plugin.hierarchy.calls.KotlinCallHierarchyProvider"
|
||||||
|
order="first" />
|
||||||
|
|
||||||
<java.elementFinder implementation="org.jetbrains.jet.asJava.JavaElementFinder"/>
|
<java.elementFinder implementation="org.jetbrains.jet.asJava.JavaElementFinder"/>
|
||||||
<java.shortNamesCache implementation="org.jetbrains.jet.plugin.caches.JetShortNamesCache"/>
|
<java.shortNamesCache implementation="org.jetbrains.jet.plugin.caches.JetShortNamesCache"/>
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.jetbrains.jet.plugin.hierarchy;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.intellij.psi.PsiClass;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiMethod;
|
||||||
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class HierarchyUtils {
|
||||||
|
public static final Predicate<PsiElement> IS_CALL_HIERARCHY_ELEMENT = new Predicate<PsiElement>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(@Nullable PsiElement input) {
|
||||||
|
return input instanceof PsiMethod ||
|
||||||
|
input instanceof PsiClass ||
|
||||||
|
input instanceof JetFile ||
|
||||||
|
(input instanceof JetNamedFunction && !((JetNamedFunction) input).isLocal()) ||
|
||||||
|
input instanceof JetClassOrObject ||
|
||||||
|
(input instanceof JetProperty && !((JetProperty) input).isLocal());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static PsiElement getCallHierarchyElement(PsiElement element) {
|
||||||
|
return JetPsiUtil.getParentByTypeAndPredicate(element, PsiElement.class, IS_CALL_HIERARCHY_ELEMENT, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.ide.hierarchy.CallHierarchyBrowserBase;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||||
|
import com.intellij.ide.hierarchy.JavaHierarchyUtil;
|
||||||
|
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||||
|
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||||
|
import com.intellij.openapi.actionSystem.ActionManager;
|
||||||
|
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||||
|
import com.intellij.openapi.actionSystem.IdeActions;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiMethod;
|
||||||
|
import com.intellij.ui.PopupHandler;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||||
|
import org.jetbrains.jet.plugin.hierarchy.HierarchyUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class KotlinCallHierarchyBrowser extends CallHierarchyBrowserBase {
|
||||||
|
public KotlinCallHierarchyBrowser(@NotNull Project project, @NotNull PsiElement element) {
|
||||||
|
super(project, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createTrees(@NotNull Map<String, JTree> type2TreeMap) {
|
||||||
|
ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP);
|
||||||
|
|
||||||
|
JTree tree1 = createTree(false);
|
||||||
|
PopupHandler.installPopupHandler(tree1, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
|
||||||
|
BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction();
|
||||||
|
baseOnThisMethodAction.registerCustomShortcutSet(
|
||||||
|
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree1
|
||||||
|
);
|
||||||
|
type2TreeMap.put(CALLEE_TYPE, tree1);
|
||||||
|
|
||||||
|
JTree tree2 = createTree(false);
|
||||||
|
PopupHandler.installPopupHandler(tree2, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
|
||||||
|
baseOnThisMethodAction.registerCustomShortcutSet(
|
||||||
|
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree2
|
||||||
|
);
|
||||||
|
type2TreeMap.put(CALLER_TYPE, tree2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PsiElement getTargetElement(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||||
|
if (descriptor instanceof KotlinCallHierarchyNodeDescriptor) {
|
||||||
|
return ((KotlinCallHierarchyNodeDescriptor) descriptor).getTargetElement();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||||
|
return getTargetElement(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PsiElement getOpenFileElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
|
||||||
|
return getTargetElement(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isApplicableElement(@NotNull PsiElement element) {
|
||||||
|
return element instanceof JetNamedDeclaration || element instanceof PsiMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HierarchyTreeStructure createHierarchyTreeStructure(@NotNull String typeName, @NotNull PsiElement psiElement) {
|
||||||
|
if (typeName.equals(CALLER_TYPE)) {
|
||||||
|
return new KotlinCallerMethodsTreeStructure(myProject, psiElement, getCurrentScopeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName.equals(CALLEE_TYPE)) {
|
||||||
|
return new KotlinCalleeMethodsTreeStructure(myProject, psiElement, getCurrentScopeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Comparator<NodeDescriptor> getComparator() {
|
||||||
|
return JavaHierarchyUtil.getComparator(myProject);
|
||||||
|
}
|
||||||
|
}
|
||||||
+258
@@ -0,0 +1,258 @@
|
|||||||
|
package org.jetbrains.jet.plugin.hierarchy.calls;
|
||||||
|
|
||||||
|
import com.intellij.icons.AllIcons;
|
||||||
|
import com.intellij.ide.IdeBundle;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.JavaHierarchyUtil;
|
||||||
|
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor;
|
||||||
|
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
|
||||||
|
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.util.PsiTreeUtil;
|
||||||
|
import com.intellij.ui.LayeredIcon;
|
||||||
|
import com.intellij.util.Function;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {
|
||||||
|
private int usageCount = 1;
|
||||||
|
private final List<PsiReference> references = new ArrayList<PsiReference>();
|
||||||
|
private final CallHierarchyNodeDescriptor javaDelegate;
|
||||||
|
|
||||||
|
public KotlinCallHierarchyNodeDescriptor(@NotNull Project project,
|
||||||
|
HierarchyNodeDescriptor parentDescriptor,
|
||||||
|
@NotNull PsiElement element,
|
||||||
|
boolean isBase,
|
||||||
|
boolean navigateToReference) {
|
||||||
|
super(project, parentDescriptor, element, isBase);
|
||||||
|
this.javaDelegate = new CallHierarchyNodeDescriptor(myProject, null, element, isBase, navigateToReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CallHierarchyNodeDescriptor getJavaDelegate() {
|
||||||
|
return javaDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void incrementUsageCount(){
|
||||||
|
usageCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addReference(PsiReference reference) {
|
||||||
|
references.add(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasReference(PsiReference reference) {
|
||||||
|
return references.contains(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final PsiElement getTargetElement(){
|
||||||
|
return myElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isValid(){
|
||||||
|
return myElement != null && myElement.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean update(){
|
||||||
|
CompositeAppearance oldText = myHighlightedText;
|
||||||
|
Icon oldIcon = getIcon();
|
||||||
|
|
||||||
|
int flags = Iconable.ICON_FLAG_VISIBILITY;
|
||||||
|
if (isMarkReadOnly()) {
|
||||||
|
flags |= Iconable.ICON_FLAG_READ_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean changes = super.update();
|
||||||
|
|
||||||
|
PsiElement targetElement = getTargetElement();
|
||||||
|
String elementText = renderElement(targetElement);
|
||||||
|
|
||||||
|
if (elementText == null) {
|
||||||
|
String invalidPrefix = IdeBundle.message("node.hierarchy.invalid");
|
||||||
|
if (!myHighlightedText.getText().startsWith(invalidPrefix)) {
|
||||||
|
myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon newIcon = targetElement.getIcon(flags);
|
||||||
|
if (changes && myIsBase) {
|
||||||
|
LayeredIcon icon = new LayeredIcon(2);
|
||||||
|
icon.setIcon(newIcon, 0);
|
||||||
|
icon.setIcon(AllIcons.Hierarchy.Base, 1, -AllIcons.Hierarchy.Base.getIconWidth() / 2, 0);
|
||||||
|
newIcon = icon;
|
||||||
|
}
|
||||||
|
setIcon(newIcon);
|
||||||
|
|
||||||
|
myHighlightedText = new CompositeAppearance();
|
||||||
|
TextAttributes mainTextAttributes = null;
|
||||||
|
if (myColor != null) {
|
||||||
|
mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
String packageName = null;
|
||||||
|
if (targetElement instanceof JetElement) {
|
||||||
|
packageName = JetPsiUtil.getPackageName((JetElement) targetElement);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PsiClass enclosingClass = PsiTreeUtil.getParentOfType(targetElement, PsiClass.class, false);
|
||||||
|
if (enclosingClass != null) {
|
||||||
|
packageName = JavaHierarchyUtil.getPackageName(enclosingClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myHighlightedText.getEnding().addText(elementText, mainTextAttributes);
|
||||||
|
|
||||||
|
if (usageCount > 1) {
|
||||||
|
myHighlightedText.getEnding().addText(
|
||||||
|
IdeBundle.message("node.call.hierarchy.N.usages", usageCount),
|
||||||
|
HierarchyNodeDescriptor.getUsageCountPrefixAttributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packageName != null && packageName.length() > 0) {
|
||||||
|
myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
myName = myHighlightedText.getText();
|
||||||
|
|
||||||
|
if (!(Comparing.equal(myHighlightedText, oldText) && Comparing.equal(getIcon(), oldIcon))) {
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String renderElement(@Nullable PsiElement element) {
|
||||||
|
String elementText;
|
||||||
|
String containerText = null;
|
||||||
|
|
||||||
|
if (element instanceof JetFile) {
|
||||||
|
elementText = ((JetFile) element).getName();
|
||||||
|
}
|
||||||
|
else if (element instanceof JetNamedDeclaration) {
|
||||||
|
BindingContext bindingContext =
|
||||||
|
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext();
|
||||||
|
|
||||||
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||||
|
if (descriptor == null) return null;
|
||||||
|
|
||||||
|
if (element instanceof JetClassOrObject) {
|
||||||
|
if (element instanceof JetObjectDeclaration && ((JetObjectDeclaration) element).isClassObject()) {
|
||||||
|
descriptor = descriptor.getContainingDeclaration();
|
||||||
|
if (!(descriptor instanceof ClassDescriptor)) return null;
|
||||||
|
|
||||||
|
elementText = renderClassOrObject((ClassDescriptor) descriptor);
|
||||||
|
}
|
||||||
|
else if (element instanceof JetEnumEntry) {
|
||||||
|
elementText = ((JetEnumEntry) element).getName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (((JetClassOrObject) element).getName() != null) {
|
||||||
|
elementText = renderClassOrObject((ClassDescriptor) descriptor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elementText = "[anonymous]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (element instanceof JetNamedFunction) {
|
||||||
|
elementText = renderNamedFunction((FunctionDescriptor) descriptor);
|
||||||
|
}
|
||||||
|
else if (element instanceof JetProperty) {
|
||||||
|
elementText = ((JetProperty) element).getName();
|
||||||
|
}
|
||||||
|
else return null;
|
||||||
|
|
||||||
|
DeclarationDescriptor containerDescriptor = descriptor.getContainingDeclaration();
|
||||||
|
while (containerDescriptor != null) {
|
||||||
|
String name = containerDescriptor.getName().asString();
|
||||||
|
if (!name.startsWith("<")) {
|
||||||
|
containerText = name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
containerDescriptor = containerDescriptor.getContainingDeclaration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (element instanceof PsiMember) {
|
||||||
|
PsiMember member = (PsiMember) element;
|
||||||
|
|
||||||
|
if (member instanceof PsiMethod) {
|
||||||
|
elementText = renderPsiMethod((PsiMethod) member);
|
||||||
|
} else if (member instanceof PsiClass) {
|
||||||
|
elementText = ClassPresentationUtil.getNameForClass((PsiClass) member, false);
|
||||||
|
} else return null;
|
||||||
|
|
||||||
|
PsiClass containingClass = member.getContainingClass();
|
||||||
|
if (containingClass != null) {
|
||||||
|
containerText = ClassPresentationUtil.getNameForClass(containingClass, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return null;
|
||||||
|
|
||||||
|
if (elementText == null) return null;
|
||||||
|
return containerText != null ? containerText + "." + elementText : elementText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String renderPsiMethod(PsiMethod member) {
|
||||||
|
return PsiFormatUtil.formatMethod(
|
||||||
|
member, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String renderNamedFunction(FunctionDescriptor descriptor) {
|
||||||
|
String name = descriptor.getName().asString();
|
||||||
|
String paramTypes = StringUtil.join(
|
||||||
|
descriptor.getValueParameters(),
|
||||||
|
new Function<ValueParameterDescriptor, String>() {
|
||||||
|
@Override
|
||||||
|
public String fun(ValueParameterDescriptor descriptor) {
|
||||||
|
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor.getType());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
", "
|
||||||
|
);
|
||||||
|
return name + "(" + paramTypes + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String renderClassOrObject(ClassDescriptor descriptor) {
|
||||||
|
return descriptor.getName().asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void navigate(boolean requestFocus) {
|
||||||
|
if (myElement instanceof Navigatable) {
|
||||||
|
((Navigatable)myElement).navigate(requestFocus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canNavigate() {
|
||||||
|
return myElement instanceof Navigatable && ((Navigatable) myElement).canNavigate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canNavigateToSource() {
|
||||||
|
return canNavigate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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.codeInsight.TargetElementUtilBase;
|
||||||
|
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyBrowser;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyProvider;
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.plugin.JetPluginUtil;
|
||||||
|
import org.jetbrains.jet.plugin.hierarchy.HierarchyUtils;
|
||||||
|
|
||||||
|
public class KotlinCallHierarchyProvider implements HierarchyProvider {
|
||||||
|
@Override
|
||||||
|
public PsiElement getTarget(@NotNull DataContext dataContext) {
|
||||||
|
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||||
|
if (project == null) return null;
|
||||||
|
|
||||||
|
return HierarchyUtils.getCallHierarchyElement(getCurrentElement(dataContext, project));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PsiElement getCurrentElement(DataContext dataContext, Project project) {
|
||||||
|
Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||||
|
if (editor != null) {
|
||||||
|
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
|
if (file == null) return null;
|
||||||
|
|
||||||
|
if (!JetPluginUtil.isInSource(file)) return null;
|
||||||
|
if (JetPluginUtil.isKtFileInGradleProjectInWrongFolder(file)) return null;
|
||||||
|
|
||||||
|
return TargetElementUtilBase.findTargetElement(editor, TargetElementUtilBase.getInstance().getAllAccepted());
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HierarchyBrowser createHierarchyBrowser(PsiElement target) {
|
||||||
|
return new KotlinCallHierarchyBrowser(target.getProject(), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void browserActivated(@NotNull HierarchyBrowser hierarchyBrowser) {
|
||||||
|
((KotlinCallHierarchyBrowser) hierarchyBrowser).changeView(CallHierarchyBrowserBase.CALLER_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.jetbrains.jet.plugin.hierarchy.calls;
|
||||||
|
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||||
|
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiClass;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiMethod;
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||||
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
|
||||||
|
public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||||
|
public KotlinCallTreeStructure(@NotNull Project project, HierarchyNodeDescriptor baseDescriptor) {
|
||||||
|
super(project, baseDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static PsiElement getTargetElement(HierarchyNodeDescriptor descriptor) {
|
||||||
|
return descriptor instanceof CallHierarchyNodeDescriptor
|
||||||
|
? ((CallHierarchyNodeDescriptor) descriptor).getEnclosingElement()
|
||||||
|
: ((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);
|
||||||
|
if (classOrObject == null) return null;
|
||||||
|
|
||||||
|
element = classOrObject.getParent();
|
||||||
|
|
||||||
|
PsiClass psiClass = LightClassUtil.getPsiClass(classOrObject);
|
||||||
|
if (psiClass == null) continue;
|
||||||
|
|
||||||
|
PsiMethod[] constructors = psiClass.getConstructors();
|
||||||
|
if (constructors.length > 0) return constructors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected static PsiMethod getPsiMethod(PsiElement element) {
|
||||||
|
if (element instanceof PsiMethod) {
|
||||||
|
return (PsiMethod) element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiMethod method = null;
|
||||||
|
if (element instanceof JetNamedFunction) {
|
||||||
|
method = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
|
||||||
|
}
|
||||||
|
else if (element instanceof JetProperty) {
|
||||||
|
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods =
|
||||||
|
LightClassUtil.getLightClassPropertyMethods((JetProperty) element);
|
||||||
|
|
||||||
|
if (propertyMethods.getGetter() != null) {
|
||||||
|
method = propertyMethods.getGetter();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
method = propertyMethods.getSetter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
assert originalDescriptor instanceof KotlinCallHierarchyNodeDescriptor;
|
||||||
|
return ((KotlinCallHierarchyNodeDescriptor) originalDescriptor).getJavaDelegate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlwaysShowPlus() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+232
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* 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.ide.hierarchy.HierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||||
|
private final String scopeType;
|
||||||
|
private final CalleeMethodsTreeStructure javaTreeStucture;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<? extends PsiElement> getCalleeElements(@NotNull JetElement rootElement, BindingContext bindingContext) {
|
||||||
|
ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||||
|
JetVisitorVoid visitor = new VisitorBase(bindingContext, result);
|
||||||
|
|
||||||
|
if (rootElement instanceof JetNamedFunction) {
|
||||||
|
JetExpression body = ((JetNamedFunction) rootElement).getBodyExpression();
|
||||||
|
if (body != null) {
|
||||||
|
body.accept(visitor);
|
||||||
|
}
|
||||||
|
} else if (rootElement instanceof JetProperty) {
|
||||||
|
for (JetPropertyAccessor accessor : ((JetProperty) rootElement).getAccessors()) {
|
||||||
|
JetExpression body = accessor.getBodyExpression();
|
||||||
|
if (body != null) {
|
||||||
|
body.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JetClassOrObject classOrObject = (JetClassOrObject) rootElement;
|
||||||
|
for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
|
||||||
|
if (specifier instanceof JetCallElement) {
|
||||||
|
specifier.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JetClassBody body = classOrObject.getBody();
|
||||||
|
if (body != null) {
|
||||||
|
for (JetClassInitializer initializer : body.getAnonymousInitializers()) {
|
||||||
|
initializer.getBody().accept(visitor);
|
||||||
|
}
|
||||||
|
for (JetProperty property : body.getProperties()) {
|
||||||
|
JetExpression initializer = property.getInitializer();
|
||||||
|
if (initializer != null) {
|
||||||
|
initializer.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Kotlin class constructor invoked from Java code
|
||||||
|
if (targetElement instanceof PsiMethod) {
|
||||||
|
PsiMethod psiMethod = (PsiMethod) targetElement;
|
||||||
|
if (psiMethod.isConstructor()) {
|
||||||
|
PsiClass psiClass = psiMethod.getContainingClass();
|
||||||
|
PsiElement navigationElement = psiClass != null ? psiClass.getNavigationElement() : null;
|
||||||
|
if (navigationElement instanceof JetClass) {
|
||||||
|
return buildChildrenByKotlinTarget(descriptor, (JetElement) navigationElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kotlin function or property invoked from Java code
|
||||||
|
if (targetElement instanceof JetClsMethod) {
|
||||||
|
return buildChildrenByKotlinTarget(descriptor, ((JetClsMethod) targetElement).getOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetElement instanceof JetElement) {
|
||||||
|
return buildChildrenByKotlinTarget(descriptor, (JetElement) targetElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaTreeStucture != null) {
|
||||||
|
CallHierarchyNodeDescriptor javaDescriptor = descriptor instanceof CallHierarchyNodeDescriptor
|
||||||
|
? (CallHierarchyNodeDescriptor) descriptor
|
||||||
|
: ((KotlinCallHierarchyNodeDescriptor)descriptor).getJavaDelegate();
|
||||||
|
return javaTreeStucture.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* 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.ide.hierarchy.HierarchyNodeDescriptor;
|
||||||
|
import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure;
|
||||||
|
import com.intellij.openapi.application.ReadActionProcessor;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.Condition;
|
||||||
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.search.SearchScope;
|
||||||
|
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.util.ArrayUtil;
|
||||||
|
import com.intellij.util.FilteringProcessor;
|
||||||
|
import com.intellij.util.Processor;
|
||||||
|
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 org.jetbrains.jet.plugin.findUsages.FindUsagesUtils;
|
||||||
|
import org.jetbrains.jet.plugin.hierarchy.HierarchyUtils;
|
||||||
|
import org.jetbrains.jet.plugin.references.JetPsiReference;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object[] buildChildren(HierarchyNodeDescriptor descriptor) {
|
||||||
|
PsiElement targetElement = getTargetElement(descriptor);
|
||||||
|
|
||||||
|
PsiClass baseClass = getBasePsiClass();
|
||||||
|
if (baseClass == null) return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||||
|
|
||||||
|
return processCallers(targetElement, descriptor, baseClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] processCallers(PsiElement element, HierarchyNodeDescriptor descriptor, PsiClass baseClass) {
|
||||||
|
SearchScope searchScope = getSearchScope(scopeType, baseClass);
|
||||||
|
Map<PsiElement, KotlinCallHierarchyNodeDescriptor> methodToDescriptorMap =
|
||||||
|
new HashMap<PsiElement, KotlinCallHierarchyNodeDescriptor>();
|
||||||
|
|
||||||
|
Object[] javaCallers = null;
|
||||||
|
if (element instanceof PsiMethod && javaTreeStructure != null) {
|
||||||
|
javaCallers = javaTreeStructure.getChildElements(getJavaNodeDescriptor(descriptor));
|
||||||
|
processPsiMethodCallers((PsiMethod) element, descriptor, methodToDescriptorMap, searchScope, true);
|
||||||
|
}
|
||||||
|
if (element instanceof JetNamedFunction) {
|
||||||
|
PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
|
||||||
|
processPsiMethodCallers(lightMethod, descriptor, methodToDescriptorMap, searchScope, false);
|
||||||
|
}
|
||||||
|
if (element instanceof JetProperty) {
|
||||||
|
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods =
|
||||||
|
LightClassUtil.getLightClassPropertyMethods((JetProperty) element);
|
||||||
|
processPsiMethodCallers(propertyMethods.getGetter(), descriptor, methodToDescriptorMap, searchScope, false);
|
||||||
|
processPsiMethodCallers(propertyMethods.getSetter(), descriptor, methodToDescriptorMap, searchScope, false);
|
||||||
|
}
|
||||||
|
if (element instanceof JetClassOrObject) {
|
||||||
|
processJetClassOrObjectCallers((JetClassOrObject) element, descriptor, methodToDescriptorMap, searchScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] callers = methodToDescriptorMap.values().toArray(new Object[methodToDescriptorMap.size()]);
|
||||||
|
return (javaCallers != null) ? ArrayUtil.mergeArrays(javaCallers, callers) : callers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPsiMethodCallers(
|
||||||
|
@Nullable PsiMethod lightMethod,
|
||||||
|
HierarchyNodeDescriptor descriptor,
|
||||||
|
Map<PsiElement, KotlinCallHierarchyNodeDescriptor> methodToDescriptorMap,
|
||||||
|
SearchScope searchScope,
|
||||||
|
boolean kotlinOnly
|
||||||
|
) {
|
||||||
|
if (lightMethod == null) return;
|
||||||
|
MethodReferencesSearch.search(lightMethod, searchScope, true)
|
||||||
|
.forEach(defaultQueryProcessor(descriptor, methodToDescriptorMap, kotlinOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processJetClassOrObjectCallers(
|
||||||
|
final JetClassOrObject classOrObject,
|
||||||
|
HierarchyNodeDescriptor descriptor,
|
||||||
|
Map<PsiElement, KotlinCallHierarchyNodeDescriptor> methodToDescriptorMap,
|
||||||
|
SearchScope searchScope
|
||||||
|
) {
|
||||||
|
Processor<PsiReference> processor = new FilteringProcessor<PsiReference>(
|
||||||
|
new Condition<PsiReference>() {
|
||||||
|
@Override
|
||||||
|
public boolean value(PsiReference reference) {
|
||||||
|
return FindUsagesUtils.isConstructorUsage(reference.getElement(), classOrObject);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultQueryProcessor(descriptor, methodToDescriptorMap, false)
|
||||||
|
);
|
||||||
|
ReferencesSearch.search(classOrObject, searchScope, false).forEach(processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Processor<PsiReference> defaultQueryProcessor(
|
||||||
|
final HierarchyNodeDescriptor descriptor,
|
||||||
|
final Map<PsiElement, KotlinCallHierarchyNodeDescriptor> methodToDescriptorMap,
|
||||||
|
final boolean kotlinOnly
|
||||||
|
) {
|
||||||
|
return new ReadActionProcessor<PsiReference>() {
|
||||||
|
@Override
|
||||||
|
public boolean processInReadAction(PsiReference ref) {
|
||||||
|
// copied from Java
|
||||||
|
if (!(ref instanceof PsiReferenceExpression || ref instanceof JetPsiReference)) {
|
||||||
|
if (!(ref instanceof PsiElement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiElement parent = ((PsiElement) ref).getParent();
|
||||||
|
if (parent instanceof PsiNewExpression) {
|
||||||
|
if (((PsiNewExpression) parent).getClassReference() != ref) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parent instanceof PsiAnonymousClass) {
|
||||||
|
if (((PsiAnonymousClass) parent).getBaseClassReference() != ref) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiElement element = HierarchyUtils.getCallHierarchyElement(ref.getElement());
|
||||||
|
|
||||||
|
if (kotlinOnly && !(element instanceof JetNamedDeclaration)) return true;
|
||||||
|
|
||||||
|
// If reference belongs to property initializer, show enclosing declaration instead
|
||||||
|
if (element instanceof JetProperty) {
|
||||||
|
JetProperty property = (JetProperty) element;
|
||||||
|
if (PsiTreeUtil.isAncestor(property.getInitializer(), ref.getElement(), false)) {
|
||||||
|
element = HierarchyUtils.getCallHierarchyElement(element.getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element != null) {
|
||||||
|
KotlinCallHierarchyNodeDescriptor d = methodToDescriptorMap.get(element);
|
||||||
|
if (d == null) {
|
||||||
|
d = new KotlinCallHierarchyNodeDescriptor(myProject, descriptor, element, false, true);
|
||||||
|
methodToDescriptorMap.put(element, d);
|
||||||
|
}
|
||||||
|
else if (!d.hasReference(ref)) {
|
||||||
|
d.incrementUsageCount();
|
||||||
|
}
|
||||||
|
d.addReference(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<node text="KClient.KClient()" base="true">
|
||||||
|
<node text="KA.KA()(2 usages) ()"/>
|
||||||
|
<node text="KA.foo(String) ()"/>
|
||||||
|
<node text="JA.JA()(2 usages) ()"/>
|
||||||
|
<node text="JA.getName() ()"/>
|
||||||
|
<node text="JA.foo(String) ()">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
class KA {
|
||||||
|
KA() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String name = "A";
|
||||||
|
public final String foo(String s) {
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient extends KClientBase {
|
||||||
|
public <caret>KClient() {
|
||||||
|
super();
|
||||||
|
new KA().foo(new KA().name);
|
||||||
|
new JA().foo(new JA().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
new KA().foo(new KA().name);
|
||||||
|
new JA().foo(new JA().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void bar() {
|
||||||
|
new KA().foo(new KA().name);
|
||||||
|
new JA().foo(new JA().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
open class JA() {
|
||||||
|
public var name: String = "A"
|
||||||
|
|
||||||
|
public open fun foo(s: String): String {
|
||||||
|
System.out.println(s)
|
||||||
|
return "A " + s
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<node text="KClient.bar()" base="true">
|
||||||
|
<node text="KA.KA()(2 usages) ()"/>
|
||||||
|
<node text="KA.foo(String)(2 usages) ()"/>
|
||||||
|
<node text="JA.JA()(4 usages) ()"/>
|
||||||
|
<node text="JA.getName()(2 usages) ()"/>
|
||||||
|
<node text="JA.foo(String)(2 usages) ()">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
<node text="Anonymous in bar() in KClient.run() ()">
|
||||||
|
<node text="KA.KA() ()"/>
|
||||||
|
<node text="KA.foo(String) ()"/>
|
||||||
|
<node text="JA.JA()(2 usages) ()"/>
|
||||||
|
<node text="JA.getName() ()"/>
|
||||||
|
<node text="JA.foo(String) ()">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
class KA {
|
||||||
|
public KA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String name = "A";
|
||||||
|
|
||||||
|
public final String foo(String s) {
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
public final void <caret>bar() {
|
||||||
|
new KA().foo("");
|
||||||
|
new JA().foo(new JA().getName());
|
||||||
|
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
new KA().foo("");
|
||||||
|
new JA().foo(new JA().getName());
|
||||||
|
}
|
||||||
|
}.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
open class JA() {
|
||||||
|
public var name: String = "A"
|
||||||
|
|
||||||
|
public open fun foo(s: String): String {
|
||||||
|
System.out.println(s)
|
||||||
|
return "A " + s
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<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="JA.JA()(4 usages)"/>
|
||||||
|
<node text="JA.foo(String)(2 usages)">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
<node text="packageVal"/>
|
||||||
|
<node text="packageFun(String)(2 usages)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
open class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class <caret>KClient(): KClientBase() {
|
||||||
|
{
|
||||||
|
fun localFun(s: String): String = packageFun(s)
|
||||||
|
|
||||||
|
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
localFun(packageVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<node text="KClient" base="true">
|
||||||
|
<node text="packageFun(String)(2 usages)"/>
|
||||||
|
<node text="KA(2 usages)"/>
|
||||||
|
<node text="KA.name"/>
|
||||||
|
<node text="KA.foo(String)"/>
|
||||||
|
<node text="JA.JA()(2 usages)"/>
|
||||||
|
<node text="JA.foo(String)">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
open class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient: KClientBase() {
|
||||||
|
class <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 JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<node text="MyEnum.FIRST" base="true">
|
||||||
|
<node text="packageFun(String)(2 usages)"/>
|
||||||
|
<node text="KA(2 usages)"/>
|
||||||
|
<node text="KA.name"/>
|
||||||
|
<node text="KA.foo(String)"/>
|
||||||
|
<node text="JA.JA()(2 usages)"/>
|
||||||
|
<node text="JA.foo(String)">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
open class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
<caret>FIRST {
|
||||||
|
val bar = run {
|
||||||
|
val localVal = packageFun("")
|
||||||
|
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
packageFun(localVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECOND {
|
||||||
|
{
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<node text="KClient.bar()" base="true">
|
||||||
|
<node text="KA(4 usages)"/>
|
||||||
|
<node text="KA.name(2 usages)"/>
|
||||||
|
<node text="KA.foo(String)(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="packageVal"/>
|
||||||
|
<node text="packageFun(String)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
class KClient() {
|
||||||
|
fun <caret>bar() {
|
||||||
|
fun localFun(s: String): String = packageFun(s)
|
||||||
|
val localVal = localFun("")
|
||||||
|
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
localFun(packageVal)
|
||||||
|
|
||||||
|
run {
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
packageFun(localVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class JA {
|
||||||
|
public JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<node text="KClient.T ()" base="true">
|
||||||
|
<node text="KA.name ()"/>
|
||||||
|
<node text="JA.JA()(2 usages) ()"/>
|
||||||
|
<node text="JA.foo(String) ()">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
<node text="packageFun(String)(2 usages) ()"/>
|
||||||
|
<node text="KA.foo(String) ()"/>
|
||||||
|
<node text="KA(2 usages) ()"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
open class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient: KClientBase() {
|
||||||
|
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 JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<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="JA.JA()(4 usages)"/>
|
||||||
|
<node text="JA.foo(String)(2 usages)">
|
||||||
|
<node text="PrintStream.println(String) (java.io)"/>
|
||||||
|
</node>
|
||||||
|
<node text="packageVal"/>
|
||||||
|
<node text="packageFun(String)(2 usages)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
open class KClientBase {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object <caret>KClient: KClientBase() {
|
||||||
|
{
|
||||||
|
fun localFun(s: String): String = packageFun(s)
|
||||||
|
|
||||||
|
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
localFun(packageVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class JA {
|
||||||
|
public JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<node text="KClient.bar" base="true">
|
||||||
|
<node text="KA(4 usages)"/>
|
||||||
|
<node text="KA.name(2 usages)"/>
|
||||||
|
<node text="KA.foo(String)(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="packageVal"/>
|
||||||
|
<node text="packageFun(String)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s
|
||||||
|
|
||||||
|
val packageVal = ""
|
||||||
|
|
||||||
|
class KClient() {
|
||||||
|
val <caret>bar: String
|
||||||
|
get() {
|
||||||
|
fun localFun(s: String): String = packageFun(s)
|
||||||
|
val localVal = localFun("")
|
||||||
|
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
localFun(packageVal)
|
||||||
|
|
||||||
|
run {
|
||||||
|
KA().foo(KA().name)
|
||||||
|
JA().foo(JA().name)
|
||||||
|
packageFun(localVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class JA {
|
||||||
|
public JA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
System.out.println(s);
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<node text="KA.KA()" base="true">
|
||||||
|
<node text="KClient.bar() ()"/>
|
||||||
|
<node text="KClient.getBar() ()"/>
|
||||||
|
<node text="KClient ()"/>
|
||||||
|
<node text="JA.newKA()"/>
|
||||||
|
<node text="JA"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
class KA {
|
||||||
|
public <caret>KA() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String name = "A";
|
||||||
|
|
||||||
|
public String foo(String s) {
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
new KA();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final a = new KA();
|
||||||
|
|
||||||
|
public final String getBar() {
|
||||||
|
return new KA().name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final KA bar() {
|
||||||
|
return new KA();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
open class JA() {
|
||||||
|
public var name: String = KA().getName()
|
||||||
|
|
||||||
|
public open fun newKA(): KA? {
|
||||||
|
return KA()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<node text="KA.foo(String)" base="true">
|
||||||
|
<node text="KClient(2 usages) ()"/>
|
||||||
|
<node text="KClient.getBar() ()"/>
|
||||||
|
<node text="KClient.bar() ()"/>
|
||||||
|
<node text="JA.foo()"/>
|
||||||
|
<node text="JA"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
class KA {
|
||||||
|
public final String name = "A"
|
||||||
|
|
||||||
|
public final String <caret>foo(String s) {
|
||||||
|
return "A " + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
new KA().foo("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String a = new KA().foo("");
|
||||||
|
|
||||||
|
public final String getBar() {
|
||||||
|
return new KA().foo("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String bar() {
|
||||||
|
return new KA().foo("");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
open class JA() {
|
||||||
|
public var name: String = KA().foo("")
|
||||||
|
|
||||||
|
public open fun foo(): String {
|
||||||
|
return KA().foo("")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<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="packageFun(String)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
class <caret>KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s + KA().name
|
||||||
|
|
||||||
|
val packageVal = KA().name
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val a = KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bar: String
|
||||||
|
get() = KA().name
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
fun localFun() = KA()
|
||||||
|
|
||||||
|
KA()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KClientObj {
|
||||||
|
val a = KA()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = new KA().getName();
|
||||||
|
|
||||||
|
public KA newKA() {
|
||||||
|
return new KA();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<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="packageFun(String)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
class KA {
|
||||||
|
val name = "A"
|
||||||
|
fun <caret>foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = KA().foo(s)
|
||||||
|
|
||||||
|
val packageVal = KA().foo("")
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
KA().foo("")
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val a = KA().foo("")
|
||||||
|
}
|
||||||
|
|
||||||
|
val bar: String
|
||||||
|
get() = KA().foo("")
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
fun localFun() = KA().foo("")
|
||||||
|
|
||||||
|
KA().foo("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KClientObj {
|
||||||
|
val a = KA().foo("")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = new KA().foo("");
|
||||||
|
|
||||||
|
public String foo() {
|
||||||
|
return new KA().foo("");
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<node text="T.KA ()" base="true">
|
||||||
|
<node text="main0.kt ()"/>
|
||||||
|
<node text="JA.newKA() ()"/>
|
||||||
|
<node text="KClientObj ()"/>
|
||||||
|
<node text="KClient ()"/>
|
||||||
|
<node text="packageFun(String) ()"/>
|
||||||
|
<node text="KClient.bar ()"/>
|
||||||
|
<node text="bar.localFun() ()"/>
|
||||||
|
<node text="KClient ()"/>
|
||||||
|
<node text="JA ()"/>
|
||||||
|
<node text="KClient.bar() ()"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
class T {
|
||||||
|
class <caret>KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s + T.KA().name
|
||||||
|
|
||||||
|
val packageVal = T.KA().name
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
T.KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val a = T.KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bar: String
|
||||||
|
get() = T.KA().name
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
fun localFun() = T.KA()
|
||||||
|
|
||||||
|
T.KA()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KClientObj {
|
||||||
|
val a = T.KA()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = new T.KA().getName();
|
||||||
|
|
||||||
|
public KA newKA() {
|
||||||
|
return new T.KA();
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<node text="T.KA ()" base="true">
|
||||||
|
<node text="KClient.bar ()"/>
|
||||||
|
<node text="JA.newKA() ()"/>
|
||||||
|
<node text="bar.localFun() ()"/>
|
||||||
|
<node text="JA ()"/>
|
||||||
|
<node text="KClient ()"/>
|
||||||
|
<node text="KClientObj ()"/>
|
||||||
|
<node text="KClient.bar() ()"/>
|
||||||
|
<node text="packageFun(String) ()"/>
|
||||||
|
<node text="KClient ()"/>
|
||||||
|
<node text="main0.kt ()"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
class T {
|
||||||
|
inner class <caret>KA {
|
||||||
|
val name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = s + T().KA().name
|
||||||
|
|
||||||
|
val packageVal = T().KA().name
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
T().KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val a = T().KA()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bar: String
|
||||||
|
get() = T().KA().name
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
fun localFun() = T().KA()
|
||||||
|
|
||||||
|
T().KA()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KClientObj {
|
||||||
|
val a = T().KA()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = new T().new KA().getName();
|
||||||
|
|
||||||
|
public KA newKA() {
|
||||||
|
return new T().new KA();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<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="KClient.bar(4 usages)"/>
|
||||||
|
<node text="KClientObj(4 usages)"/>
|
||||||
|
<node text="main0.kt(2 usages)"/>
|
||||||
|
<node text="packageFun(String)(2 usages)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
class KA {
|
||||||
|
var <caret>name = "A"
|
||||||
|
fun foo(s: String): String = "A: $s"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun packageFun(s: String): String = KA().name
|
||||||
|
|
||||||
|
val packageVal = KA().name
|
||||||
|
|
||||||
|
class KClient {
|
||||||
|
{
|
||||||
|
KA().name = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
val a = KA().name
|
||||||
|
}
|
||||||
|
|
||||||
|
val bar: String
|
||||||
|
get() = KA().name
|
||||||
|
set(value: String) {KA().name = value}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
fun localFun() = KA().name
|
||||||
|
|
||||||
|
val s = KA().name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KClientObj {
|
||||||
|
val a = KA().name
|
||||||
|
{
|
||||||
|
KA().name = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class JA {
|
||||||
|
public String name = new KA().getName();
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return new KA().getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,15 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.hierarchy;
|
package org.jetbrains.jet.plugin.hierarchy;
|
||||||
|
|
||||||
import com.intellij.ide.hierarchy.HierarchyBrowserBaseEx;
|
import com.intellij.ide.hierarchy.*;
|
||||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
|
||||||
import com.intellij.ide.hierarchy.LanguageTypeHierarchy;
|
|
||||||
import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure;
|
import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure;
|
||||||
import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure;
|
import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure;
|
||||||
import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure;
|
import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure;
|
||||||
import com.intellij.lang.Language;
|
import com.intellij.lang.Language;
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
|
||||||
import com.intellij.openapi.projectRoots.Sdk;
|
import com.intellij.openapi.projectRoots.Sdk;
|
||||||
import com.intellij.openapi.util.Computable;
|
import com.intellij.openapi.util.Computable;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
@@ -38,6 +36,8 @@ import com.intellij.util.ArrayUtil;
|
|||||||
import com.intellij.util.Processor;
|
import com.intellij.util.Processor;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||||
|
import org.jetbrains.jet.plugin.hierarchy.calls.KotlinCalleeMethodsTreeStructure;
|
||||||
|
import org.jetbrains.jet.plugin.hierarchy.calls.KotlinCallerMethodsTreeStructure;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -68,11 +68,24 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
|||||||
doHierarchyTest(getSubTypesHierarchyStructure(), getFilesToConfigure());
|
doHierarchyTest(getSubTypesHierarchyStructure(), getFilesToConfigure());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void doCallerHierarchyTest(@NotNull String folderName) throws Exception {
|
||||||
|
this.folderName = folderName;
|
||||||
|
doHierarchyTest(getCallerHierarchyStructure(), getFilesToConfigure());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doCalleeHierarchyTest(@NotNull String folderName) throws Exception {
|
||||||
|
this.folderName = folderName;
|
||||||
|
doHierarchyTest(getCalleeHierarchyStructure(), getFilesToConfigure());
|
||||||
|
}
|
||||||
|
|
||||||
private Computable<HierarchyTreeStructure> getSuperTypesHierarchyStructure() {
|
private Computable<HierarchyTreeStructure> getSuperTypesHierarchyStructure() {
|
||||||
return new Computable<HierarchyTreeStructure>() {
|
return new Computable<HierarchyTreeStructure>() {
|
||||||
@Override
|
@Override
|
||||||
public HierarchyTreeStructure compute() {
|
public HierarchyTreeStructure compute() {
|
||||||
return new SupertypesHierarchyTreeStructure(getProject(), (PsiClass) getElementAtCaret());
|
return new SupertypesHierarchyTreeStructure(
|
||||||
|
getProject(),
|
||||||
|
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage()))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -81,8 +94,11 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
|||||||
return new Computable<HierarchyTreeStructure>() {
|
return new Computable<HierarchyTreeStructure>() {
|
||||||
@Override
|
@Override
|
||||||
public HierarchyTreeStructure compute() {
|
public HierarchyTreeStructure compute() {
|
||||||
return new SubtypesHierarchyTreeStructure(getProject(), (PsiClass) getElementAtCaret(),
|
return new SubtypesHierarchyTreeStructure(
|
||||||
HierarchyBrowserBaseEx.SCOPE_PROJECT);
|
getProject(),
|
||||||
|
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||||
|
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -91,14 +107,43 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
|||||||
return new Computable<HierarchyTreeStructure>() {
|
return new Computable<HierarchyTreeStructure>() {
|
||||||
@Override
|
@Override
|
||||||
public HierarchyTreeStructure compute() {
|
public HierarchyTreeStructure compute() {
|
||||||
return new TypeHierarchyTreeStructure(getProject(), (PsiClass) getElementAtCaret(),
|
return new TypeHierarchyTreeStructure(
|
||||||
HierarchyBrowserBaseEx.SCOPE_PROJECT);
|
getProject(),
|
||||||
|
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||||
|
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private PsiElement getElementAtCaret() {
|
private Computable<HierarchyTreeStructure> getCallerHierarchyStructure() {
|
||||||
PsiElement target = LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage()).getTarget(getDataContext());
|
return new Computable<HierarchyTreeStructure>() {
|
||||||
|
@Override
|
||||||
|
public HierarchyTreeStructure compute() {
|
||||||
|
return new KotlinCallerMethodsTreeStructure(
|
||||||
|
getProject(),
|
||||||
|
getElementAtCaret(LanguageCallHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||||
|
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Computable<HierarchyTreeStructure> getCalleeHierarchyStructure() {
|
||||||
|
return new Computable<HierarchyTreeStructure>() {
|
||||||
|
@Override
|
||||||
|
public HierarchyTreeStructure compute() {
|
||||||
|
return new KotlinCalleeMethodsTreeStructure(
|
||||||
|
getProject(),
|
||||||
|
getElementAtCaret(LanguageCallHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||||
|
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private PsiElement getElementAtCaret(HierarchyProvider provider) {
|
||||||
|
PsiElement target = provider.getTarget(getDataContext());
|
||||||
assert target != null : "Cannot apply action for element at caret";
|
assert target != null : "Cannot apply action for element at caret";
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -111,8 +156,8 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
|||||||
|
|
||||||
private DataContext getDataContext() {
|
private DataContext getDataContext() {
|
||||||
MapDataContext context = new MapDataContext();
|
MapDataContext context = new MapDataContext();
|
||||||
context.put(PlatformDataKeys.PROJECT, getProject());
|
context.put(CommonDataKeys.PROJECT, getProject());
|
||||||
context.put(PlatformDataKeys.EDITOR, getEditor());
|
context.put(CommonDataKeys.EDITOR, getEditor());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.hierarchy.AbstractHierarchyTest;
|
|||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@InnerTestClasses({HierarchyTestGenerated.Type.class, HierarchyTestGenerated.Super.class, HierarchyTestGenerated.Sub.class})
|
@InnerTestClasses({HierarchyTestGenerated.Type.class, HierarchyTestGenerated.Super.class, HierarchyTestGenerated.Sub.class, HierarchyTestGenerated.Callers.class, HierarchyTestGenerated.Callees.class})
|
||||||
public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
||||||
@TestMetadata("idea/testData/hierarchy/class/type")
|
@TestMetadata("idea/testData/hierarchy/class/type")
|
||||||
public static class Type extends AbstractHierarchyTest {
|
public static class Type extends AbstractHierarchyTest {
|
||||||
@@ -191,11 +191,109 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/hierarchy/calls/callers")
|
||||||
|
public static class Callers extends AbstractHierarchyTest {
|
||||||
|
public void testAllFilesPresentInCallers() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/hierarchy/calls/callers"), Pattern.compile("^(.+)$"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaConstructor")
|
||||||
|
public void testJavaConstructor() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/javaConstructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaMethod")
|
||||||
|
public void testJavaMethod() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/javaMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinClass")
|
||||||
|
public void testKotlinClass() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinFunction")
|
||||||
|
public void testKotlinFunction() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinFunction");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinNestedClass")
|
||||||
|
public void testKotlinNestedClass() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinNestedClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinNestedInnerClass")
|
||||||
|
public void testKotlinNestedInnerClass() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinProperty")
|
||||||
|
public void testKotlinProperty() throws Exception {
|
||||||
|
doCallerHierarchyTest("idea/testData/hierarchy/calls/callers/kotlinProperty");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/hierarchy/calls/callees")
|
||||||
|
public static class Callees extends AbstractHierarchyTest {
|
||||||
|
public void testAllFilesPresentInCallees() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/hierarchy/calls/callees"), Pattern.compile("^(.+)$"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaConstructor")
|
||||||
|
public void testJavaConstructor() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/javaConstructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaMethod")
|
||||||
|
public void testJavaMethod() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/javaMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinClass")
|
||||||
|
public void testKotlinClass() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinClassObject")
|
||||||
|
public void testKotlinClassObject() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinClassObject");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinEnumClass")
|
||||||
|
public void testKotlinEnumClass() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinEnumClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinFunction")
|
||||||
|
public void testKotlinFunction() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinFunction");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinNestedClass")
|
||||||
|
public void testKotlinNestedClass() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinNestedClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinObject")
|
||||||
|
public void testKotlinObject() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinObject");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinProperty")
|
||||||
|
public void testKotlinProperty() throws Exception {
|
||||||
|
doCalleeHierarchyTest("idea/testData/hierarchy/calls/callees/kotlinProperty");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
TestSuite suite = new TestSuite("HierarchyTestGenerated");
|
TestSuite suite = new TestSuite("HierarchyTestGenerated");
|
||||||
suite.addTestSuite(Type.class);
|
suite.addTestSuite(Type.class);
|
||||||
suite.addTestSuite(Super.class);
|
suite.addTestSuite(Super.class);
|
||||||
suite.addTestSuite(Sub.class);
|
suite.addTestSuite(Sub.class);
|
||||||
|
suite.addTestSuite(Callers.class);
|
||||||
|
suite.addTestSuite(Callees.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user