1 /* 2 * Copyright 2014, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smalidea.psi.impl; 33 34 import com.intellij.openapi.util.TextRange; 35 import com.intellij.psi.*; 36 import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; 37 import com.intellij.psi.infos.CandidateInfo; 38 import com.intellij.psi.scope.PsiScopeProcessor; 39 import com.intellij.util.IncorrectOperationException; 40 import org.jetbrains.annotations.NotNull; 41 import org.jetbrains.annotations.Nullable; 42 import org.jf.smalidea.psi.SmaliCompositeElementFactory; 43 import org.jf.smalidea.psi.SmaliElementTypes; 44 import org.jf.smalidea.psi.leaf.SmaliClassDescriptor; 45 import org.jf.smalidea.util.NameUtils; 46 47 public class SmaliClassTypeElement extends SmaliTypeElement implements PsiJavaCodeReferenceElement { 48 public static final SmaliClassTypeElement[] EMPTY_ARRAY = new SmaliClassTypeElement[0]; 49 50 public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() { 51 @Override public SmaliCompositeElement createElement() { 52 return new SmaliClassTypeElement(); 53 } 54 }; 55 56 @Nullable private SmaliClassType classType = null; 57 58 public SmaliClassTypeElement() { 59 super(SmaliElementTypes.CLASS_TYPE); 60 } 61 62 @NotNull @Override public SmaliClassType getType() { 63 if (classType == null) { 64 classType = new SmaliClassType(this); 65 } 66 return classType; 67 } 68 69 @Override public String getName() { 70 return NameUtils.shortNameFromQualifiedName(getCanonicalText()); 71 } 72 73 @Nullable @Override public SmaliClassTypeElement getInnermostComponentReferenceElement() { 74 return this; 75 } 76 77 @Override public PsiElement getElement() { 78 return this; 79 } 80 81 @Override public PsiReference getReference() { 82 return this; 83 } 84 85 @Override public TextRange getRangeInElement() { 86 return new TextRange(0, getTextLength()); 87 } 88 89 @Nullable @Override public PsiClass resolve() { 90 return NameUtils.resolveSmaliType(this, getText()); 91 } 92 93 @NotNull @Override public String getCanonicalText() { 94 return getQualifiedName(); 95 } 96 97 @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { 98 SmaliClassDescriptor descriptor = getReferenceNameElement(); 99 if (descriptor == null) { 100 throw new IncorrectOperationException(); 101 } 102 103 SmaliClassDescriptor newDescriptor = new SmaliClassDescriptor(NameUtils.javaToSmaliType(newElementName)); 104 CodeEditUtil.setNodeGenerated(newDescriptor, true); 105 106 this.replaceChild(descriptor, newDescriptor); 107 return this; 108 } 109 110 @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { 111 if (element instanceof PsiClass) { 112 handleElementRename(((PsiClass) element).getQualifiedName()); 113 return this; 114 } 115 throw new IncorrectOperationException(); 116 } 117 118 @Override public boolean isReferenceTo(PsiElement element) { 119 if (!(element instanceof PsiClass)) { 120 return false; 121 } 122 return element.getManager().areElementsEquivalent(element, resolve()); 123 } 124 125 @NotNull @Override public Object[] getVariants() { 126 // TODO: implement this? 127 return new Object[0]; 128 } 129 130 @Override public boolean isSoft() { 131 return false; 132 } 133 134 // *************************************************************************** 135 // Below are the PsiJavaCodeReferenceElement-specific methods 136 137 @Override public void processVariants(@NotNull PsiScopeProcessor processor) { 138 // TODO: maybe just do nothing? 139 throw new UnsupportedOperationException(); 140 } 141 142 @Nullable @Override public SmaliClassDescriptor getReferenceNameElement() { 143 return findChildByClass(SmaliClassDescriptor.class); 144 } 145 146 @Nullable @Override public PsiReferenceParameterList getParameterList() { 147 // TODO: (generics) implement this 148 return null; 149 } 150 151 @NotNull @Override public PsiType[] getTypeParameters() { 152 // TODO: (generics) implement this 153 return new PsiType[0]; 154 } 155 156 @Override public boolean isQualified() { 157 // TODO: should this return false for classes in the top level package? 158 return true; 159 } 160 161 @Override public String getQualifiedName() { 162 PsiClass psiClass = resolve(); 163 if (psiClass != null) { 164 return psiClass.getQualifiedName(); 165 } 166 return NameUtils.smaliToJavaType(getText()); 167 } 168 169 @NotNull @Override public JavaResolveResult advancedResolve(boolean incompleteCode) { 170 PsiClass element = resolve(); 171 if (element == null) { 172 return JavaResolveResult.EMPTY; 173 } 174 return new CandidateInfo(element, PsiSubstitutor.EMPTY); 175 } 176 177 @NotNull @Override public JavaResolveResult[] multiResolve(boolean incompleteCode) { 178 PsiClass element = resolve(); 179 if (element == null) { 180 return JavaResolveResult.EMPTY_ARRAY; 181 } 182 return new CandidateInfo[] { new CandidateInfo(element, PsiSubstitutor.EMPTY) }; 183 } 184 185 @Nullable @Override public PsiElement getQualifier() { 186 return null; 187 } 188 189 @Nullable @Override public String getReferenceName() { 190 return getName(); 191 } 192 } 193