Implement call hierarchy
This commit is contained in:
@@ -102,17 +102,17 @@ public class JetObjectDeclaration extends JetNamedDeclarationStub<PsiJetObjectSt
|
||||
@Override
|
||||
@Nullable
|
||||
public JetModifierList getModifierList() {
|
||||
PsiElement parent = getParent();
|
||||
if (isClassObject(parent)) {
|
||||
if (isClassObject()) {
|
||||
PsiElement parent = getParent();
|
||||
assert parent instanceof JetDeclaration;
|
||||
return ((JetDeclaration)parent).getModifierList();
|
||||
}
|
||||
return (JetModifierList) findChildByType(JetNodeTypes.MODIFIER_LIST);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isClassObject(@NotNull PsiElement parent) {
|
||||
return parent.getNode().getElementType().equals(JetNodeTypes.CLASS_OBJECT);
|
||||
public boolean isClassObject() {
|
||||
PsiElement parent = getParent();
|
||||
return parent != null && parent.getNode().getElementType().equals(JetNodeTypes.CLASS_OBJECT);
|
||||
}
|
||||
|
||||
@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,
|
||||
testModelWithDirectories("idea/testData/hierarchy/class/type", "doTypeClassHierarchyTest"),
|
||||
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(
|
||||
|
||||
@@ -263,6 +263,13 @@
|
||||
<library.presentationProvider implementation="org.jetbrains.jet.plugin.framework.JsHeaderLibraryPresentationProvider"/>
|
||||
|
||||
<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.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;
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyBrowserBaseEx;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.ide.hierarchy.LanguageTypeHierarchy;
|
||||
import com.intellij.ide.hierarchy.*;
|
||||
import com.intellij.ide.hierarchy.type.SubtypesHierarchyTreeStructure;
|
||||
import com.intellij.ide.hierarchy.type.SupertypesHierarchyTreeStructure;
|
||||
import com.intellij.ide.hierarchy.type.TypeHierarchyTreeStructure;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -38,6 +36,8 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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.util.ArrayList;
|
||||
@@ -68,11 +68,24 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
||||
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() {
|
||||
return new Computable<HierarchyTreeStructure>() {
|
||||
@Override
|
||||
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>() {
|
||||
@Override
|
||||
public HierarchyTreeStructure compute() {
|
||||
return new SubtypesHierarchyTreeStructure(getProject(), (PsiClass) getElementAtCaret(),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT);
|
||||
return new SubtypesHierarchyTreeStructure(
|
||||
getProject(),
|
||||
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -91,14 +107,43 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
||||
return new Computable<HierarchyTreeStructure>() {
|
||||
@Override
|
||||
public HierarchyTreeStructure compute() {
|
||||
return new TypeHierarchyTreeStructure(getProject(), (PsiClass) getElementAtCaret(),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT);
|
||||
return new TypeHierarchyTreeStructure(
|
||||
getProject(),
|
||||
(PsiClass) getElementAtCaret(LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage())),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PsiElement getElementAtCaret() {
|
||||
PsiElement target = LanguageTypeHierarchy.INSTANCE.forLanguage(getLanguage()).getTarget(getDataContext());
|
||||
private Computable<HierarchyTreeStructure> getCallerHierarchyStructure() {
|
||||
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";
|
||||
return target;
|
||||
}
|
||||
@@ -111,8 +156,8 @@ public abstract class AbstractHierarchyTest extends HierarchyViewTestBase {
|
||||
|
||||
private DataContext getDataContext() {
|
||||
MapDataContext context = new MapDataContext();
|
||||
context.put(PlatformDataKeys.PROJECT, getProject());
|
||||
context.put(PlatformDataKeys.EDITOR, getEditor());
|
||||
context.put(CommonDataKeys.PROJECT, getProject());
|
||||
context.put(CommonDataKeys.EDITOR, getEditor());
|
||||
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 */
|
||||
@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 {
|
||||
@TestMetadata("idea/testData/hierarchy/class/type")
|
||||
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() {
|
||||
TestSuite suite = new TestSuite("HierarchyTestGenerated");
|
||||
suite.addTestSuite(Type.class);
|
||||
suite.addTestSuite(Super.class);
|
||||
suite.addTestSuite(Sub.class);
|
||||
suite.addTestSuite(Callers.class);
|
||||
suite.addTestSuite(Callees.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user