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
.psi
.impl
.source
;
18 import com
.intellij
.lang
.ASTNode
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.util
.TextRange
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.codeStyle
.CodeStyleSettingsManager
;
23 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
24 import com
.intellij
.psi
.filters
.*;
25 import com
.intellij
.psi
.filters
.classes
.AnnotationTypeFilter
;
26 import com
.intellij
.psi
.filters
.element
.ModifierFilter
;
27 import com
.intellij
.psi
.impl
.CheckUtil
;
28 import com
.intellij
.psi
.impl
.PsiImplUtil
;
29 import com
.intellij
.psi
.impl
.PsiManagerEx
;
30 import com
.intellij
.psi
.impl
.source
.parsing
.Parsing
;
31 import com
.intellij
.psi
.impl
.source
.resolve
.ClassResolverProcessor
;
32 import com
.intellij
.psi
.impl
.source
.resolve
.ResolveCache
;
33 import com
.intellij
.psi
.impl
.source
.resolve
.VariableResolverProcessor
;
34 import com
.intellij
.psi
.impl
.source
.tree
.*;
35 import com
.intellij
.psi
.infos
.CandidateInfo
;
36 import com
.intellij
.psi
.scope
.ElementClassFilter
;
37 import com
.intellij
.psi
.scope
.PsiScopeProcessor
;
38 import com
.intellij
.psi
.scope
.processor
.FilterScopeProcessor
;
39 import com
.intellij
.psi
.scope
.util
.PsiScopesUtil
;
40 import com
.intellij
.psi
.tree
.ChildRoleBase
;
41 import com
.intellij
.psi
.tree
.IElementType
;
42 import com
.intellij
.psi
.util
.PsiUtil
;
43 import com
.intellij
.util
.IncorrectOperationException
;
44 import org
.jetbrains
.annotations
.NotNull
;
45 import org
.jetbrains
.annotations
.Nullable
;
47 public class PsiJavaCodeReferenceElementImpl
extends CompositePsiElement
implements PsiJavaCodeReferenceElement
, SourceJavaCodeReference
{
48 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl");
50 private volatile String myCachedQName
= null;
51 private volatile String myCachedTextSkipWhiteSpaceAndComments
;
52 private int myKindWhenDummy
= CLASS_NAME_KIND
;
54 public static final int CLASS_NAME_KIND
= 1;
55 public static final int PACKAGE_NAME_KIND
= 2;
56 public static final int CLASS_OR_PACKAGE_NAME_KIND
= 3;
57 public static final int CLASS_FQ_NAME_KIND
= 4;
58 public static final int CLASS_FQ_OR_PACKAGE_NAME_KIND
= 5;
59 public static final int CLASS_IN_QUALIFIED_NEW_KIND
= 6;
61 public PsiJavaCodeReferenceElementImpl() {
62 super(JavaElementType
.JAVA_CODE_REFERENCE
);
65 public int getTextOffset() {
66 final ASTNode refName
= getReferenceNameNode();
67 return refName
!= null ? refName
.getStartOffset() : super.getTextOffset();
70 public void setKindWhenDummy(final int kind
) {
71 LOG
.assertTrue(getTreeParent().getElementType() == TokenType
.DUMMY_HOLDER
);
72 myKindWhenDummy
= kind
;
75 public int getKind() {
76 IElementType i
= getTreeParent().getElementType();
77 if (i
== TokenType
.DUMMY_HOLDER
) {
78 return myKindWhenDummy
;
80 else if (i
== JavaElementType
.TYPE
) {
81 return getTreeParent().getTreeParent().getPsi() instanceof PsiTypeCodeFragment ? CLASS_OR_PACKAGE_NAME_KIND
: CLASS_NAME_KIND
;
83 else if (i
== JavaElementType
.EXTENDS_LIST
|| i
== JavaElementType
.IMPLEMENTS_LIST
|| i
== JavaElementType
.EXTENDS_BOUND_LIST
|| i
==
84 JavaElementType
.THROWS_LIST
||
85 i
== JavaElementType
.THIS_EXPRESSION
||
86 i
== JavaElementType
.SUPER_EXPRESSION
||
87 i
== JavaDocElementType
.DOC_METHOD_OR_FIELD_REF
||
88 i
== JavaDocTokenType
.DOC_TAG_VALUE_TOKEN
||
89 i
== JavaElementType
.REFERENCE_PARAMETER_LIST
||
90 i
== JavaElementType
.ANNOTATION
) {
92 return CLASS_OR_PACKAGE_NAME_KIND
;
95 return CLASS_NAME_KIND
;
97 else if (i
== JavaElementType
.NEW_EXPRESSION
) {
98 final ASTNode qualifier
= getTreeParent().findChildByRole(ChildRole
.QUALIFIER
);
99 return qualifier
!= null ? CLASS_IN_QUALIFIED_NEW_KIND
: CLASS_NAME_KIND
;
101 else if (i
== JavaElementType
.ANONYMOUS_CLASS
) {
102 if (getTreeParent().getChildRole(this) == ChildRole
.BASE_CLASS_REFERENCE
) {
103 LOG
.assertTrue(getTreeParent().getTreeParent().getElementType() == JavaElementType
.NEW_EXPRESSION
);
104 final ASTNode qualifier
= getTreeParent().getTreeParent().findChildByRole(ChildRole
.QUALIFIER
);
105 return qualifier
!= null ? CLASS_IN_QUALIFIED_NEW_KIND
: CLASS_NAME_KIND
;
108 return CLASS_OR_PACKAGE_NAME_KIND
; // uncomplete code
111 else if (i
== JavaElementType
.PACKAGE_STATEMENT
) {
112 return PACKAGE_NAME_KIND
;
114 else if (i
== JavaElementType
.IMPORT_STATEMENT
) {
115 final boolean isOnDemand
= ((PsiImportStatement
)SourceTreeToPsiMap
.treeElementToPsi(getTreeParent())).isOnDemand();
116 return isOnDemand ? CLASS_FQ_OR_PACKAGE_NAME_KIND
: CLASS_FQ_NAME_KIND
;
118 else if (i
== JavaElementType
.IMPORT_STATIC_STATEMENT
) {
119 return CLASS_FQ_OR_PACKAGE_NAME_KIND
;
121 else if (i
== JavaElementType
.JAVA_CODE_REFERENCE
) {
122 final int parentKind
= ((PsiJavaCodeReferenceElementImpl
)getTreeParent()).getKind();
123 switch (parentKind
) {
124 case CLASS_NAME_KIND
:
125 return CLASS_OR_PACKAGE_NAME_KIND
;
127 case PACKAGE_NAME_KIND
:
128 return PACKAGE_NAME_KIND
;
130 case CLASS_OR_PACKAGE_NAME_KIND
:
131 return CLASS_OR_PACKAGE_NAME_KIND
;
133 case CLASS_FQ_NAME_KIND
:
134 return CLASS_FQ_OR_PACKAGE_NAME_KIND
;
136 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
137 return CLASS_FQ_OR_PACKAGE_NAME_KIND
;
139 case CLASS_IN_QUALIFIED_NEW_KIND
:
140 return CLASS_IN_QUALIFIED_NEW_KIND
; //??
143 LOG
.assertTrue(false);
147 else if (i
== JavaElementType
.CLASS
|| i
== JavaElementType
.PARAMETER_LIST
|| i
== TokenType
.ERROR_ELEMENT
) {
148 return CLASS_OR_PACKAGE_NAME_KIND
;
150 else if (i
== JavaElementType
.IMPORT_STATIC_REFERENCE
) {
151 return CLASS_FQ_OR_PACKAGE_NAME_KIND
;
153 else if (i
== JavaDocElementType
.DOC_TAG
|| i
== JavaDocElementType
.DOC_INLINE_TAG
|| i
== JavaDocElementType
.DOC_REFERENCE_HOLDER
|| i
==
154 JavaDocElementType
.DOC_TYPE_HOLDER
) {
155 return CLASS_OR_PACKAGE_NAME_KIND
;
157 else if (isCodeFragmentType(i
)) {
158 PsiJavaCodeReferenceCodeFragment fragment
= (PsiJavaCodeReferenceCodeFragment
)getTreeParent().getPsi();
159 return fragment
.isClassesAccepted() ? CLASS_FQ_OR_PACKAGE_NAME_KIND
: PACKAGE_NAME_KIND
;
162 LOG
.error("Unknown parent for java code reference:" + getTreeParent());
163 return CLASS_NAME_KIND
;
167 private static boolean isCodeFragmentType(IElementType type
) {
168 return type
== TokenType
.CODE_FRAGMENT
|| type
instanceof ICodeFragmentElementType
;
171 public void deleteChildInternal(@NotNull final ASTNode child
) {
172 if (getChildRole(child
) == ChildRole
.QUALIFIER
) {
173 final ASTNode dot
= findChildByRole(ChildRole
.DOT
);
174 super.deleteChildInternal(child
);
175 deleteChildInternal(dot
);
178 super.deleteChildInternal(child
);
182 public final ASTNode
findChildByRole(final int role
) {
183 LOG
.assertTrue(ChildRole
.isUnique(role
));
188 case ChildRole
.REFERENCE_NAME
:
189 if (getLastChildNode().getElementType() == JavaTokenType
.IDENTIFIER
) {
190 return getLastChildNode();
193 if (getLastChildNode().getElementType() == JavaElementType
.REFERENCE_PARAMETER_LIST
) {
194 ASTNode current
= getLastChildNode().getTreePrev();
195 while (current
!= null && StdTokenSets
.WHITE_SPACE_OR_COMMENT_BIT_SET
.contains(current
.getElementType())) {
196 current
= current
.getTreePrev();
198 if (current
!= null && current
.getElementType() == JavaTokenType
.IDENTIFIER
) {
205 case ChildRole
.REFERENCE_PARAMETER_LIST
:
206 if (getLastChildNode().getElementType() == JavaElementType
.REFERENCE_PARAMETER_LIST
) {
207 return getLastChildNode();
213 case ChildRole
.QUALIFIER
:
214 if (getFirstChildNode().getElementType() == JavaElementType
.JAVA_CODE_REFERENCE
) {
215 return getFirstChildNode();
222 return findChildByType(JavaTokenType
.DOT
);
226 public final int getChildRole(final ASTNode child
) {
227 LOG
.assertTrue(child
.getTreeParent() == this);
228 final IElementType i
= child
.getElementType();
229 if (i
== JavaElementType
.REFERENCE_PARAMETER_LIST
) {
230 return ChildRole
.REFERENCE_PARAMETER_LIST
;
232 else if (i
== JavaElementType
.JAVA_CODE_REFERENCE
) {
233 return ChildRole
.QUALIFIER
;
235 else if (i
== JavaTokenType
.DOT
) {
236 return ChildRole
.DOT
;
238 else if (i
== JavaTokenType
.IDENTIFIER
) {
239 return ChildRole
.REFERENCE_NAME
;
242 return ChildRoleBase
.NONE
;
246 public String
getCanonicalText() {
248 case CLASS_NAME_KIND
:
249 case CLASS_OR_PACKAGE_NAME_KIND
:
250 case CLASS_IN_QUALIFIED_NEW_KIND
:
251 final PsiElement target
= resolve();
252 if (target
instanceof PsiClass
) {
253 final PsiClass aClass
= (PsiClass
)target
;
254 String name
= aClass
.getQualifiedName();
256 name
= aClass
.getName(); //?
258 final PsiType
[] types
= getTypeParameters();
259 if (types
.length
== 0) return name
;
261 final StringBuilder buf
= new StringBuilder();
264 for (int i
= 0; i
< types
.length
; i
++) {
265 if (i
> 0) buf
.append(',');
266 buf
.append(types
[i
].getCanonicalText());
270 return buf
.toString();
272 else if (target
instanceof PsiPackage
) {
273 return ((PsiPackage
)target
).getQualifiedName();
276 LOG
.assertTrue(target
== null);
277 return getTextSkipWhiteSpaceAndComments();
279 case PACKAGE_NAME_KIND
:
280 case CLASS_FQ_NAME_KIND
:
281 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
282 return getTextSkipWhiteSpaceAndComments();
285 LOG
.assertTrue(false);
290 public PsiReference
getReference() {
294 public final PsiElement
resolve() {
295 return advancedResolve(false).getElement();
298 private static final class OurGenericsResolver
implements ResolveCache
.PolyVariantResolver
<PsiJavaReference
> {
299 private static final OurGenericsResolver INSTANCE
= new OurGenericsResolver();
301 public static JavaResolveResult
[] _resolve(final PsiJavaReference ref
, final boolean incompleteCode
) {
302 final PsiJavaCodeReferenceElementImpl referenceElement
= (PsiJavaCodeReferenceElementImpl
)ref
;
303 final int kind
= referenceElement
.getKind();
304 JavaResolveResult
[] result
= referenceElement
.resolve(kind
);
305 if (incompleteCode
&& result
.length
== 0 && kind
!= CLASS_FQ_NAME_KIND
&& kind
!= CLASS_FQ_OR_PACKAGE_NAME_KIND
) {
306 final VariableResolverProcessor processor
= new VariableResolverProcessor(referenceElement
);
307 PsiScopesUtil
.resolveAndWalk(processor
, referenceElement
, null, incompleteCode
);
308 result
= processor
.getResult();
309 if (result
.length
> 0) {
312 if (kind
== CLASS_NAME_KIND
) {
313 return referenceElement
.resolve(PACKAGE_NAME_KIND
);
319 public JavaResolveResult
[] resolve(final PsiJavaReference ref
, final boolean incompleteCode
) {
320 final JavaResolveResult
[] result
= _resolve(ref
, incompleteCode
);
321 if (result
.length
> 0 && result
[0].getElement() instanceof PsiClass
) {
322 final PsiType
[] parameters
= ((PsiJavaCodeReferenceElement
)ref
).getTypeParameters();
323 final JavaResolveResult
[] newResult
= new JavaResolveResult
[result
.length
];
324 for (int i
= 0; i
< result
.length
; i
++) {
325 final CandidateInfo resolveResult
= (CandidateInfo
)result
[i
];
326 final PsiClass aClass
= (PsiClass
)resolveResult
.getElement();
327 assert aClass
!= null;
328 newResult
[i
] = !aClass
.hasTypeParameters() ? resolveResult
: new CandidateInfo(resolveResult
, resolveResult
.getSubstitutor().putAll(aClass
, parameters
));
337 public JavaResolveResult
advancedResolve(final boolean incompleteCode
) {
338 final JavaResolveResult
[] results
= multiResolve(incompleteCode
);
339 if (results
.length
== 1) return results
[0];
340 return JavaResolveResult
.EMPTY
;
344 public JavaResolveResult
[] multiResolve(final boolean incompleteCode
) {
345 final PsiManagerEx manager
= getManager();
346 if (manager
== null) {
347 LOG
.assertTrue(false, "getManager() == null!");
348 return JavaResolveResult
.EMPTY_ARRAY
;
351 final ResolveCache resolveCache
= manager
.getResolveCache();
352 final ResolveResult
[] results
= resolveCache
.resolveWithCaching(this, OurGenericsResolver
.INSTANCE
, true, incompleteCode
);
353 return results
.length
== 0 ? JavaResolveResult
.EMPTY_ARRAY
: (JavaResolveResult
[])results
;
356 private PsiSubstitutor
updateSubstitutor(PsiSubstitutor subst
, final PsiClass psiClass
) {
357 final PsiType
[] parameters
= getTypeParameters();
358 if (psiClass
!= null) {
359 subst
= subst
.putAll(psiClass
, parameters
);
364 private JavaResolveResult
[] resolve(final int kind
) {
366 case CLASS_FQ_NAME_KIND
:
367 // TODO: support type parameters in FQ names
368 final String textSkipWhiteSpaceAndComments
= getTextSkipWhiteSpaceAndComments();
369 if (textSkipWhiteSpaceAndComments
== null || textSkipWhiteSpaceAndComments
.length() == 0) return JavaResolveResult
.EMPTY_ARRAY
;
370 final PsiClass aClass
=
371 JavaPsiFacade
.getInstance(getProject()).findClass(textSkipWhiteSpaceAndComments
, getResolveScope());
372 if (aClass
== null) return JavaResolveResult
.EMPTY_ARRAY
;
373 return new JavaResolveResult
[]{new CandidateInfo(aClass
, updateSubstitutor(PsiSubstitutor
.EMPTY
, aClass
), this, false)};
375 case CLASS_IN_QUALIFIED_NEW_KIND
: {
376 PsiElement parent
= getParent();
377 if (parent
instanceof JavaDummyHolder
) {
378 parent
= parent
.getContext();
381 if (parent
instanceof PsiAnonymousClass
) {
382 parent
= parent
.getParent();
384 final PsiExpression qualifier
;
385 if (parent
instanceof PsiNewExpression
) {
386 qualifier
= ((PsiNewExpression
)parent
).getQualifier();
387 LOG
.assertTrue(qualifier
!= null);
389 else if (parent
instanceof PsiJavaCodeReferenceElement
) {
390 return JavaResolveResult
.EMPTY_ARRAY
;
393 LOG
.assertTrue(false, "Invalid java reference!");
394 return JavaResolveResult
.EMPTY_ARRAY
;
397 final PsiType qualifierType
= qualifier
.getType();
398 if (qualifierType
== null) return JavaResolveResult
.EMPTY_ARRAY
;
399 if (!(qualifierType
instanceof PsiClassType
)) return JavaResolveResult
.EMPTY_ARRAY
;
400 final JavaResolveResult result
= PsiUtil
.resolveGenericsClassInType(qualifierType
);
401 if (result
.getElement() == null) return JavaResolveResult
.EMPTY_ARRAY
;
402 final PsiElement classNameElement
= getReferenceNameElement();
403 if (!(classNameElement
instanceof PsiIdentifier
)) return JavaResolveResult
.EMPTY_ARRAY
;
404 final String className
= classNameElement
.getText();
406 final ClassResolverProcessor processor
= new ClassResolverProcessor(className
, this);
407 result
.getElement().processDeclarations(processor
, ResolveState
.initial().put(PsiSubstitutor
.KEY
, result
.getSubstitutor()), this, this);
408 return processor
.getResult();
410 case CLASS_NAME_KIND
: {
411 final PsiElement classNameElement
= getReferenceNameElement();
412 if (!(classNameElement
instanceof PsiIdentifier
)) return JavaResolveResult
.EMPTY_ARRAY
;
413 final String className
= classNameElement
.getText();
415 final ClassResolverProcessor processor
= new ClassResolverProcessor(className
, this);
416 PsiScopesUtil
.resolveAndWalk(processor
, this, null);
418 return processor
.getResult();
421 case PACKAGE_NAME_KIND
:
422 final String packageName
= getTextSkipWhiteSpaceAndComments();
423 final PsiManager manager
= getManager();
424 final PsiPackage aPackage
= JavaPsiFacade
.getInstance(manager
.getProject()).findPackage(packageName
);
425 if (aPackage
== null || !aPackage
.isValid()) {
426 return JavaPsiFacade
.getInstance(manager
.getProject()).isPartOfPackagePrefix(packageName
)
427 ? CandidateInfo
.RESOLVE_RESULT_FOR_PACKAGE_PREFIX_PACKAGE
428 : JavaResolveResult
.EMPTY_ARRAY
;
430 return new JavaResolveResult
[]{new CandidateInfo(aPackage
, PsiSubstitutor
.EMPTY
)};
432 case CLASS_FQ_OR_PACKAGE_NAME_KIND
: {
433 final JavaResolveResult
[] result
= resolve(CLASS_FQ_NAME_KIND
);
434 if (result
.length
== 0) {
435 return resolve(PACKAGE_NAME_KIND
);
439 case CLASS_OR_PACKAGE_NAME_KIND
:
440 final JavaResolveResult
[] classResolveResult
= resolve(CLASS_NAME_KIND
);
441 // [dsl]todo[ik]: review this change I guess ResolveInfo should be merged if both
442 // class and package resolve failed.
443 if (classResolveResult
.length
== 0) {
444 final JavaResolveResult
[] packageResolveResult
= resolve(PACKAGE_NAME_KIND
);
445 if (packageResolveResult
.length
> 0) return packageResolveResult
;
447 return classResolveResult
;
449 LOG
.assertTrue(false);
451 return JavaResolveResult
.EMPTY_ARRAY
;
454 public final PsiElement
handleElementRename(final String newElementName
) throws IncorrectOperationException
{
455 final PsiElement oldIdentifier
= getReferenceNameElement();
456 if (oldIdentifier
== null) {
457 throw new IncorrectOperationException();
459 final PsiElement identifier
= JavaPsiFacade
.getInstance(getProject()).getElementFactory().createIdentifier(newElementName
);
460 oldIdentifier
.replace(identifier
);
465 public PsiElement
bindToElement(@NotNull final PsiElement element
) throws IncorrectOperationException
{
466 CheckUtil
.checkWritable(this);
467 if (isReferenceTo(element
)) return this;
470 case CLASS_NAME_KIND
:
471 case CLASS_FQ_NAME_KIND
:
472 if (!(element
instanceof PsiClass
)) {
473 throw cannotBindError(element
);
475 return bindToClass((PsiClass
)element
);
477 case PACKAGE_NAME_KIND
:
478 if (!(element
instanceof PsiPackage
)) {
479 throw cannotBindError(element
);
481 return bindToPackage((PsiPackage
)element
);
483 case CLASS_OR_PACKAGE_NAME_KIND
:
484 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
485 if (element
instanceof PsiClass
) {
486 return bindToClass((PsiClass
)element
);
488 else if (element
instanceof PsiPackage
) {
489 return bindToPackage((PsiPackage
)element
);
492 throw cannotBindError(element
);
494 case CLASS_IN_QUALIFIED_NEW_KIND
:
495 if (element
instanceof PsiClass
) {
496 final PsiClass aClass
= (PsiClass
)element
;
497 final String name
= aClass
.getName();
499 throw new IncorrectOperationException(aClass
.toString());
501 final TreeElement ref
=
502 Parsing
.parseJavaCodeReferenceText(aClass
.getManager(), name
, SharedImplUtil
.findCharTableByTree(this));
503 getTreeParent().replaceChildInternal(this, ref
);
504 return SourceTreeToPsiMap
.treeElementToPsi(ref
);
507 throw cannotBindError(element
);
511 LOG
.assertTrue(false);
516 private static IncorrectOperationException
cannotBindError(final PsiElement element
) {
517 return new IncorrectOperationException("Cannot bind to "+element
);
520 private PsiElement
bindToClass(final PsiClass aClass
) throws IncorrectOperationException
{
521 String qName
= aClass
.getQualifiedName();
522 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(getProject());
524 qName
= aClass
.getName();
525 final PsiClass psiClass
= facade
.getResolveHelper().resolveReferencedClass(qName
, this);
526 if (!getManager().areElementsEquivalent(psiClass
, aClass
)) {
527 throw cannotBindError(aClass
);
531 if (facade
.findClass(qName
, getResolveScope()) == null) {
536 final boolean preserveQualification
= CodeStyleSettingsManager
.getSettings(getProject()).USE_FQ_CLASS_NAMES
&& isFullyQualified();
537 final PsiManager manager
= aClass
.getManager();
538 String text
= qName
+ getParameterList().getText();
539 ASTNode ref
= Parsing
.parseJavaCodeReferenceText(manager
, text
, SharedImplUtil
.findCharTableByTree(this));
540 LOG
.assertTrue(ref
!= null, "Failed to parse reference from text '" + text
+ "'");
541 getTreeParent().replaceChildInternal(this, (TreeElement
)ref
);
542 if (!preserveQualification
/*&& (TreeUtil.findParent(ref, ElementType.DOC_COMMENT) == null)*/) {
543 final JavaCodeStyleManager codeStyleManager
= JavaCodeStyleManager
.getInstance(aClass
.getProject());
544 ref
= SourceTreeToPsiMap
.psiElementToTree(
545 codeStyleManager
.shortenClassReferences(SourceTreeToPsiMap
.treeElementToPsi(ref
), JavaCodeStyleManager
.UNCOMPLETE_CODE
)
548 return SourceTreeToPsiMap
.treeElementToPsi(ref
);
551 private boolean isFullyQualified() {
553 case CLASS_OR_PACKAGE_NAME_KIND
:
554 if (resolve() instanceof PsiPackage
) return true;
555 case CLASS_NAME_KIND
:
558 case PACKAGE_NAME_KIND
:
559 case CLASS_FQ_NAME_KIND
:
560 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
564 LOG
.assertTrue(false);
568 final ASTNode qualifier
= findChildByRole(ChildRole
.QUALIFIER
);
569 if (qualifier
== null) return false;
571 LOG
.assertTrue(qualifier
.getElementType() == JavaElementType
.JAVA_CODE_REFERENCE
);
572 final PsiElement refElement
= ((PsiJavaCodeReferenceElement
)SourceTreeToPsiMap
.treeElementToPsi(qualifier
)).resolve();
573 if (refElement
instanceof PsiPackage
) return true;
575 return ((PsiJavaCodeReferenceElementImpl
)SourceTreeToPsiMap
.treeElementToPsi(qualifier
)).isFullyQualified();
578 private PsiElement
bindToPackage(final PsiPackage aPackage
) throws IncorrectOperationException
{
579 final String qName
= aPackage
.getQualifiedName();
580 if (qName
.length() == 0) {
581 throw new IncorrectOperationException("Cannot bind to default package: "+aPackage
);
583 final TreeElement ref
= Parsing
.parseJavaCodeReferenceText(getManager(), qName
, SharedImplUtil
.findCharTableByTree(this));
584 getTreeParent().replaceChildInternal(this, ref
);
585 return SourceTreeToPsiMap
.treeElementToPsi(ref
);
588 public boolean isReferenceTo(final PsiElement element
) {
590 case CLASS_NAME_KIND
:
591 case CLASS_IN_QUALIFIED_NEW_KIND
:
592 if (!(element
instanceof PsiClass
)) return false;
595 case CLASS_FQ_NAME_KIND
: {
596 if (!(element
instanceof PsiClass
)) return false;
597 final String qName
= ((PsiClass
)element
).getQualifiedName();
598 return qName
!= null && qName
.equals(getCanonicalText());
601 case PACKAGE_NAME_KIND
: {
602 if (!(element
instanceof PsiPackage
)) return false;
603 final String qName
= ((PsiPackage
)element
).getQualifiedName();
604 return qName
.equals(getCanonicalText());
607 case CLASS_OR_PACKAGE_NAME_KIND
:
608 // if (lastChild.type != IDENTIFIER) return false;
609 if (element
instanceof PsiPackage
) {
610 final String qName
= ((PsiPackage
)element
).getQualifiedName();
611 return qName
.equals(getCanonicalText());
613 else if (element
instanceof PsiClass
) {
614 final PsiIdentifier nameIdentifier
= ((PsiClass
)element
).getNameIdentifier();
615 if (nameIdentifier
== null) return false;
616 PsiElement nameElement
= getReferenceNameElement();
617 return nameElement
!= null && nameElement
.textMatches(nameIdentifier
) &&
618 element
.getManager().areElementsEquivalent(resolve(), element
);
624 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
625 if (element
instanceof PsiClass
) {
626 final String qName
= ((PsiClass
)element
).getQualifiedName();
627 return qName
!= null && qName
.equals(getCanonicalText());
629 else if (element
instanceof PsiPackage
) {
630 final String qName
= ((PsiPackage
)element
).getQualifiedName();
631 return qName
.equals(getCanonicalText());
637 LOG
.assertTrue(false);
641 final ASTNode referenceNameElement
= getReferenceNameNode();
642 if (referenceNameElement
== null || referenceNameElement
.getElementType() != JavaTokenType
.IDENTIFIER
) return false;
643 final String name
= ((PsiClass
)element
).getName();
644 return name
!= null && referenceNameElement
.getText().equals(name
) && element
.getManager().areElementsEquivalent(resolve(), element
);
647 private String
getTextSkipWhiteSpaceAndComments() {
648 String whiteSpaceAndComments
= myCachedTextSkipWhiteSpaceAndComments
;
649 if (whiteSpaceAndComments
== null) {
650 myCachedTextSkipWhiteSpaceAndComments
= whiteSpaceAndComments
= SourceUtil
.getTextSkipWhiteSpaceAndComments(this);
652 return whiteSpaceAndComments
;
655 public String
getClassNameText() {
656 String cachedQName
= myCachedQName
;
657 if (cachedQName
== null) {
658 myCachedQName
= cachedQName
= PsiNameHelper
.getQualifiedClassName(getTextSkipWhiteSpaceAndComments(), false);
663 public void fullyQualify(final PsiClass targetClass
) {
664 final int kind
= getKind();
665 if (kind
!= CLASS_NAME_KIND
&& kind
!= CLASS_OR_PACKAGE_NAME_KIND
&& kind
!= CLASS_IN_QUALIFIED_NEW_KIND
) {
666 LOG
.error("Wrong kind " + kind
);
669 JavaSourceUtil
.fullyQualifyReference(this, targetClass
);
672 public boolean isQualified() {
673 return getChildRole(getFirstChildNode()) != ChildRole
.REFERENCE_NAME
;
676 public PsiElement
getQualifier() {
677 return SourceTreeToPsiMap
.treeElementToPsi(findChildByRole(ChildRole
.QUALIFIER
));
680 public void clearCaches() {
682 myCachedQName
= null;
683 myCachedTextSkipWhiteSpaceAndComments
= null;
686 public Object
[] getVariants() {
687 final ElementFilter filter
;
690 case CLASS_OR_PACKAGE_NAME_KIND
:
691 filter
= new OrFilter();
692 ((OrFilter
)filter
).addFilter(ElementClassFilter
.CLASS
);
693 ((OrFilter
)filter
).addFilter(ElementClassFilter
.PACKAGE_FILTER
);
695 case CLASS_NAME_KIND
:
696 filter
= ElementClassFilter
.CLASS
;
698 case PACKAGE_NAME_KIND
:
699 filter
= ElementClassFilter
.PACKAGE_FILTER
;
701 case CLASS_FQ_NAME_KIND
:
702 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
703 filter
= new OrFilter();
704 ((OrFilter
)filter
).addFilter(ElementClassFilter
.PACKAGE_FILTER
);
706 ((OrFilter
)filter
).addFilter(ElementClassFilter
.CLASS
);
709 case CLASS_IN_QUALIFIED_NEW_KIND
:
710 filter
= ElementClassFilter
.CLASS
;
713 throw new RuntimeException("Unknown reference type");
716 return PsiImplUtil
.getReferenceVariantsByFilter(this, filter
);
719 public boolean isSoft() {
723 public void processVariants(final PsiScopeProcessor processor
) {
724 final OrFilter filter
= new OrFilter();
725 PsiElement superParent
= getParent();
726 boolean smartCompletion
= true;
728 smartCompletion
= false;
731 while (superParent
!= null) {
732 if (superParent
instanceof PsiCodeBlock
|| superParent
instanceof PsiVariable
) {
733 smartCompletion
= false;
736 superParent
= superParent
.getParent();
739 if (!smartCompletion
&& !isCodeFragmentType(getTreeParent().getElementType()) && !(getParent() instanceof PsiAnnotation
)) {
740 /*filter.addFilter(ElementClassFilter.CLASS);
741 filter.addFilter(ElementClassFilter.PACKAGE);*/
742 filter
.addFilter(new AndFilter(ElementClassFilter
.METHOD
, new NotFilter(new ConstructorFilter())));
743 filter
.addFilter(ElementClassFilter
.VARIABLE
);
746 case CLASS_OR_PACKAGE_NAME_KIND
:
747 addClassFilter(filter
);
748 filter
.addFilter(ElementClassFilter
.PACKAGE_FILTER
);
750 case CLASS_NAME_KIND
:
751 addClassFilter(filter
);
753 case PACKAGE_NAME_KIND
:
754 filter
.addFilter(ElementClassFilter
.PACKAGE_FILTER
);
756 case CLASS_FQ_NAME_KIND
:
757 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
758 filter
.addFilter(ElementClassFilter
.PACKAGE_FILTER
);
760 filter
.addFilter(ElementClassFilter
.CLASS
);
763 case CLASS_IN_QUALIFIED_NEW_KIND
:
764 final PsiElement parent
= getParent();
765 if (parent
instanceof PsiNewExpression
) {
766 final PsiNewExpression newExpr
= (PsiNewExpression
)parent
;
767 final PsiType type
= newExpr
.getQualifier().getType();
768 final PsiClass aClass
= PsiUtil
.resolveClassInType(type
);
769 if (aClass
!= null) {
770 aClass
.processDeclarations(new FilterScopeProcessor(new AndFilter(ElementClassFilter
.CLASS
, new ModifierFilter(PsiModifier
.STATIC
, false)),
771 processor
), ResolveState
.initial(), null, this);
774 // throw new RuntimeException("Qualified new is not allowed for primitives");
778 // throw new RuntimeException("Reference type is qualified new, but parent expression is: " + getParent());
783 throw new RuntimeException("Unknown reference type");
785 final FilterScopeProcessor proc
= new FilterScopeProcessor(filter
, processor
);
786 PsiScopesUtil
.resolveAndWalk(proc
, this, null, true);
789 private void addClassFilter(final OrFilter filter
) {
790 if (getParent() instanceof PsiAnnotation
) {
791 filter
.addFilter(new AnnotationTypeFilter());
794 filter
.addFilter(ElementClassFilter
.CLASS
);
798 public PsiElement
getReferenceNameElement() {
799 return SourceTreeToPsiMap
.treeElementToPsi(getReferenceNameNode());
803 private ASTNode
getReferenceNameNode() {
804 return findChildByRole(ChildRole
.REFERENCE_NAME
);
808 public PsiReferenceParameterList
getParameterList() {
809 return (PsiReferenceParameterList
)findChildByRoleAsPsiElement(ChildRole
.REFERENCE_PARAMETER_LIST
);
812 public String
getQualifiedName() {
814 case CLASS_NAME_KIND
:
815 case CLASS_OR_PACKAGE_NAME_KIND
:
816 case CLASS_IN_QUALIFIED_NEW_KIND
:
817 final PsiElement target
= resolve();
818 if (target
instanceof PsiClass
) {
819 final PsiClass aClass
= (PsiClass
)target
;
820 String name
= aClass
.getQualifiedName();
822 name
= aClass
.getName(); //?
826 else if (target
instanceof PsiPackage
) {
827 return ((PsiPackage
)target
).getQualifiedName();
830 LOG
.assertTrue(target
== null);
831 return getClassNameText();
834 case PACKAGE_NAME_KIND
:
835 case CLASS_FQ_NAME_KIND
:
836 case CLASS_FQ_OR_PACKAGE_NAME_KIND
:
837 return getTextSkipWhiteSpaceAndComments(); // there cannot be any <...>
840 LOG
.assertTrue(false);
846 public String
getReferenceName() {
847 final ASTNode childByRole
= getReferenceNameNode();
848 if (childByRole
== null) return null;
849 return childByRole
.getText();
852 public final TextRange
getRangeInElement() {
853 final TreeElement nameChild
= (TreeElement
)getReferenceNameNode();
854 if (nameChild
== null) return new TextRange(0, getTextLength());
855 final int startOffset
= nameChild
.getStartOffsetInParent();
856 return new TextRange(startOffset
, startOffset
+ nameChild
.getTextLength());
860 public PsiType
[] getTypeParameters() {
861 final PsiReferenceParameterList parameterList
= getParameterList();
862 if (parameterList
== null) return PsiType
.EMPTY_ARRAY
;
863 return parameterList
.getTypeArguments();
867 public final PsiElement
getElement() {
871 public final void accept(@NotNull final PsiElementVisitor visitor
) {
872 if (visitor
instanceof JavaElementVisitor
) {
873 ((JavaElementVisitor
)visitor
).visitReferenceElement(this);
876 visitor
.visitElement(this);
880 public final String
toString() {
881 return "PsiJavaCodeReferenceElement:" + getText();