• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.google.common.collect.ImmutableList;
35 import com.google.common.collect.Lists;
36 import com.intellij.debugger.SourcePosition;
37 import com.intellij.lang.ASTNode;
38 import com.intellij.navigation.ItemPresentation;
39 import com.intellij.navigation.ItemPresentationProviders;
40 import com.intellij.openapi.util.Pair;
41 import com.intellij.openapi.vfs.VirtualFile;
42 import com.intellij.psi.*;
43 import com.intellij.psi.PsiModifier.ModifierConstant;
44 import com.intellij.psi.impl.InheritanceImplUtil;
45 import com.intellij.psi.impl.PsiClassImplUtil;
46 import com.intellij.psi.impl.PsiImplUtil;
47 import com.intellij.psi.javadoc.PsiDocComment;
48 import com.intellij.psi.scope.PsiScopeProcessor;
49 import com.intellij.psi.util.PsiUtil;
50 import com.intellij.util.IncorrectOperationException;
51 import com.sun.jdi.Location;
52 import com.sun.jdi.Method;
53 import com.sun.jdi.ReferenceType;
54 import org.jetbrains.annotations.NonNls;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
57 import org.jf.smalidea.SmaliIcons;
58 import org.jf.smalidea.psi.SmaliElementTypes;
59 import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
60 import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
61 import org.jf.smalidea.psi.stub.SmaliClassStub;
62 
63 import javax.annotation.Nonnull;
64 import javax.swing.*;
65 import java.util.Collection;
66 import java.util.List;
67 
68 public class SmaliClass extends SmaliStubBasedPsiElement<SmaliClassStub> implements PsiClass, SmaliModifierListOwner {
SmaliClass(@otNull SmaliClassStub stub)69     public SmaliClass(@NotNull SmaliClassStub stub) {
70         super(stub, SmaliElementTypes.CLASS);
71     }
72 
SmaliClass(@otNull ASTNode node)73     public SmaliClass(@NotNull ASTNode node) {
74         super(node);
75     }
76 
77     @Nonnull
78     @Override
getName()79     public String getName() {
80         String name = getQualifiedName();
81         if (name == null) {
82             return "";
83         }
84         int lastDot = name.lastIndexOf('.');
85         if (lastDot < 0) {
86             return name;
87         }
88         return name.substring(lastDot+1);
89     }
90 
getPresentation()91     @Override public ItemPresentation getPresentation() {
92         return ItemPresentationProviders.getItemPresentation(this);
93     }
94 
getQualifiedName()95     @Nullable @Override public String getQualifiedName() {
96         SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
97         if (classStatement == null) {
98             return null;
99         }
100         return classStatement.getQualifiedName();
101     }
102 
getPackageName()103     @NotNull public String getPackageName() {
104         String name = getQualifiedName();
105         if (name == null) {
106             return "";
107         }
108         int lastDot = name.lastIndexOf('.');
109         if (lastDot < 0) {
110             return "";
111         }
112         return name.substring(0, lastDot);
113     }
114 
hasTypeParameters()115     @Override public boolean hasTypeParameters() {
116         // TODO: implement generics
117         return false;
118     }
119 
isInterface()120     @Override public boolean isInterface() {
121         return hasModifierProperty("interface");
122     }
123 
isAnnotationType()124     @Override public boolean isAnnotationType() {
125         return hasModifierProperty("annotation");
126     }
127 
isEnum()128     @Override public boolean isEnum() {
129         return hasModifierProperty("enum");
130     }
131 
getSuperStatement()132     @Nullable public SmaliSuperStatement getSuperStatement() {
133         return findChildByClass(SmaliSuperStatement.class);
134     }
135 
getExtendsList()136     @NotNull @Override public SmaliExtendsList getExtendsList() {
137         return getRequiredStubOrPsiChild(SmaliElementTypes.EXTENDS_LIST);
138     }
139 
getImplementsStatements()140     @NotNull public SmaliImplementsStatement[] getImplementsStatements() {
141         return findChildrenByClass(SmaliImplementsStatement.class);
142     }
143 
getImplementsList()144     @NotNull @Override public SmaliImplementsList getImplementsList() {
145         return getRequiredStubOrPsiChild(SmaliElementTypes.IMPLEMENTS_LIST);
146     }
147 
getExtendsListTypes()148     @NotNull @Override public SmaliClassType[] getExtendsListTypes() {
149         return getExtendsList().getReferencedTypes();
150     }
151 
getImplementsListTypes()152     @NotNull @Override public SmaliClassType[] getImplementsListTypes() {
153         return getImplementsList().getReferencedTypes();
154     }
155 
getSuperClass()156     @Nullable @Override public PsiClass getSuperClass() {
157         return PsiClassImplUtil.getSuperClass(this);
158     }
159 
getInterfaces()160     @Override public PsiClass[] getInterfaces() {
161         return PsiClassImplUtil.getInterfaces(this);
162     }
163 
getSupers()164     @NotNull @Override public PsiClass[] getSupers() {
165         return PsiClassImplUtil.getSupers(this);
166     }
167 
getSuperTypes()168     @NotNull @Override public PsiClassType[] getSuperTypes() {
169         return PsiClassImplUtil.getSuperTypes(this);
170     }
171 
getFields()172     @NotNull @Override public SmaliField[] getFields() {
173         SmaliField[] fields = getStubOrPsiChildren(SmaliElementTypes.FIELD, new SmaliField[0]);
174         List<SmaliField> filteredFields = null;
175         for (int i=fields.length-1; i>=0; i--) {
176             SmaliField field = fields[i];
177             if (field.getName() == null) {
178                 if (filteredFields == null) {
179                     filteredFields = Lists.newArrayList(fields);
180                 }
181                 filteredFields.remove(i);
182             }
183         }
184         if (filteredFields != null) {
185             return filteredFields.toArray(new SmaliField[filteredFields.size()]);
186         }
187         return fields;
188     }
189 
getMethods()190     @NotNull @Override public SmaliMethod[] getMethods() {
191         return getStubOrPsiChildren(SmaliElementTypes.METHOD, new SmaliMethod[0]);
192     }
193 
getConstructors()194     @NotNull @Override public PsiMethod[] getConstructors() {
195         return PsiImplUtil.getConstructors(this);
196     }
197 
getInnerClasses()198     @NotNull @Override public PsiClass[] getInnerClasses() {
199         return new PsiClass[0];
200     }
201 
getInitializers()202     @NotNull @Override public PsiClassInitializer[] getInitializers() {
203         // TODO: do we need to return the <clinit> method here?
204         return new PsiClassInitializer[0];
205     }
206 
getAllFields()207     @NotNull @Override public PsiField[] getAllFields() {
208         return PsiClassImplUtil.getAllFields(this);
209     }
210 
getAllMethods()211     @NotNull @Override public PsiMethod[] getAllMethods() {
212         return PsiClassImplUtil.getAllMethods(this);
213     }
214 
getAllInnerClasses()215     @NotNull @Override public PsiClass[] getAllInnerClasses() {
216         return new PsiClass[0];
217     }
218 
findFieldByName(@onNls String name, boolean checkBases)219     @Nullable @Override public PsiField findFieldByName(@NonNls String name, boolean checkBases) {
220         return PsiClassImplUtil.findFieldByName(this, name, checkBases);
221     }
222 
findMethodBySignature(PsiMethod patternMethod, boolean checkBases)223     @Nullable @Override public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
224         return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
225     }
226 
findMethodsBySignature(PsiMethod patternMethod, boolean checkBases)227     @NotNull @Override public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
228         return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
229     }
230 
findMethodsByName(@onNls String name, boolean checkBases)231     @NotNull @Override public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) {
232         return PsiClassImplUtil.findMethodsByName(this, name, checkBases);
233     }
234 
235     @NotNull @Override
findMethodsAndTheirSubstitutorsByName(@onNls String name, boolean checkBases)236     public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) {
237         return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
238     }
239 
getAllMethodsAndTheirSubstitutors()240     @NotNull @Override public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
241         return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD);
242     }
243 
findInnerClassByName(@onNls String name, boolean checkBases)244     @Nullable @Override public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) {
245         return null;
246     }
247 
getLBrace()248     @Nullable @Override public PsiElement getLBrace() {
249         return null;
250     }
251 
getRBrace()252     @Nullable @Override public PsiElement getRBrace() {
253         return null;
254     }
255 
getClassStatement()256     @Nullable public SmaliClassStatement getClassStatement() {
257         return getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
258     }
259 
getNameIdentifier()260     @Nullable @Override public SmaliClassDescriptor getNameIdentifier() {
261         SmaliClassStatement classStatement = getClassStatement();
262         if (classStatement == null) {
263             return null;
264         }
265         return classStatement.getNameIdentifier();
266     }
267 
getScope()268     @Override public PsiElement getScope() {
269         return null;
270     }
271 
isInheritor(@otNull PsiClass baseClass, boolean checkDeep)272     @Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
273         return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
274     }
275 
isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass)276     @Override public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
277         return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
278     }
279 
getContainingClass()280     @Nullable @Override public PsiClass getContainingClass() {
281         return null;
282     }
283 
getVisibleSignatures()284     @NotNull @Override public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
285         return ImmutableList.of();
286     }
287 
setName(@onNls @otNull String name)288     @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
289         SmaliClassStatement classStatement = getClassStatement();
290         if (classStatement == null) {
291             throw new IncorrectOperationException();
292         }
293 
294         SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
295         if (classTypeElement == null) {
296             throw new IncorrectOperationException();
297         }
298 
299         String expectedPath = "/" + getName() + ".smali";
300 
301         VirtualFile virtualFile = this.getContainingFile().getVirtualFile();
302         if (virtualFile != null) {
303             String actualPath = virtualFile.getPath();
304             if (actualPath.endsWith(expectedPath)) {
305                 getContainingFile().setName(name + ".smali");
306             }
307         }
308 
309         String packageName = this.getPackageName();
310         String newName;
311         if (packageName.length() > 0) {
312             newName = packageName + "." + name;
313         } else {
314             newName = name;
315         }
316         classTypeElement.handleElementRename(newName);
317         return this;
318     }
319 
setPackageName(@onNls @otNull String packageName)320     public void setPackageName(@NonNls @NotNull String packageName) {
321         SmaliClassStatement classStatement = getClassStatement();
322         if (classStatement == null) {
323             throw new IncorrectOperationException();
324         }
325 
326         SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
327         if (classTypeElement == null) {
328             throw new IncorrectOperationException();
329         }
330 
331         String newName;
332         if (packageName.length() > 0) {
333             newName = packageName + "." + getName();
334         } else {
335             newName = getName();
336         }
337 
338         classTypeElement.handleElementRename(newName);
339     }
340 
getDocComment()341     @Nullable @Override public PsiDocComment getDocComment() {
342         return null;
343     }
344 
isDeprecated()345     @Override public boolean isDeprecated() {
346         return false;
347     }
348 
getTypeParameterList()349     @Nullable @Override public PsiTypeParameterList getTypeParameterList() {
350         return null;
351     }
352 
getTypeParameters()353     @NotNull @Override public PsiTypeParameter[] getTypeParameters() {
354         return new PsiTypeParameter[0];
355     }
356 
getModifierList()357     @Nullable @Override public SmaliModifierList getModifierList() {
358         SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
359         if (classStatement == null) {
360             return null;
361         }
362         return classStatement.getModifierList();
363     }
364 
hasModifierProperty(@odifierConstant @onNls @otNull String name)365     @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) {
366         SmaliModifierList smaliModifierList = getModifierList();
367         return smaliModifierList != null && smaliModifierList.hasModifierProperty(name);
368     }
369 
getAnnotations()370     @NotNull @Override public SmaliAnnotation[] getAnnotations() {
371         return getStubOrPsiChildren(SmaliElementTypes.ANNOTATION, new SmaliAnnotation[0]);
372     }
373 
getApplicableAnnotations()374     @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
375         return getAnnotations();
376     }
377 
findAnnotation(@otNull @onNls String qualifiedName)378     @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
379         for (SmaliAnnotation annotation: getAnnotations()) {
380             if (qualifiedName.equals(annotation.getQualifiedName())) {
381                 return annotation;
382             }
383         }
384         return null;
385     }
386 
addAnnotation(@otNull @onNls String qualifiedName)387     @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
388         // TODO: implement this
389         return null;
390     }
391 
getLocationForSourcePosition(@onnull ReferenceType type, @Nonnull SourcePosition position)392     @Nullable public Location getLocationForSourcePosition(@Nonnull ReferenceType type,
393                                                            @Nonnull SourcePosition position) {
394 
395         SmaliMethod[] smaliMethods = findChildrenByType(SmaliElementTypes.METHOD, SmaliMethod.class);
396 
397         for (SmaliMethod smaliMethod: smaliMethods) {
398             //TODO: check the start line+end line of the method
399             int offset = smaliMethod.getOffsetForLine(position.getLine());
400             if (offset != -1) {
401                 List<Method> methods = type.methodsByName(smaliMethod.getName(),
402                         smaliMethod.getMethodPrototype().getText());
403                 if (methods.size() > 0) {
404                     return methods.get(0).locationOfCodeIndex(offset/2);
405                 }
406             }
407         }
408         return null;
409     }
410 
411     @Override
processDeclarations(@otNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place)412     public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state,
413                                        PsiElement lastParent, @NotNull PsiElement place) {
414         return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place,
415                 PsiUtil.getLanguageLevel(place), false);
416     }
417 
getElementIcon(@conFlags int flags)418     @Nullable @Override protected Icon getElementIcon(@IconFlags int flags) {
419         return SmaliIcons.SmaliIcon;
420     }
421 }