update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / source / PsiImportStaticReferenceElementImpl.java
bloba61ed6a614ba8601d3d47eee975eaeb997383a73
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.source;
18 import com.intellij.codeInsight.daemon.JavaErrorMessages;
19 import com.intellij.lang.ASTNode;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.util.Key;
22 import com.intellij.openapi.util.TextRange;
23 import com.intellij.psi.*;
24 import com.intellij.psi.filters.ClassFilter;
25 import com.intellij.psi.impl.source.parsing.Parsing;
26 import com.intellij.psi.impl.source.resolve.ResolveCache;
27 import com.intellij.psi.impl.source.tree.*;
28 import com.intellij.psi.scope.BaseScopeProcessor;
29 import com.intellij.psi.scope.NameHint;
30 import com.intellij.psi.scope.PsiScopeProcessor;
31 import com.intellij.psi.scope.processor.FilterScopeProcessor;
32 import com.intellij.psi.scope.util.PsiScopesUtil;
33 import com.intellij.psi.tree.ChildRoleBase;
34 import com.intellij.psi.tree.IElementType;
35 import com.intellij.psi.util.PsiTreeUtil;
36 import com.intellij.util.ArrayUtil;
37 import com.intellij.util.IncorrectOperationException;
38 import org.jetbrains.annotations.NotNull;
40 import java.util.ArrayList;
41 import java.util.List;
43 /**
44 * @author dsl
46 public class PsiImportStaticReferenceElementImpl extends CompositePsiElement implements PsiImportStaticReferenceElement {
47 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiImportStaticReferenceElementImpl");
48 private volatile String myCanonicalText;
50 public PsiImportStaticReferenceElementImpl() {
51 super(JavaElementType.IMPORT_STATIC_REFERENCE);
54 public int getTextOffset() {
55 ASTNode refName = findChildByRole(ChildRole.REFERENCE_NAME);
56 if (refName != null){
57 return refName.getStartOffset();
59 else{
60 return super.getTextOffset();
64 public void clearCaches() {
65 super.clearCaches();
66 myCanonicalText = null;
69 public final ASTNode findChildByRole(int role) {
70 LOG.assertTrue(ChildRole.isUnique(role));
71 switch(role){
72 default:
73 return null;
75 case ChildRole.REFERENCE_NAME:
76 if (getLastChildNode().getElementType() == JavaTokenType.IDENTIFIER){
77 return getLastChildNode();
79 else{
80 return null;
83 case ChildRole.QUALIFIER:
84 if (getFirstChildNode().getElementType() == JavaElementType.JAVA_CODE_REFERENCE){
85 return getFirstChildNode();
87 else{
88 return null;
91 case ChildRole.DOT:
92 return findChildByType(JavaTokenType.DOT);
96 public final int getChildRole(ASTNode child) {
97 LOG.assertTrue(child.getTreeParent() == this);
98 IElementType i = child.getElementType();
99 if (i == JavaElementType.JAVA_CODE_REFERENCE) {
100 return ChildRole.QUALIFIER;
102 else if (i == JavaTokenType.DOT) {
103 return ChildRole.DOT;
105 else if (i == JavaTokenType.IDENTIFIER) {
106 return ChildRole.REFERENCE_NAME;
108 else {
109 return ChildRoleBase.NONE;
114 public PsiElement getReferenceNameElement() {
115 return findChildByRoleAsPsiElement(ChildRole.REFERENCE_NAME);
118 public PsiReferenceParameterList getParameterList() {
119 return null;
122 @NotNull
123 public PsiType[] getTypeParameters() {
124 return PsiType.EMPTY_ARRAY;
127 public PsiElement getQualifier() {
128 return findChildByRoleAsPsiElement(ChildRole.QUALIFIER);
131 public PsiJavaCodeReferenceElement getClassReference() {
132 return (PsiJavaCodeReferenceElement)findChildByRoleAsPsiElement(ChildRole.QUALIFIER);
135 public PsiImportStaticStatement bindToTargetClass(PsiClass aClass) throws IncorrectOperationException {
136 final String qualifiedName = aClass.getQualifiedName();
137 if (qualifiedName == null) throw new IncorrectOperationException();
138 final CompositeElement newRef = Parsing.parseJavaCodeReferenceText(getManager(), qualifiedName, SharedImplUtil.findCharTableByTree(this));
139 if (getQualifier() != null) {
140 replaceChildInternal(findChildByRole(ChildRole.QUALIFIER), newRef);
141 return (PsiImportStaticStatement)getParent();
143 else {
144 final LeafElement dot = Factory.createSingleLeafElement(JavaTokenType.DOT, ".", 0, 1, SharedImplUtil.findCharTableByTree(newRef), getManager());
145 newRef.rawInsertAfterMe(dot);
146 final CompositeElement errorElement =
147 Factory.createErrorElement(JavaErrorMessages.message("import.statement.identifier.or.asterisk.expected."));
148 dot.rawInsertAfterMe(errorElement);
149 final CompositeElement parentComposite = (CompositeElement)SourceTreeToPsiMap.psiElementToTree(getParent());
150 parentComposite.addInternal(newRef, errorElement, this, Boolean.TRUE);
151 parentComposite.deleteChildInternal(this);
152 return (PsiImportStaticStatement)SourceTreeToPsiMap.treeElementToPsi(parentComposite);
156 public boolean isQualified() {
157 return findChildByRole(ChildRole.QUALIFIER) != null;
160 public String getQualifiedName() {
161 return getCanonicalText();
164 public boolean isSoft() {
165 return false;
168 public String getReferenceName() {
169 final ASTNode childByRole = findChildByRole(ChildRole.REFERENCE_NAME);
170 if (childByRole == null) return "";
171 return childByRole.getText();
174 public PsiElement getElement() {
175 return this;
178 public TextRange getRangeInElement() {
179 TreeElement nameChild = (TreeElement)findChildByRole(ChildRole.REFERENCE_NAME);
180 if (nameChild == null) return new TextRange(0, getTextLength());
181 final int startOffset = nameChild.getStartOffsetInParent();
182 return new TextRange(startOffset, startOffset + nameChild.getTextLength());
185 public String getCanonicalText() {
186 String canonicalText = myCanonicalText;
187 if (canonicalText == null) {
188 myCanonicalText = canonicalText = calcCanonicalText();
190 return canonicalText;
193 private String calcCanonicalText() {
194 final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)getQualifier();
195 if (referenceElement == null) {
196 return getReferenceName();
198 else {
199 return referenceElement.getCanonicalText() + "." + getReferenceName();
203 public String toString() {
204 return "PsiImportStaticReferenceElement:" + getText();
207 @NotNull
208 public JavaResolveResult advancedResolve(boolean incompleteCode) {
209 final JavaResolveResult[] results = multiResolve(incompleteCode);
210 if (results.length == 1) return results[0];
211 return JavaResolveResult.EMPTY;
214 @NotNull
215 public JavaResolveResult[] multiResolve(boolean incompleteCode) {
216 final ResolveCache resolveCache = getManager().getResolveCache();
217 return (JavaResolveResult[])resolveCache.resolveWithCaching(this, OurGenericsResolver.INSTANCE, true, incompleteCode);
220 private class OurResolveResult implements JavaResolveResult {
221 final PsiMember myTarget;
222 Boolean myAccessible = null;
225 public OurResolveResult(PsiMember target) {
226 myTarget = target;
229 public PsiMember getElement() {
230 return myTarget;
233 public PsiSubstitutor getSubstitutor() {
234 return PsiSubstitutor.EMPTY;
237 public boolean isValidResult() {
238 return isAccessible();
241 public boolean isAccessible() {
242 if (myAccessible == null) {
243 myAccessible = JavaPsiFacade.getInstance(getProject()).getResolveHelper().isAccessible(myTarget, PsiImportStaticReferenceElementImpl.this, null);
245 return myAccessible.booleanValue();
248 public boolean isStaticsScopeCorrect() {
249 return true;
252 public PsiElement getCurrentFileResolveScope() {
253 return null;
256 public boolean isPackagePrefixPackageReference() {
257 return false;
262 private static final class OurGenericsResolver implements ResolveCache.PolyVariantResolver<PsiImportStaticReferenceElementImpl> {
263 private static final OurGenericsResolver INSTANCE = new OurGenericsResolver();
264 public JavaResolveResult[] resolve(PsiImportStaticReferenceElementImpl referenceElement, boolean incompleteCode) {
265 final PsiElement qualifier = referenceElement.getQualifier();
266 if (!(qualifier instanceof PsiJavaCodeReferenceElement)) return JavaResolveResult.EMPTY_ARRAY;
267 final PsiElement target = ((PsiJavaCodeReferenceElement)qualifier).resolve();
268 if (!(target instanceof PsiClass)) return JavaResolveResult.EMPTY_ARRAY;
269 final ArrayList<JavaResolveResult> results = new ArrayList<JavaResolveResult>();
270 target
271 .processDeclarations(referenceElement.new MyScopeProcessor(results), ResolveState.initial(), referenceElement, referenceElement);
272 if (results.size() <= 1) {
273 return results.toArray(new JavaResolveResult[results.size()]);
275 for(int i = results.size() - 1; i >= 0; i--) {
276 final JavaResolveResult resolveResult = results.get(i);
277 if (!resolveResult.isValidResult()) {
278 results.remove(i);
281 return results.toArray(new JavaResolveResult[results.size()]);
286 private class MyScopeProcessor extends BaseScopeProcessor implements NameHint {
287 private final List<JavaResolveResult> myResults;
289 public MyScopeProcessor(List<JavaResolveResult> results) {
290 myResults = results;
293 public boolean execute(PsiElement element, ResolveState state) {
294 if (element instanceof PsiMember
295 && ((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) {
296 myResults.add(new OurResolveResult((PsiMember)element));
298 return true;
301 public String getName(ResolveState state) {
302 return getReferenceName();
305 @Override
306 public <T> T getHint(Key<T> hintKey) {
307 if (hintKey == NameHint.KEY) {
308 return (T)this;
311 return super.getHint(hintKey);
315 public PsiReference getReference() {
316 return this;
319 public PsiElement resolve() {
320 return advancedResolve(false).getElement();
323 public boolean isReferenceTo(PsiElement element) {
324 final String name = getReferenceName();
325 return name != null &&
326 element instanceof PsiNamedElement &&
327 name.equals(((PsiNamedElement)element).getName()) && element.getManager().areElementsEquivalent(resolve(), element);
330 public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
331 PsiElement oldIdentifier = findChildByRoleAsPsiElement(ChildRole.REFERENCE_NAME);
332 if (oldIdentifier == null){
333 throw new IncorrectOperationException();
335 PsiIdentifier identifier = JavaPsiFacade.getInstance(getProject()).getElementFactory().createIdentifier(newElementName);
336 oldIdentifier.replace(identifier);
337 return this;
340 public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
341 if (!(element instanceof PsiMember) ||
342 !(element instanceof PsiNamedElement) ||
343 ((PsiNamedElement)element).getName() == null) {
344 throw new IncorrectOperationException();
346 if (!((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) {
347 if (element instanceof PsiClass && ((PsiClass)element).getContainingClass() == null) {
348 // "move inner to upper level" of a statically imported inner class => replace with regular import
349 return replaceWithRegularImport((PsiClass) element);
351 throw new IncorrectOperationException();
354 PsiClass containingClass = ((PsiMember)element).getContainingClass();
355 if (containingClass == null) throw new IncorrectOperationException();
356 PsiElement qualifier = getQualifier();
357 if (qualifier == null) {
358 throw new IncorrectOperationException();
360 ((PsiReference)qualifier).bindToElement(containingClass);
362 PsiElement oldIdentifier = findChildByRoleAsPsiElement(ChildRole.REFERENCE_NAME);
363 if (oldIdentifier == null){
364 throw new IncorrectOperationException();
367 PsiIdentifier identifier = JavaPsiFacade.getInstance(getProject()).getElementFactory().createIdentifier(((PsiNamedElement)element).getName());
368 oldIdentifier.replace(identifier);
369 return this;
372 private PsiElement replaceWithRegularImport(final PsiClass psiClass) throws IncorrectOperationException {
373 PsiImportStaticStatement baseStatement = PsiTreeUtil.getParentOfType(getElement(), PsiImportStaticStatement.class);
374 PsiImportStatement statement = JavaPsiFacade.getInstance(getProject()).getElementFactory().createImportStatement(psiClass);
375 statement = (PsiImportStatement) baseStatement.replace(statement);
376 final PsiJavaCodeReferenceElement reference = statement.getImportReference();
377 assert reference != null;
378 return reference;
381 public void processVariants(PsiScopeProcessor processor) {
382 FilterScopeProcessor proc = new FilterScopeProcessor(new ClassFilter(PsiModifierListOwner.class), processor);
383 PsiScopesUtil.resolveAndWalk(proc, this, null, true);
386 public Object[] getVariants() {
387 // IMPLEMENT[dsl]
388 return ArrayUtil.EMPTY_OBJECT_ARRAY;
391 public void accept(@NotNull PsiElementVisitor visitor) {
392 if (visitor instanceof JavaElementVisitor) {
393 ((JavaElementVisitor)visitor).visitImportStaticReferenceElement(this);
395 else {
396 visitor.visitElement(this);