diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java
index fe56b0b2699..d8ad1dbde64 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java
@@ -102,17 +102,17 @@ public class JetObjectDeclaration extends JetNamedDeclarationStub
+
+
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/HierarchyUtils.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/HierarchyUtils.java
new file mode 100644
index 00000000000..159590a9e91
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/HierarchyUtils.java
@@ -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 IS_CALL_HIERARCHY_ELEMENT = new Predicate() {
+ @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);
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyBrowser.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyBrowser.java
new file mode 100644
index 00000000000..72fa02f590e
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyBrowser.java
@@ -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 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 getComparator() {
+ return JavaHierarchyUtil.getComparator(myProject);
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyNodeDescriptor.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyNodeDescriptor.java
new file mode 100644
index 00000000000..842cd12dc34
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyNodeDescriptor.java
@@ -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 references = new ArrayList();
+ 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() {
+ @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();
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyProvider.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyProvider.java
new file mode 100644
index 00000000000..21b655c9f16
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallHierarchyProvider.java
@@ -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);
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallTreeStructure.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallTreeStructure.java
new file mode 100644
index 00000000000..3f1d79fc0dc
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallTreeStructure.java
@@ -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;
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCalleeMethodsTreeStructure.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCalleeMethodsTreeStructure.java
new file mode 100644
index 00000000000..4490126b4b9
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCalleeMethodsTreeStructure.java
@@ -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 result;
+
+ private VisitorBase(BindingContext bindingContext, ArrayList 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 result = new ArrayList();
+ 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 declarationToDescriptorMap =
+ new HashMap();
+
+ ArrayList result = new ArrayList();
+
+ 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);
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java
new file mode 100644
index 00000000000..c94f81e9baa
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java
@@ -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 methodToDescriptorMap =
+ new HashMap();
+
+ 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 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 methodToDescriptorMap,
+ SearchScope searchScope
+ ) {
+ Processor processor = new FilteringProcessor(
+ new Condition() {
+ @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 defaultQueryProcessor(
+ final HierarchyNodeDescriptor descriptor,
+ final Map methodToDescriptorMap,
+ final boolean kotlinOnly
+ ) {
+ return new ReadActionProcessor() {
+ @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;
+ }
+ };
+ }
+}
diff --git a/idea/testData/hierarchy/calls/callees/javaConstructor/JavaConstructor_verification.xml b/idea/testData/hierarchy/calls/callees/javaConstructor/JavaConstructor_verification.xml
new file mode 100644
index 00000000000..7319ab48fef
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaConstructor/JavaConstructor_verification.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/javaConstructor/main0.java b/idea/testData/hierarchy/calls/callees/javaConstructor/main0.java
new file mode 100644
index 00000000000..ff6732ac52b
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaConstructor/main0.java
@@ -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 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());
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/javaConstructor/main1.kt b/idea/testData/hierarchy/calls/callees/javaConstructor/main1.kt
new file mode 100644
index 00000000000..156782a7241
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaConstructor/main1.kt
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/javaMethod/JavaMethod_verification.xml b/idea/testData/hierarchy/calls/callees/javaMethod/JavaMethod_verification.xml
new file mode 100644
index 00000000000..7e8f8c64157
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaMethod/JavaMethod_verification.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/javaMethod/main0.java b/idea/testData/hierarchy/calls/callees/javaMethod/main0.java
new file mode 100644
index 00000000000..c18428c98ea
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaMethod/main0.java
@@ -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 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();
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/javaMethod/main1.kt b/idea/testData/hierarchy/calls/callees/javaMethod/main1.kt
new file mode 100644
index 00000000000..c5621a75580
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/javaMethod/main1.kt
@@ -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
+ }
+}
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClass/KotlinClass_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinClass/KotlinClass_verification.xml
new file mode 100644
index 00000000000..efb4bd5de75
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClass/KotlinClass_verification.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClass/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinClass/main0.kt
new file mode 100644
index 00000000000..bd229783c3f
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClass/main0.kt
@@ -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 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)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClass/main1.java b/idea/testData/hierarchy/calls/callees/kotlinClass/main1.java
new file mode 100644
index 00000000000..efb7db9b4a5
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClass/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public String name = "A";
+
+ public JA() {
+
+ }
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClassObject/KotlinClassObject_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinClassObject/KotlinClassObject_verification.xml
new file mode 100644
index 00000000000..5916f091b3f
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClassObject/KotlinClassObject_verification.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClassObject/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinClassObject/main0.kt
new file mode 100644
index 00000000000..889011598e9
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClassObject/main0.kt
@@ -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 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)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinClassObject/main1.java b/idea/testData/hierarchy/calls/callees/kotlinClassObject/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinClassObject/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinEnumClass/KotlinEnumClass_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/KotlinEnumClass_verification.xml
new file mode 100644
index 00000000000..1328a954edd
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/KotlinEnumClass_verification.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main0.kt
new file mode 100644
index 00000000000..8a52e67ffd7
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main0.kt
@@ -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 {
+ 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)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main1.java b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinEnumClass/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinFunction/KotlinFunction_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinFunction/KotlinFunction_verification.xml
new file mode 100644
index 00000000000..9fa3d970e47
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinFunction/KotlinFunction_verification.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/kotlinFunction/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinFunction/main0.kt
new file mode 100644
index 00000000000..e8ff1e20b92
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinFunction/main0.kt
@@ -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 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)
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinFunction/main1.java b/idea/testData/hierarchy/calls/callees/kotlinFunction/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinFunction/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinNestedClass/KotlinNestedClass_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/KotlinNestedClass_verification.xml
new file mode 100644
index 00000000000..1ab9d67a932
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/KotlinNestedClass_verification.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main0.kt
new file mode 100644
index 00000000000..358a498f89a
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main0.kt
@@ -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 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)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main1.java b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinNestedClass/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinObject/KotlinObject_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinObject/KotlinObject_verification.xml
new file mode 100644
index 00000000000..efb4bd5de75
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinObject/KotlinObject_verification.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/kotlinObject/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinObject/main0.kt
new file mode 100644
index 00000000000..0219c2fa943
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinObject/main0.kt
@@ -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 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)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinObject/main1.java b/idea/testData/hierarchy/calls/callees/kotlinObject/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinObject/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinProperty/KotlinProperty_verification.xml b/idea/testData/hierarchy/calls/callees/kotlinProperty/KotlinProperty_verification.xml
new file mode 100644
index 00000000000..fc2a03a5df2
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinProperty/KotlinProperty_verification.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callees/kotlinProperty/main0.kt b/idea/testData/hierarchy/calls/callees/kotlinProperty/main0.kt
new file mode 100644
index 00000000000..884b9e3a379
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinProperty/main0.kt
@@ -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 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 ""
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callees/kotlinProperty/main1.java b/idea/testData/hierarchy/calls/callees/kotlinProperty/main1.java
new file mode 100644
index 00000000000..c57b6f49533
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callees/kotlinProperty/main1.java
@@ -0,0 +1,12 @@
+class JA {
+ public JA() {
+
+ }
+
+ public String name = "A";
+
+ public String foo(String s) {
+ System.out.println(s);
+ return "A " + s;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/javaConstructor/JavaConstructor_verification.xml b/idea/testData/hierarchy/calls/callers/javaConstructor/JavaConstructor_verification.xml
new file mode 100644
index 00000000000..9b195204881
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaConstructor/JavaConstructor_verification.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/javaConstructor/main0.java b/idea/testData/hierarchy/calls/callers/javaConstructor/main0.java
new file mode 100644
index 00000000000..04707c611b6
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaConstructor/main0.java
@@ -0,0 +1,27 @@
+class KA {
+ public 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();
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/javaConstructor/main1.kt b/idea/testData/hierarchy/calls/callers/javaConstructor/main1.kt
new file mode 100644
index 00000000000..9317baf5b79
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaConstructor/main1.kt
@@ -0,0 +1,7 @@
+open class JA() {
+ public var name: String = KA().getName()
+
+ public open fun newKA(): KA? {
+ return KA()
+ }
+}
diff --git a/idea/testData/hierarchy/calls/callers/javaMethod/JavaMethod_verification.xml b/idea/testData/hierarchy/calls/callers/javaMethod/JavaMethod_verification.xml
new file mode 100644
index 00000000000..1d1abf12886
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaMethod/JavaMethod_verification.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/javaMethod/main0.java b/idea/testData/hierarchy/calls/callers/javaMethod/main0.java
new file mode 100644
index 00000000000..bd49d048794
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaMethod/main0.java
@@ -0,0 +1,23 @@
+class KA {
+ public final String name = "A"
+
+ public final String 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("");
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/javaMethod/main1.kt b/idea/testData/hierarchy/calls/callers/javaMethod/main1.kt
new file mode 100644
index 00000000000..25eadaa3b58
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/javaMethod/main1.kt
@@ -0,0 +1,7 @@
+open class JA() {
+ public var name: String = KA().foo("")
+
+ public open fun foo(): String {
+ return KA().foo("")
+ }
+}
diff --git a/idea/testData/hierarchy/calls/callers/kotlinClass/KotlinClass_verification.xml b/idea/testData/hierarchy/calls/callers/kotlinClass/KotlinClass_verification.xml
new file mode 100644
index 00000000000..56904b54ddc
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinClass/KotlinClass_verification.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/kotlinClass/main0.kt b/idea/testData/hierarchy/calls/callers/kotlinClass/main0.kt
new file mode 100644
index 00000000000..3562b15fc97
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinClass/main0.kt
@@ -0,0 +1,31 @@
+class 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()
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinClass/main1.java b/idea/testData/hierarchy/calls/callers/kotlinClass/main1.java
new file mode 100644
index 00000000000..bd801cb1c3b
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinClass/main1.java
@@ -0,0 +1,7 @@
+class JA {
+ public String name = new KA().getName();
+
+ public KA newKA() {
+ return new KA();
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinFunction/KotlinFunction_verification.xml b/idea/testData/hierarchy/calls/callers/kotlinFunction/KotlinFunction_verification.xml
new file mode 100644
index 00000000000..43a32cc0524
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinFunction/KotlinFunction_verification.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/kotlinFunction/main0.kt b/idea/testData/hierarchy/calls/callers/kotlinFunction/main0.kt
new file mode 100644
index 00000000000..3baf3fc9af6
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinFunction/main0.kt
@@ -0,0 +1,31 @@
+class KA {
+ val name = "A"
+ fun 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("")
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinFunction/main1.java b/idea/testData/hierarchy/calls/callers/kotlinFunction/main1.java
new file mode 100644
index 00000000000..5f5d2903bea
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinFunction/main1.java
@@ -0,0 +1,7 @@
+class JA {
+ public String name = new KA().foo("");
+
+ public String foo() {
+ return new KA().foo("");
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedClass/KotlinNestedClass_verification.xml b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/KotlinNestedClass_verification.xml
new file mode 100644
index 00000000000..4658419a1cb
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/KotlinNestedClass_verification.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main0.kt b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main0.kt
new file mode 100644
index 00000000000..4d7c0cbe47f
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main0.kt
@@ -0,0 +1,33 @@
+class T {
+ class 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()
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main1.java b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main1.java
new file mode 100644
index 00000000000..a2475ba825d
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedClass/main1.java
@@ -0,0 +1,7 @@
+class JA {
+ public String name = new T.KA().getName();
+
+ public KA newKA() {
+ return new T.KA();
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/KotlinNestedInnerClass_verification.xml b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/KotlinNestedInnerClass_verification.xml
new file mode 100644
index 00000000000..39c1dcbcab6
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/KotlinNestedInnerClass_verification.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main0.kt b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main0.kt
new file mode 100644
index 00000000000..b5d0facd385
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main0.kt
@@ -0,0 +1,33 @@
+class T {
+ inner class 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()
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main1.java b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main1.java
new file mode 100644
index 00000000000..b00de364b22
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinNestedInnerClass/main1.java
@@ -0,0 +1,7 @@
+class JA {
+ public String name = new T().new KA().getName();
+
+ public KA newKA() {
+ return new T().new KA();
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinProperty/KotlinProperty_verification.xml b/idea/testData/hierarchy/calls/callers/kotlinProperty/KotlinProperty_verification.xml
new file mode 100644
index 00000000000..e1d9ffe2b9e
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinProperty/KotlinProperty_verification.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/idea/testData/hierarchy/calls/callers/kotlinProperty/main0.kt b/idea/testData/hierarchy/calls/callers/kotlinProperty/main0.kt
new file mode 100644
index 00000000000..06941927ef7
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinProperty/main0.kt
@@ -0,0 +1,35 @@
+class KA {
+ var 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 = ""
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/hierarchy/calls/callers/kotlinProperty/main1.java b/idea/testData/hierarchy/calls/callers/kotlinProperty/main1.java
new file mode 100644
index 00000000000..aa0728f4147
--- /dev/null
+++ b/idea/testData/hierarchy/calls/callers/kotlinProperty/main1.java
@@ -0,0 +1,7 @@
+class JA {
+ public String name = new KA().getName();
+
+ public String getName() {
+ return new KA().getName();
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/plugin/hierarchy/AbstractHierarchyTest.java b/idea/tests/org/jetbrains/jet/plugin/hierarchy/AbstractHierarchyTest.java
index b1a314156df..638962d1210 100644
--- a/idea/tests/org/jetbrains/jet/plugin/hierarchy/AbstractHierarchyTest.java
+++ b/idea/tests/org/jetbrains/jet/plugin/hierarchy/AbstractHierarchyTest.java
@@ -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 getSuperTypesHierarchyStructure() {
return new Computable() {
@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() {
@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() {
@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 getCallerHierarchyStructure() {
+ return new Computable() {
+ @Override
+ public HierarchyTreeStructure compute() {
+ return new KotlinCallerMethodsTreeStructure(
+ getProject(),
+ getElementAtCaret(LanguageCallHierarchy.INSTANCE.forLanguage(getLanguage())),
+ HierarchyBrowserBaseEx.SCOPE_PROJECT
+ );
+ }
+ };
+ }
+
+ private Computable getCalleeHierarchyStructure() {
+ return new Computable() {
+ @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;
}
diff --git a/idea/tests/org/jetbrains/jet/plugin/hierarchy/HierarchyTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/hierarchy/HierarchyTestGenerated.java
index ac1c5088ac9..2dea2a4f117 100644
--- a/idea/tests/org/jetbrains/jet/plugin/hierarchy/HierarchyTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/plugin/hierarchy/HierarchyTestGenerated.java
@@ -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;
}
}