update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / compiled / ClsJavaCodeReferenceElementImpl.java
blob5708a57807150ea0d0f650f4948fa0a44b20d89e
1 /*
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;
35 import java.util.Map;
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) {
49 myParent = parent;
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;
68 s = s.substring(1);
71 myTypeParameters[i] = new ClsTypeElementImpl(this, s, variance);
74 myQualifiedName = PsiNameHelper.getQualifiedClassName(myCanonicalText, false);
77 @NotNull
78 public PsiElement[] getChildren() {
79 return PsiElement.EMPTY_ARRAY;
82 public PsiElement getParent() {
83 return myParent;
86 public String getText() {
87 return PsiNameHelper.getPresentableText(this);
90 public int getTextLength() {
91 return getText().length();
94 public PsiReference getReference() {
95 return this;
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>();
115 int index = 0;
116 for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable((PsiClass)resolve)) {
117 if (index >= myTypeParameters.length) {
118 substitutionMap.put(parameter, null);
120 else {
121 substitutionMap.put(parameter, myTypeParameters[index].getType());
123 index++;
125 return new CandidateInfo(resolve, PsiSubstitutorImpl.createSubstitutor(substitutionMap));
127 else {
128 return new CandidateInfo(resolve, PsiSubstitutor.EMPTY);
133 @NotNull
134 public JavaResolveResult advancedResolve(boolean incompleteCode) {
135 final JavaResolveResult[] results = multiResolve(incompleteCode);
136 if (results.length == 1) return results[0];
137 return JavaResolveResult.EMPTY;
140 @NotNull
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();
157 if (list != null) {
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() {
179 return null;
182 public PsiReferenceParameterList getParameterList() {
183 return null;
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() {
214 return false;
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);
229 else {
230 visitor.visitElement(this);
234 @NonNls
235 public String toString() {
236 return "PsiJavaCodeReferenceElement:" + getText();
239 public TextRange getRangeInElement() {
240 return new TextRange(0, getTextLength());
243 public PsiElement getElement() {
244 return this;
247 @NotNull
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;
257 return cachedTypes;
260 public boolean isQualified() {
261 return false;
264 public PsiElement getQualifier() {
265 return null;