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
.compiled
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.util
.TextRange
;
20 import com
.intellij
.openapi
.util
.text
.StringUtil
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.impl
.PsiManagerEx
;
23 import com
.intellij
.psi
.impl
.PsiSubstitutorImpl
;
24 import com
.intellij
.psi
.impl
.source
.resolve
.ResolveCache
;
25 import com
.intellij
.psi
.impl
.source
.tree
.JavaElementType
;
26 import com
.intellij
.psi
.impl
.source
.tree
.TreeElement
;
27 import com
.intellij
.psi
.infos
.CandidateInfo
;
28 import com
.intellij
.psi
.scope
.PsiScopeProcessor
;
29 import com
.intellij
.psi
.util
.PsiUtil
;
30 import com
.intellij
.util
.IncorrectOperationException
;
31 import com
.intellij
.util
.containers
.HashMap
;
32 import org
.jetbrains
.annotations
.NonNls
;
33 import org
.jetbrains
.annotations
.NotNull
;
37 public class ClsJavaCodeReferenceElementImpl
extends ClsElementImpl
implements PsiJavaCodeReferenceElement
{
38 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.compiled.ClsJavaCodeReferenceElementImpl");
40 private final PsiElement myParent
;
41 private final String myCanonicalText
;
42 private final String myQualifiedName
;
43 private final ClsTypeElementImpl
[] myTypeParameters
; // in right-to-left order
44 private volatile PsiType
[] myTypeParametersCachedTypes
= null; // in left-to-right-order
45 @NonNls private static final String EXTENDS_PREFIX
= "?extends";
46 @NonNls private static final String SUPER_PREFIX
= "?super";
48 public ClsJavaCodeReferenceElementImpl(PsiElement parent
, String canonicalText
) {
51 myCanonicalText
= canonicalText
;
52 final String
[] classParametersText
= PsiNameHelper
.getClassParametersText(canonicalText
);
53 int length
= classParametersText
.length
;
54 myTypeParameters
= length
== 0 ? ClsTypeElementImpl
.EMPTY_ARRAY
: new ClsTypeElementImpl
[length
];
55 for (int i
= 0; i
< length
; i
++) {
56 String s
= classParametersText
[length
- i
- 1];
57 char variance
= ClsTypeElementImpl
.VARIANCE_NONE
;
58 if (s
.startsWith(EXTENDS_PREFIX
)) {
59 variance
= ClsTypeElementImpl
.VARIANCE_EXTENDS
;
60 s
= s
.substring(EXTENDS_PREFIX
.length());
62 else if (s
.startsWith(SUPER_PREFIX
)) {
63 variance
= ClsTypeElementImpl
.VARIANCE_SUPER
;
64 s
= s
.substring(SUPER_PREFIX
.length());
66 else if (StringUtil
.startsWithChar(s
, '?')) {
67 variance
= ClsTypeElementImpl
.VARIANCE_INVARIANT
;
71 myTypeParameters
[i
] = new ClsTypeElementImpl(this, s
, variance
);
74 myQualifiedName
= PsiNameHelper
.getQualifiedClassName(myCanonicalText
, false);
78 public PsiElement
[] getChildren() {
79 return PsiElement
.EMPTY_ARRAY
;
82 public PsiElement
getParent() {
86 public String
getText() {
87 return PsiNameHelper
.getPresentableText(this);
90 public int getTextLength() {
91 return getText().length();
94 public PsiReference
getReference() {
98 public String
getCanonicalText() {
99 return myCanonicalText
;
102 private static class Resolver
implements ResolveCache
.PolyVariantResolver
<ClsJavaCodeReferenceElementImpl
> {
103 public static final Resolver INSTANCE
= new Resolver();
105 public JavaResolveResult
[] resolve(ClsJavaCodeReferenceElementImpl ref
, boolean incompleteCode
) {
106 final JavaResolveResult resolveResult
= ref
.advancedResolveImpl();
107 return resolveResult
.getElement() == null ? JavaResolveResult
.EMPTY_ARRAY
: new JavaResolveResult
[] {resolveResult
};
111 private JavaResolveResult
advancedResolveImpl() {
112 final PsiElement resolve
= resolveElement();
113 if (resolve
instanceof PsiClass
) {
114 final Map
<PsiTypeParameter
, PsiType
> substitutionMap
= new HashMap
<PsiTypeParameter
, PsiType
>();
116 for (PsiTypeParameter parameter
: PsiUtil
.typeParametersIterable((PsiClass
)resolve
)) {
117 if (index
>= myTypeParameters
.length
) {
118 substitutionMap
.put(parameter
, null);
121 substitutionMap
.put(parameter
, myTypeParameters
[index
].getType());
125 return new CandidateInfo(resolve
, PsiSubstitutorImpl
.createSubstitutor(substitutionMap
));
128 return new CandidateInfo(resolve
, PsiSubstitutor
.EMPTY
);
134 public JavaResolveResult
advancedResolve(boolean incompleteCode
) {
135 final JavaResolveResult
[] results
= multiResolve(incompleteCode
);
136 if (results
.length
== 1) return results
[0];
137 return JavaResolveResult
.EMPTY
;
141 public JavaResolveResult
[] multiResolve(boolean incompleteCode
) {
142 final ResolveCache resolveCache
= ((PsiManagerEx
)getManager()).getResolveCache();
143 ResolveResult
[] results
= resolveCache
.resolveWithCaching(this, Resolver
.INSTANCE
, true, incompleteCode
);
144 return (JavaResolveResult
[])results
;
147 public PsiElement
resolve() {
148 return advancedResolve(false).getElement();
151 private PsiElement
resolveElement() {
152 PsiElement element
= getParent();
153 while(element
!= null && (!(element
instanceof PsiClass
) || element
instanceof PsiTypeParameter
)) {
154 if(element
instanceof PsiMethod
){
155 final PsiMethod method
= (PsiMethod
)element
;
156 final PsiTypeParameterList list
= method
.getTypeParameterList();
158 final PsiTypeParameter
[] parameters
= list
.getTypeParameters();
159 for (int i
= 0; parameters
!= null && i
< parameters
.length
; i
++) {
160 final PsiTypeParameter parameter
= parameters
[i
];
161 if (myQualifiedName
.equals(parameter
.getName())) return parameter
;
165 element
= element
.getParent();
167 if (element
== null) return null;
168 for (PsiTypeParameter parameter
: PsiUtil
.typeParametersIterable((PsiTypeParameterListOwner
)element
)) {
169 if (myQualifiedName
.equals(parameter
.getName())) return parameter
;
171 return JavaPsiFacade
.getInstance(getProject()).findClass(myQualifiedName
, getResolveScope());
174 public void processVariants(PsiScopeProcessor processor
) {
175 throw new RuntimeException("Variants are not available for light references");
178 public PsiElement
getReferenceNameElement() {
182 public PsiReferenceParameterList
getParameterList() {
186 public String
getQualifiedName() {
187 return getCanonicalText();
190 public String
getReferenceName() {
191 return PsiNameHelper
.getShortClassName(myCanonicalText
);
194 public PsiElement
handleElementRename(String newElementName
) throws IncorrectOperationException
{
195 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
198 public PsiElement
bindToElement(@NotNull PsiElement element
) throws IncorrectOperationException
{
199 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
202 public boolean isReferenceTo(PsiElement element
) {
203 if (!(element
instanceof PsiClass
)) return false;
204 PsiClass aClass
= (PsiClass
)element
;
205 return myCanonicalText
.equals(aClass
.getQualifiedName())
206 || getManager().areElementsEquivalent(resolve(), element
);
209 public Object
[] getVariants() {
210 throw new RuntimeException("Variants are not available for references to compiled code");
213 public boolean isSoft() {
217 public void appendMirrorText(final int indentLevel
, final StringBuffer buffer
) {
218 buffer
.append(getCanonicalText());
221 public void setMirror(@NotNull TreeElement element
) {
222 setMirrorCheckingType(element
, JavaElementType
.JAVA_CODE_REFERENCE
);
225 public void accept(@NotNull PsiElementVisitor visitor
) {
226 if (visitor
instanceof JavaElementVisitor
) {
227 ((JavaElementVisitor
)visitor
).visitReferenceElement(this);
230 visitor
.visitElement(this);
235 public String
toString() {
236 return "PsiJavaCodeReferenceElement:" + getText();
239 public TextRange
getRangeInElement() {
240 return new TextRange(0, getTextLength());
243 public PsiElement
getElement() {
248 public PsiType
[] getTypeParameters() {
249 PsiType
[] cachedTypes
= myTypeParametersCachedTypes
;
250 if (cachedTypes
== null) {
251 cachedTypes
= myTypeParameters
.length
== 0 ? PsiType
.EMPTY_ARRAY
: new PsiType
[myTypeParameters
.length
];
252 for (int i
= 0; i
< cachedTypes
.length
; i
++) {
253 cachedTypes
[cachedTypes
.length
- i
- 1] = myTypeParameters
[i
].getType();
255 myTypeParametersCachedTypes
= cachedTypes
;
260 public boolean isQualified() {
264 public PsiElement
getQualifier() {