2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.codeInsight
;
18 import com
.intellij
.openapi
.editor
.Editor
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.psi
.util
.PsiTreeUtil
;
21 import com
.intellij
.psi
.util
.PsiUtil
;
22 import com
.intellij
.psi
.xml
.XmlAttribute
;
23 import com
.intellij
.psi
.xml
.XmlAttributeValue
;
24 import com
.intellij
.psi
.xml
.XmlTag
;
25 import com
.intellij
.psi
.xml
.XmlText
;
26 import org
.jetbrains
.annotations
.NotNull
;
27 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.util
.ArrayList
;
30 import java
.util
.Arrays
;
31 import java
.util
.Collection
;
32 import java
.util
.List
;
34 public class TargetElementUtil
extends TargetElementUtilBase
{
35 public static final int NEW_AS_CONSTRUCTOR
= 0x04;
36 public static final int THIS_ACCEPTED
= 0x10;
37 public static final int SUPER_ACCEPTED
= 0x20;
40 public int getAllAccepted() {
41 return super.getAllAccepted() | NEW_AS_CONSTRUCTOR
| THIS_ACCEPTED
| SUPER_ACCEPTED
;
44 public int getDefinitionSearchFlags() {
45 return super.getDefinitionSearchFlags() | THIS_ACCEPTED
| SUPER_ACCEPTED
;
48 public int getReferenceSearchFlags() {
49 return super.getReferenceSearchFlags() | NEW_AS_CONSTRUCTOR
;
54 public PsiElement
findTargetElement(final Editor editor
, final int flags
, final int offset
) {
55 final PsiElement element
= super.findTargetElement(editor
, flags
, offset
);
56 if (element
instanceof PsiKeyword
) {
57 if (element
.getParent() instanceof PsiThisExpression
) {
58 if ((flags
& THIS_ACCEPTED
) == 0) return null;
59 PsiType type
= ((PsiThisExpression
)element
.getParent()).getType();
60 if (!(type
instanceof PsiClassType
)) return null;
61 return ((PsiClassType
)type
).resolve();
64 if (element
.getParent() instanceof PsiSuperExpression
) {
65 if ((flags
& SUPER_ACCEPTED
) == 0) return null;
66 PsiType type
= ((PsiSuperExpression
)element
.getParent()).getType();
67 if (!(type
instanceof PsiClassType
)) return null;
68 return ((PsiClassType
)type
).resolve();
74 protected boolean isAcceptableReferencedElement(final PsiElement element
, final PsiElement referenceOrReferencedElement
) {
75 return super.isAcceptableReferencedElement(element
, referenceOrReferencedElement
) &&
76 !isEnumConstantReference(element
, referenceOrReferencedElement
);
79 private static boolean isEnumConstantReference(final PsiElement element
, final PsiElement referenceOrReferencedElement
) {
80 return element
!= null &&
81 element
.getParent() instanceof PsiEnumConstant
&&
82 referenceOrReferencedElement
instanceof PsiMethod
&&
83 ((PsiMethod
)referenceOrReferencedElement
).isConstructor();
87 protected PsiElement
getReferenceOrReferencedElement(PsiFile file
, Editor editor
, int flags
, int offset
) {
88 PsiElement refElement
= super.getReferenceOrReferencedElement(file
, editor
, flags
, offset
);
89 PsiReference ref
= null;
90 if (refElement
== null) {
91 ref
= TargetElementUtilBase
.findReference(editor
, offset
);
92 if (ref
instanceof PsiJavaReference
) {
93 refElement
= ((PsiJavaReference
)ref
).advancedResolve(true).getElement();
97 if (refElement
!= null) {
98 if ((flags
& NEW_AS_CONSTRUCTOR
) != 0) {
100 ref
= TargetElementUtilBase
.findReference(editor
, offset
);
103 PsiElement parent
= ref
.getElement().getParent();
104 if (parent
instanceof PsiAnonymousClass
) {
105 parent
= parent
.getParent();
107 if (parent
instanceof PsiNewExpression
) {
108 PsiMethod constructor
= ((PsiNewExpression
)parent
).resolveConstructor();
109 if (constructor
!= null) {
110 refElement
= constructor
;
115 if (refElement
instanceof PsiClass
) {
116 final PsiFile containingFile
= refElement
.getContainingFile();
117 if (containingFile
!= null && containingFile
.getVirtualFile() == null) { // in mirror file of compiled class
118 String qualifiedName
= ((PsiClass
)refElement
).getQualifiedName();
119 if (qualifiedName
== null) return null;
120 return JavaPsiFacade
.getInstance(refElement
.getProject()).findClass(qualifiedName
, refElement
.getResolveScope());
128 protected PsiElement
getNamedElement(final PsiElement element
) {
129 PsiElement parent
= element
.getParent();
130 if (element
instanceof PsiIdentifier
) {
131 if (parent
instanceof PsiClass
&& element
.equals(((PsiClass
)parent
).getNameIdentifier())) {
134 else if (parent
instanceof PsiVariable
&& element
.equals(((PsiVariable
)parent
).getNameIdentifier())) {
137 else if (parent
instanceof PsiMethod
&& element
.equals(((PsiMethod
)parent
).getNameIdentifier())) {
140 else if (parent
instanceof PsiLabeledStatement
&& element
.equals(((PsiLabeledStatement
)parent
).getLabelIdentifier())) {
144 else if ((parent
= PsiTreeUtil
.getParentOfType(element
, PsiNamedElement
.class, false)) != null) {
145 // A bit hacky depends on navigation offset correctly overridden
146 if (parent
.getTextOffset() == element
.getTextRange().getStartOffset() && !(parent
instanceof XmlAttribute
)) {
154 public static PsiReferenceExpression
findReferenceExpression(Editor editor
) {
155 final PsiReference ref
= findReference(editor
);
156 return ref
instanceof PsiReferenceExpression ?
(PsiReferenceExpression
)ref
: null;
160 public PsiElement
adjustReference(@NotNull final PsiReference ref
) {
161 final PsiElement parent
= ref
.getElement().getParent();
162 if (parent
instanceof PsiMethodCallExpression
) return parent
;
163 return super.adjustReference(ref
);
168 public PsiElement
adjustElement(final Editor editor
, final int flags
, final PsiElement element
, final PsiElement contextElement
) {
169 if (element
!= null) {
170 if (element
instanceof PsiAnonymousClass
) {
171 return ((PsiAnonymousClass
)element
).getBaseClassType().resolve();
175 if (contextElement
== null) return null;
176 final PsiElement parent
= contextElement
.getParent();
177 if (parent
instanceof XmlText
|| parent
instanceof XmlAttributeValue
) {
178 return TargetElementUtilBase
.getInstance().findTargetElement(editor
, flags
, parent
.getParent().getTextRange().getStartOffset() + 1);
180 else if (parent
instanceof XmlTag
|| parent
instanceof XmlAttribute
) {
181 return TargetElementUtilBase
.getInstance().findTargetElement(editor
, flags
, parent
.getTextRange().getStartOffset() + 1);
186 public Collection
<PsiElement
> getTargetCandidates(final PsiReference reference
) {
187 PsiElement parent
= reference
.getElement().getParent();
188 if (parent
instanceof PsiMethodCallExpression
) {
189 PsiMethodCallExpression callExpr
= (PsiMethodCallExpression
)parent
;
190 boolean allowStatics
= false;
191 PsiExpression qualifier
= callExpr
.getMethodExpression().getQualifierExpression();
192 if (qualifier
== null) {
195 else if (qualifier
instanceof PsiJavaCodeReferenceElement
) {
196 PsiElement referee
= ((PsiJavaCodeReferenceElement
)qualifier
).advancedResolve(true).getElement();
197 if (referee
instanceof PsiClass
) allowStatics
= true;
199 PsiResolveHelper helper
= JavaPsiFacade
.getInstance(parent
.getProject()).getResolveHelper();
200 PsiElement
[] candidates
= PsiUtil
.mapElements(helper
.getReferencedMethodCandidates(callExpr
, false));
201 ArrayList
<PsiElement
> methods
= new ArrayList
<PsiElement
>();
202 for (PsiElement candidate1
: candidates
) {
203 PsiMethod candidate
= (PsiMethod
)candidate1
;
204 if (candidate
.hasModifierProperty(PsiModifier
.STATIC
) && !allowStatics
) continue;
205 List
<PsiMethod
> supers
= Arrays
.asList(candidate
.findSuperMethods());
206 if (supers
.isEmpty()) {
207 methods
.add(candidate
);
210 methods
.addAll(supers
);
216 return super.getTargetCandidates(reference
);
219 public PsiElement
getGotoDeclarationTarget(final PsiElement element
, final PsiElement navElement
) {
220 if (navElement
== element
&& element
instanceof PsiCompiledElement
&& element
instanceof PsiMethod
) {
221 PsiMethod method
= (PsiMethod
)element
;
222 if (method
.isConstructor() && method
.getParameterList().getParametersCount() == 0) {
223 PsiClass aClass
= method
.getContainingClass();
224 PsiElement navClass
= aClass
.getNavigationElement();
225 if (aClass
!= navClass
) return navClass
;
228 return super.getGotoDeclarationTarget(element
, navElement
);
232 public boolean includeSelfInGotoImplementation(final PsiElement element
) {
233 if (element
instanceof PsiModifierListOwner
&& ((PsiModifierListOwner
)element
).hasModifierProperty(PsiModifier
.ABSTRACT
)) {
236 return super.includeSelfInGotoImplementation(element
);