mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-101405 Call hierarchy support for Groovy
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-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.
|
||||
@@ -34,12 +34,8 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.presentation.java.ClassPresentationUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.ui.LayeredIcon;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -68,7 +64,7 @@ public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
|
||||
return myElement == null ? null : getEnclosingElement(myElement);
|
||||
}
|
||||
|
||||
static PsiMember getEnclosingElement(final PsiElement element){
|
||||
public static PsiMember getEnclosingElement(final PsiElement element){
|
||||
return PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class);
|
||||
}
|
||||
|
||||
@@ -138,8 +134,8 @@ public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
|
||||
}
|
||||
final String methodText = PsiFormatUtil.formatMethod(
|
||||
method,
|
||||
PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS,
|
||||
PsiFormatUtil.SHOW_TYPE
|
||||
PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS,
|
||||
PsiFormatUtilBase.SHOW_TYPE
|
||||
);
|
||||
buffer.append(methodText);
|
||||
|
||||
|
||||
@@ -17,12 +17,11 @@ package com.intellij.ide.hierarchy.call;
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -63,69 +62,15 @@ public final class CallerMethodsTreeStructure extends HierarchyTreeStructure {
|
||||
methodsToFind.add(method);
|
||||
ContainerUtil.addAll(methodsToFind, method.findDeepestSuperMethods());
|
||||
|
||||
final Map<PsiMember, CallHierarchyNodeDescriptor> methodToDescriptorMap = new HashMap<PsiMember, CallHierarchyNodeDescriptor>();
|
||||
final Map<PsiMember, NodeDescriptor> methodToDescriptorMap = new HashMap<PsiMember, NodeDescriptor>();
|
||||
for (final PsiMethod methodToFind : methodsToFind) {
|
||||
final JavaCallHierarchyData data = new JavaCallHierarchyData(originalClass, methodToFind, originalType, method, methodsToFind, descriptor, methodToDescriptorMap, myProject);
|
||||
|
||||
MethodReferencesSearch.search(methodToFind, searchScope, true).forEach(new Processor<PsiReference>() {
|
||||
@Override
|
||||
public boolean process(final PsiReference reference) {
|
||||
if (reference instanceof PsiReferenceExpression) {
|
||||
final PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression();
|
||||
if (qualifier instanceof PsiSuperExpression) { // filter super.foo() call inside foo() and similar cases (bug 8411)
|
||||
final PsiClass superClass = PsiUtil.resolveClassInType(qualifier.getType());
|
||||
if (originalClass.isInheritor(superClass, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (qualifier != null && !methodToFind.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final PsiType qualifierType = qualifier.getType();
|
||||
if (qualifierType instanceof PsiClassType &&
|
||||
!TypeConversionUtil.isAssignable(qualifierType, originalType) &&
|
||||
methodToFind != method) {
|
||||
final PsiClass psiClass = ((PsiClassType)qualifierType).resolve();
|
||||
if (psiClass != null) {
|
||||
final PsiMethod callee = psiClass.findMethodBySignature(methodToFind, true);
|
||||
if (callee != null && !methodsToFind.contains(callee)) {
|
||||
// skip sibling methods
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(reference instanceof PsiElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final PsiElement parent = ((PsiElement)reference).getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
if (((PsiNewExpression)parent).getClassReference() != reference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiAnonymousClass) {
|
||||
if (((PsiAnonymousClass)parent).getBaseClassReference() != reference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiElement element = reference.getElement();
|
||||
final PsiMember key = CallHierarchyNodeDescriptor.getEnclosingElement(element);
|
||||
|
||||
synchronized (methodToDescriptorMap) {
|
||||
CallHierarchyNodeDescriptor d = methodToDescriptorMap.get(key);
|
||||
if (d == null) {
|
||||
d = new CallHierarchyNodeDescriptor(myProject, descriptor, element, false, true);
|
||||
methodToDescriptorMap.put(key, d);
|
||||
}
|
||||
else if (!d.hasReference(reference)) {
|
||||
d.incrementUsageCount();
|
||||
}
|
||||
d.addReference(reference);
|
||||
for (CallReferenceProcessor processor : CallReferenceProcessor.EP_NAME.getExtensions()) {
|
||||
if (!processor.process(reference, data)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.ide.hierarchy.call;
|
||||
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 10/5/13
|
||||
*/
|
||||
public class JavaCallReferenceProcessor implements CallReferenceProcessor {
|
||||
@Override
|
||||
public boolean process(@NotNull PsiReference reference, @NotNull JavaCallHierarchyData data) {
|
||||
PsiClass originalClass = data.getOriginalClass();
|
||||
PsiMethod method = data.getMethod();
|
||||
Set<PsiMethod> methodsToFind = data.getMethodsToFind();
|
||||
PsiMethod methodToFind = data.getMethodToFind();
|
||||
PsiClassType originalType = data.getOriginalType();
|
||||
Map<PsiMember, NodeDescriptor> methodToDescriptorMap = data.getResultMap();
|
||||
Project myProject = data.getProject();
|
||||
|
||||
if (reference instanceof PsiReferenceExpression) {
|
||||
final PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression();
|
||||
if (qualifier instanceof PsiSuperExpression) { // filter super.foo() call inside foo() and similar cases (bug 8411)
|
||||
final PsiClass superClass = PsiUtil.resolveClassInType(qualifier.getType());
|
||||
if (superClass == null || originalClass.isInheritor(superClass, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (qualifier != null && !methodToFind.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final PsiType qualifierType = qualifier.getType();
|
||||
if (qualifierType instanceof PsiClassType &&
|
||||
!TypeConversionUtil.isAssignable(qualifierType, originalType) &&
|
||||
methodToFind != method) {
|
||||
final PsiClass psiClass = ((PsiClassType)qualifierType).resolve();
|
||||
if (psiClass != null) {
|
||||
final PsiMethod callee = psiClass.findMethodBySignature(methodToFind, true);
|
||||
if (callee != null && !methodsToFind.contains(callee)) {
|
||||
// skip sibling methods
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(reference instanceof PsiElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final PsiElement parent = ((PsiElement)reference).getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
if (((PsiNewExpression)parent).getClassReference() != reference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiAnonymousClass) {
|
||||
if (((PsiAnonymousClass)parent).getBaseClassReference() != reference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiElement element = reference.getElement();
|
||||
final PsiMember key = CallHierarchyNodeDescriptor.getEnclosingElement(element);
|
||||
|
||||
synchronized (methodToDescriptorMap) {
|
||||
CallHierarchyNodeDescriptor d = (CallHierarchyNodeDescriptor)methodToDescriptorMap.get(key);
|
||||
if (d == null) {
|
||||
d = new CallHierarchyNodeDescriptor(myProject, (CallHierarchyNodeDescriptor)data.getNodeDescriptor(), element, false, true);
|
||||
methodToDescriptorMap.put(key, d);
|
||||
}
|
||||
else if (!d.hasReference(reference)) {
|
||||
d.incrementUsageCount();
|
||||
}
|
||||
d.addReference(reference);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.ide.hierarchy.call;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 10/5/13
|
||||
*/
|
||||
public interface CallReferenceProcessor {
|
||||
ExtensionPointName<CallReferenceProcessor> EP_NAME = ExtensionPointName.create("com.intellij.hierarchy.referenceProcessor");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param reference reference to process
|
||||
* @param data settings to use while processing
|
||||
* @return false if the reference is processed
|
||||
*/
|
||||
boolean process(@NotNull PsiReference reference, @NotNull JavaCallHierarchyData data);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.ide.hierarchy.call;
|
||||
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 10/5/13
|
||||
*/
|
||||
public class JavaCallHierarchyData {
|
||||
private final PsiClass myOriginalClass;
|
||||
private final PsiMethod myMethodToFind;
|
||||
private final PsiClassType myOriginalType;
|
||||
private final PsiMethod myMethod;
|
||||
private final Set<PsiMethod> myMethodsToFind;
|
||||
private final NodeDescriptor myNodeDescriptor;
|
||||
private final Map<PsiMember, NodeDescriptor> myResultMap;
|
||||
private final Project myProject;
|
||||
|
||||
public JavaCallHierarchyData(PsiClass originalClass,
|
||||
PsiMethod methodToFind,
|
||||
PsiClassType originalType,
|
||||
PsiMethod method,
|
||||
Set<PsiMethod> methodsToFind,
|
||||
NodeDescriptor nodeDescriptor,
|
||||
Map<PsiMember, NodeDescriptor> resultMap,
|
||||
Project project) {
|
||||
|
||||
myOriginalClass = originalClass;
|
||||
myMethodToFind = methodToFind;
|
||||
myOriginalType = originalType;
|
||||
myMethod = method;
|
||||
myMethodsToFind = methodsToFind;
|
||||
myNodeDescriptor = nodeDescriptor;
|
||||
myResultMap = resultMap;
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public PsiClass getOriginalClass() {
|
||||
return myOriginalClass;
|
||||
}
|
||||
|
||||
public PsiMethod getMethodToFind() {
|
||||
return myMethodToFind;
|
||||
}
|
||||
|
||||
public PsiClassType getOriginalType() {
|
||||
return myOriginalType;
|
||||
}
|
||||
|
||||
public PsiMethod getMethod() {
|
||||
return myMethod;
|
||||
}
|
||||
|
||||
public Set<PsiMethod> getMethodsToFind() {
|
||||
return myMethodsToFind;
|
||||
}
|
||||
|
||||
public NodeDescriptor getNodeDescriptor() {
|
||||
return myNodeDescriptor;
|
||||
}
|
||||
|
||||
public Map<PsiMember, NodeDescriptor> getResultMap() {
|
||||
return myResultMap;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user