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 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 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 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; } }