summaryrefslogtreecommitdiff
path: root/python/src/com/jetbrains/python/hierarchy
diff options
context:
space:
mode:
Diffstat (limited to 'python/src/com/jetbrains/python/hierarchy')
-rw-r--r--python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java (renamed from python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java)31
-rw-r--r--python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java4
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java101
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java76
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java85
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java42
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java42
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java163
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java18
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java25
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java27
11 files changed, 562 insertions, 52 deletions
diff --git a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java b/python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java
index ea8c250b2e4f..c9720fb01af3 100644
--- a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java
+++ b/python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java
@@ -19,15 +19,14 @@ import com.intellij.ide.IdeBundle;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.navigation.ItemPresentation;
-import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
import org.jetbrains.annotations.NotNull;
-
-import java.awt.*;
+import org.jetbrains.annotations.Nullable;
/**
* Created by IntelliJ IDEA.
@@ -35,14 +34,14 @@ import java.awt.*;
* Date: Jul 31, 2009
* Time: 6:26:37 PM
*/
-public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
-
- public PyTypeHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
+public class PyHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
+ public PyHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
super(element.getProject(), parentDescriptor, element, isBase);
}
- public PyClass getClassElement() {
- return (PyClass)myElement;
+ @Nullable
+ public PsiElement getPsiElement() {
+ return myElement;
}
public boolean isValid() {
@@ -55,10 +54,6 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
final CompositeAppearance oldText = myHighlightedText;
myHighlightedText = new CompositeAppearance();
- TextAttributes classNameAttributes = null;
- if (myColor != null) {
- classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
- }
NavigatablePsiElement element = (NavigatablePsiElement)myElement;
if (element == null) {
@@ -71,10 +66,14 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
final ItemPresentation presentation = element.getPresentation();
if (presentation != null) {
- final PyClass cl = getClassElement();
- myHighlightedText.getEnding().addText(cl.getName(), classNameAttributes);
- myHighlightedText.getEnding()
- .addText(" (" + cl.getContainingFile().getName() + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
+ if (element instanceof PyFunction) {
+ final PyClass cls = ((PyFunction)element).getContainingClass();
+ if (cls != null) {
+ myHighlightedText.getEnding().addText(cls.getName() + ".");
+ }
+ }
+ myHighlightedText.getEnding().addText(presentation.getPresentableText());
+ myHighlightedText.getEnding().addText(" " + presentation.getLocationString(), HierarchyNodeDescriptor.getPackageNameAttributes());
}
myName = myHighlightedText.getText();
diff --git a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java b/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
index 643440571618..817d462044fe 100644
--- a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
+++ b/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
@@ -52,10 +52,10 @@ public class PyTypeHierarchyBrowser extends TypeHierarchyBrowserBase {
@Nullable
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
- if (!(descriptor instanceof PyTypeHierarchyNodeDescriptor)) {
+ if (!(descriptor instanceof PyHierarchyNodeDescriptor)) {
return null;
}
- return ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement();
+ return ((PyHierarchyNodeDescriptor)descriptor).getPsiElement();
}
protected void createTrees(@NotNull Map<String, JTree> trees) {
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java
new file mode 100644
index 000000000000..c5224e617ec9
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.ide.util.treeView.NodeDescriptor;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.PopupHandler;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyUtils;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * @author novokrest
+ */
+public class PyCallHierarchyBrowser extends CallHierarchyBrowserBase {
+ private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.hierarchy.call.PyCallHierarchyBrowser");
+ private static final String GROUP_PY_CALL_HIERARCHY_POPUP = "PyCallHierarchyPopupMenu";
+
+ public PyCallHierarchyBrowser(PsiElement function) {
+ super(function.getProject(), function);
+ }
+
+ @Nullable
+ @Override
+ protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ return pyDescriptor.getPsiElement();
+ }
+ return null;
+ }
+
+ @Override
+ protected void createTrees(@NotNull Map<String, JTree> type2TreeMap) {
+ final ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(GROUP_PY_CALL_HIERARCHY_POPUP);
+
+ final JTree callerTree = createHierarchyTree(group);
+ final JTree calleeTree = createHierarchyTree(group);
+
+ type2TreeMap.put(CALLER_TYPE, callerTree);
+ type2TreeMap.put(CALLEE_TYPE, calleeTree);
+ }
+
+ private JTree createHierarchyTree(ActionGroup group) {
+ final JTree tree = createTree(false);
+ PopupHandler.installPopupHandler(tree, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
+ return tree;
+ }
+
+ @Override
+ protected boolean isApplicableElement(@NotNull PsiElement element) {
+ return element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
+ }
+
+ @Nullable
+ @Override
+ protected HierarchyTreeStructure createHierarchyTreeStructure(@NotNull String typeName, @NotNull PsiElement psiElement) {
+ if (CALLER_TYPE.equals(typeName)) {
+ return new PyCallerFunctionTreeStructure(myProject, psiElement, getCurrentScopeType());
+ }
+ else if (CALLEE_TYPE.equals(typeName)) {
+ return new PyCalleeFunctionTreeStructure(myProject, psiElement, getCurrentScopeType());
+ }
+ else {
+ LOG.error("unexpected type: " + typeName);
+ return null;
+ }
+ }
+
+ @Nullable
+ @Override
+ protected Comparator<NodeDescriptor> getComparator() {
+ return PyHierarchyUtils.getComparator(myProject);
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java
new file mode 100644
index 000000000000..67c0d6ddfa0b
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+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 com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author novokrest
+ */
+public class PyCallHierarchyProvider implements HierarchyProvider {
+ @Nullable
+ @Override
+ public PsiElement getTarget(@NotNull DataContext dataContext) {
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ if (project == null) return null;
+
+ PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
+ if (element == null) {
+ Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ if (editor != null) {
+ PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+ if (file == null) return null;
+
+ element = TargetElementUtilBase.findTargetElement(editor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED |
+ TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED |
+ TargetElementUtilBase.LOOKUP_ITEM_ACCEPTED);
+ if (element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile) {
+ return element;
+ }
+
+ element = file.findElementAt(editor.getCaretModel().getOffset());
+ }
+ }
+ return PsiTreeUtil.getNonStrictParentOfType(element, PyFunction.class, PyClass.class, PyFile.class);
+ }
+
+ @NotNull
+ @Override
+ public HierarchyBrowser createHierarchyBrowser(PsiElement target) {
+ return new PyCallHierarchyBrowser(target);
+ }
+
+ @Override
+ public void browserActivated(@NotNull HierarchyBrowser hierarchyBrowser) {
+ ((PyCallHierarchyBrowser)hierarchyBrowser).changeView(CallHierarchyBrowserBase.CALLER_TYPE);
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java
new file mode 100644
index 000000000000..c5d60138299c
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ArrayUtil;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public abstract class PyCallHierarchyTreeStructureBase extends HierarchyTreeStructure {
+ private final String myScopeType;
+
+ public PyCallHierarchyTreeStructureBase(Project project, PsiElement element, String currentScopeType) {
+ super(project, new PyHierarchyNodeDescriptor(null, element, true));
+ myScopeType = currentScopeType;
+ }
+
+ @NotNull
+ protected abstract List<PsiElement> getChildren(@NotNull PyElement element);
+
+ @NotNull
+ @Override
+ protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
+ final List<PyHierarchyNodeDescriptor> descriptors = new ArrayList<PyHierarchyNodeDescriptor>();
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ final PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ final PsiElement element = pyDescriptor.getPsiElement();
+ final boolean isCallable = element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
+ HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
+ if (!(element instanceof PyElement) || !isCallable || nodeDescriptor == null) {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ final List<PsiElement> children = getChildren((PyElement)element);
+
+ final HashMap<PsiElement, PyHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<PsiElement, PyHierarchyNodeDescriptor>();
+ PsiElement baseClass = element instanceof PyFunction ? ((PyFunction)element).getContainingClass() : null;
+
+ for (PsiElement caller : children) {
+ if (isInScope(baseClass, caller, myScopeType)) {
+ PyHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
+ if (callerDescriptor == null) {
+ callerDescriptor = new PyHierarchyNodeDescriptor(descriptor, caller, false);
+ callerToDescriptorMap.put(caller, callerDescriptor);
+ descriptors.add(callerDescriptor);
+ }
+ }
+ }
+
+ }
+ return ArrayUtil.toObjectArray(descriptors);
+ }
+
+ @Override
+ public boolean isAlwaysShowPlus() {
+ return true;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java
new file mode 100644
index 000000000000..b0465083ef05
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyCalleeFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
+ public PyCalleeFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
+ super(project, element, currentScopeType);
+ }
+
+ @NotNull
+ @Override
+ protected List<PsiElement> getChildren(@NotNull PyElement element) {
+ final List<PsiElement> callees = new ArrayList<PsiElement>();
+ // TODO: Add callees from the dynamic call data manager
+ callees.addAll(PyStaticCallHierarchyUtil.getCallees(element));
+ return callees;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java
new file mode 100644
index 000000000000..d45e79ce8d95
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyCallerFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
+ public PyCallerFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
+ super(project, element, currentScopeType);
+ }
+
+ @NotNull
+ @Override
+ protected List<PsiElement> getChildren(@NotNull PyElement element) {
+ final List<PsiElement> callers = new ArrayList<PsiElement>();
+ // TODO: Add callers from the dynamic call data manager
+ callers.addAll(PyStaticCallHierarchyUtil.getCallers(element));
+ return callers;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java
new file mode 100644
index 000000000000..5657dcb589e9
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000-2014 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 com.jetbrains.python.hierarchy.call;
+
+import com.google.common.collect.Lists;
+import com.intellij.find.findUsages.FindUsagesHandler;
+import com.intellij.find.findUsages.FindUsagesOptions;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.CommonProcessors;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.findUsages.PyClassFindUsagesHandler;
+import com.jetbrains.python.findUsages.PyFunctionFindUsagesHandler;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.search.PySuperMethodsSearch;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyStaticCallHierarchyUtil {
+ public static Collection<PsiElement> getCallees(@NotNull PyElement element) {
+ final List<PsiElement> callees = Lists.newArrayList();
+
+ final PyRecursiveElementVisitor visitor = new PyRecursiveElementVisitor() {
+ @Override
+ public void visitPyParameterList(PyParameterList node) {
+ }
+
+ @Override
+ public void visitPyLambdaExpression(PyLambdaExpression node) {
+ }
+
+ @Override
+ public void visitPyFunction(PyFunction innerFunction) {
+ for (PyParameter parameter : innerFunction.getParameterList().getParameters()) {
+ PsiElement defaultValue = parameter.getDefaultValue();
+ if (defaultValue != null) {
+ defaultValue.accept(this);
+ }
+ }
+ }
+
+ @Override
+ public void visitPyCallExpression(PyCallExpression callExpression) {
+ super.visitPyCallExpression(callExpression);
+ PsiElement calleeFunction = callExpression.resolveCalleeFunction(PyResolveContext.defaultContext());
+ if (calleeFunction instanceof PyFunction) {
+ callees.add(calleeFunction);
+ }
+ }
+ };
+
+ visitor.visitElement(element);
+
+ return callees;
+ }
+
+ public static Collection<PsiElement> getCallers(@NotNull PyElement pyElement) {
+ final List<PsiElement> callers = Lists.newArrayList();
+ final Collection<UsageInfo> usages = findUsages(pyElement);
+
+ for (UsageInfo usage : usages) {
+ PsiElement element = usage.getElement();
+ if (element == null) {
+ continue;
+ }
+
+ element = element.getParent();
+ while (element instanceof PyParenthesizedExpression) {
+ element = element.getParent();
+ }
+
+ if (element instanceof PyCallExpression) {
+ PsiElement caller = PsiTreeUtil.getParentOfType(element, PyParameterList.class, PyFunction.class);
+ if (caller instanceof PyFunction) {
+ callers.add(caller);
+ }
+ else if (caller instanceof PyParameterList) {
+ PsiElement innerFunction = PsiTreeUtil.getParentOfType(caller, PyFunction.class);
+ PsiElement outerFunction = PsiTreeUtil.getParentOfType(innerFunction, PyFunction.class);
+ if (innerFunction != null && outerFunction != null) {
+ callers.add(outerFunction);
+ }
+ }
+ }
+ }
+
+ return callers;
+ }
+
+ private static Collection<UsageInfo> findUsages(@NotNull final PsiElement element) {
+ final FindUsagesHandler handler = createFindUsageHandler(element);
+ if (handler == null) {
+ return Lists.newArrayList();
+ }
+ final CommonProcessors.CollectProcessor<UsageInfo> processor = new CommonProcessors.CollectProcessor<UsageInfo>();
+ final PsiElement[] psiElements = ArrayUtil.mergeArrays(handler.getPrimaryElements(), handler.getSecondaryElements());
+ final FindUsagesOptions options = handler.getFindUsagesOptions(null);
+ for (PsiElement psiElement : psiElements) {
+ handler.processElementUsages(psiElement, processor, options);
+ }
+ return processor.getResults();
+ }
+
+ /**
+ * @see {@link com.jetbrains.python.findUsages.PyFindUsagesHandlerFactory#createFindUsagesHandler(com.intellij.psi.PsiElement, boolean) createFindUsagesHandler}
+ */
+ @Nullable
+ private static FindUsagesHandler createFindUsageHandler(@NotNull final PsiElement element) {
+ if (element instanceof PyFunction) {
+ final Collection<PsiElement> superMethods = PySuperMethodsSearch.search((PyFunction)element, true).findAll();
+ if (superMethods.size() > 0) {
+ final PsiElement next = superMethods.iterator().next();
+ if (next instanceof PyFunction && !isInObject((PyFunction)next)) {
+ List<PsiElement> allMethods = Lists.newArrayList();
+ allMethods.add(element);
+ allMethods.addAll(superMethods);
+
+ return new PyFunctionFindUsagesHandler(element, allMethods);
+ }
+ }
+ return new PyFunctionFindUsagesHandler(element);
+ }
+ if (element instanceof PyClass) {
+ return new PyClassFindUsagesHandler((PyClass)element);
+ }
+ return null;
+ }
+
+ /**
+ * @see {@link com.jetbrains.python.findUsages.PyFindUsagesHandlerFactory#isInObject(com.jetbrains.python.psi.PyFunction) isInObject}
+ */
+ private static boolean isInObject(PyFunction fun) {
+ final PyClass containingClass = fun.getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ return (PyNames.FAKE_OLD_BASE.equals(containingClass.getName()) ||
+ (PyNames.OBJECT.equals(containingClass.getName()) && PyBuiltinCache.getInstance(fun).isBuiltin(containingClass)));
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
index 7b43fe7329cf..f4287b28bd6c 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
@@ -18,9 +18,10 @@ package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Query;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.search.PyClassInheritorsSearch;
import org.jetbrains.annotations.NotNull;
@@ -40,17 +41,20 @@ public class PySubTypesHierarchyTreeStructure extends HierarchyTreeStructure {
}
public PySubTypesHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), new PyTypeHierarchyNodeDescriptor(null, cl, true));
+ super(cl.getProject(), new PyHierarchyNodeDescriptor(null, cl, true));
}
@NotNull
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
- final PyClass classElement = ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement();
- Query<PyClass> subClasses = PyClassInheritorsSearch.search(classElement, false);
+ final List<PyHierarchyNodeDescriptor> res = new ArrayList<PyHierarchyNodeDescriptor>();
+ final PsiElement element = ((PyHierarchyNodeDescriptor)descriptor).getPsiElement();
+ if (element instanceof PyClass) {
+ final PyClass cls = (PyClass)element;
+ Query<PyClass> subClasses = PyClassInheritorsSearch.search(cls, false);
+ for (PyClass subClass : subClasses) {
+ res.add(new PyHierarchyNodeDescriptor(descriptor, subClass, false));
+ }
- List<PyTypeHierarchyNodeDescriptor> res = new ArrayList<PyTypeHierarchyNodeDescriptor>();
- for (PyClass cl : subClasses) {
- res.add(new PyTypeHierarchyNodeDescriptor(descriptor, cl, false));
}
return ArrayUtil.toObjectArray(res);
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
index 38b4c6ee7f76..8087767c61d8 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
@@ -17,8 +17,8 @@ package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
-import com.intellij.openapi.project.Project;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import org.jetbrains.annotations.NotNull;
@@ -32,20 +32,23 @@ import java.util.List;
* Time: 7:04:07 PM
*/
public class PySuperTypesHierarchyTreeStructure extends HierarchyTreeStructure {
- protected PySuperTypesHierarchyTreeStructure(final Project project, final HierarchyNodeDescriptor baseDescriptor) {
- super(project, baseDescriptor);
- }
-
public PySuperTypesHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), new PyTypeHierarchyNodeDescriptor(null, cl, true));
+ super(cl.getProject(), new PyHierarchyNodeDescriptor(null, cl, true));
}
@NotNull
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
- final PyClass[] superClasses = ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement().getSuperClasses();
- List<PyTypeHierarchyNodeDescriptor> res = new ArrayList<PyTypeHierarchyNodeDescriptor>();
- for (PyClass superClass : superClasses) {
- res.add(new PyTypeHierarchyNodeDescriptor(descriptor, superClass, false));
+ final List<PyHierarchyNodeDescriptor> res = new ArrayList<PyHierarchyNodeDescriptor>();
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ final PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ final PsiElement element = pyDescriptor.getPsiElement();
+ if (element instanceof PyClass) {
+ final PyClass cls = (PyClass)element;
+ final PyClass[] superClasses = cls.getSuperClasses();
+ for (PyClass superClass : superClasses) {
+ res.add(new PyHierarchyNodeDescriptor(descriptor, superClass, false));
+ }
+ }
}
return res.toArray();
}
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
index 6707ac9b7e14..0eb505f4857b 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
@@ -16,8 +16,7 @@
package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
-import com.intellij.openapi.project.Project;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyUtil;
import org.jetbrains.annotations.NotNull;
@@ -28,30 +27,26 @@ import java.util.List;
* @author Alexey.Ivanov
*/
public class PyTypeHierarchyTreeStructure extends PySubTypesHierarchyTreeStructure {
- private static PyTypeHierarchyNodeDescriptor buildHierarchyElement(@NotNull final PyClass cl) {
- PyTypeHierarchyNodeDescriptor descriptor = null;
+ public PyTypeHierarchyTreeStructure(@NotNull final PyClass cl) {
+ super(cl.getProject(), buildHierarchyElement(cl));
+ setBaseElement(myBaseDescriptor);
+ }
+
+ private static PyHierarchyNodeDescriptor buildHierarchyElement(@NotNull final PyClass cl) {
+ PyHierarchyNodeDescriptor descriptor = null;
List<PyClass> superClasses = PyUtil.getAllSuperClasses(cl);
for (int i = superClasses.size() - 1; i >= 0; --i) {
final PyClass superClass = superClasses.get(i);
- final PyTypeHierarchyNodeDescriptor newDescriptor = new PyTypeHierarchyNodeDescriptor(descriptor, superClass, false);
+ final PyHierarchyNodeDescriptor newDescriptor = new PyHierarchyNodeDescriptor(descriptor, superClass, false);
if (descriptor != null) {
- descriptor.setCachedChildren(new PyTypeHierarchyNodeDescriptor[]{newDescriptor});
+ descriptor.setCachedChildren(new PyHierarchyNodeDescriptor[]{newDescriptor});
}
descriptor = newDescriptor;
}
- final PyTypeHierarchyNodeDescriptor newDescriptor = new PyTypeHierarchyNodeDescriptor(descriptor, cl, true);
+ final PyHierarchyNodeDescriptor newDescriptor = new PyHierarchyNodeDescriptor(descriptor, cl, true);
if (descriptor != null) {
descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor});
}
return newDescriptor;
}
-
- protected PyTypeHierarchyTreeStructure(final Project project, final HierarchyNodeDescriptor baseDescriptor) {
- super(project, baseDescriptor);
- }
-
- public PyTypeHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), buildHierarchyElement(cl));
- setBaseElement(myBaseDescriptor);
- }
}