| /* |
| * Copyright 2014, Google Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package org.jf.smalidea.psi.impl; |
| |
| import com.google.common.collect.Lists; |
| import com.intellij.debugger.SourcePosition; |
| import com.intellij.lang.ASTNode; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.psi.*; |
| import com.intellij.psi.PsiModifier.ModifierConstant; |
| import com.intellij.psi.impl.PsiClassImplUtil; |
| import com.intellij.psi.impl.PsiImplUtil; |
| import com.intellij.psi.javadoc.PsiDocComment; |
| import com.intellij.psi.scope.PsiScopeProcessor; |
| import com.intellij.psi.util.PsiUtil; |
| import com.intellij.util.IncorrectOperationException; |
| import com.sun.jdi.Location; |
| import com.sun.jdi.Method; |
| import com.sun.jdi.ReferenceType; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jf.smalidea.SmaliIcons; |
| import org.jf.smalidea.psi.SmaliElementTypes; |
| import org.jf.smalidea.psi.iface.SmaliModifierListOwner; |
| import org.jf.smalidea.psi.stub.SmaliClassStub; |
| |
| import javax.annotation.Nonnull; |
| import javax.swing.*; |
| import java.util.Collection; |
| import java.util.List; |
| |
| public class SmaliClass extends SmaliStubBasedPsiElement<SmaliClassStub> implements PsiClass, SmaliModifierListOwner { |
| public SmaliClass(@NotNull SmaliClassStub stub) { |
| super(stub, SmaliElementTypes.CLASS); |
| } |
| |
| public SmaliClass(@NotNull ASTNode node) { |
| super(node); |
| } |
| |
| @Nonnull |
| @Override |
| public String getName() { |
| String name = getQualifiedName(); |
| if (name == null) { |
| return ""; |
| } |
| int lastDot = name.lastIndexOf('.'); |
| if (lastDot < 0) { |
| return name; |
| } |
| return name.substring(lastDot+1); |
| } |
| |
| @Nullable @Override public String getQualifiedName() { |
| SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT); |
| if (classStatement == null) { |
| return null; |
| } |
| return classStatement.getQualifiedName(); |
| } |
| |
| @NotNull public String getPackageName() { |
| String name = getQualifiedName(); |
| if (name == null) { |
| return ""; |
| } |
| int lastDot = name.lastIndexOf('.'); |
| if (lastDot < 0) { |
| return ""; |
| } |
| return name.substring(0, lastDot); |
| } |
| |
| @Override public boolean hasTypeParameters() { |
| // TODO: implement generics |
| return false; |
| } |
| |
| @Override public boolean isInterface() { |
| return hasModifierProperty("interface"); |
| } |
| |
| @Override public boolean isAnnotationType() { |
| return hasModifierProperty("annotation"); |
| } |
| |
| @Override public boolean isEnum() { |
| return hasModifierProperty("enum"); |
| } |
| |
| @Nullable public SmaliSuperStatement getSuperStatement() { |
| return findChildByClass(SmaliSuperStatement.class); |
| } |
| |
| @NotNull @Override public SmaliExtendsList getExtendsList() { |
| return getRequiredStubOrPsiChild(SmaliElementTypes.EXTENDS_LIST); |
| } |
| |
| @NotNull public SmaliImplementsStatement[] getImplementsStatements() { |
| return findChildrenByClass(SmaliImplementsStatement.class); |
| } |
| |
| @NotNull @Override public SmaliImplementsList getImplementsList() { |
| return getRequiredStubOrPsiChild(SmaliElementTypes.IMPLEMENTS_LIST); |
| } |
| |
| @NotNull @Override public SmaliClassType[] getExtendsListTypes() { |
| return getExtendsList().getReferencedTypes(); |
| } |
| |
| @NotNull @Override public SmaliClassType[] getImplementsListTypes() { |
| return getImplementsList().getReferencedTypes(); |
| } |
| |
| @Nullable @Override public PsiClass getSuperClass() { |
| return PsiClassImplUtil.getSuperClass(this); |
| } |
| |
| @Override public PsiClass[] getInterfaces() { |
| return PsiClassImplUtil.getInterfaces(this); |
| } |
| |
| @NotNull @Override public PsiClass[] getSupers() { |
| return PsiClassImplUtil.getSupers(this); |
| } |
| |
| @NotNull @Override public PsiClassType[] getSuperTypes() { |
| return PsiClassImplUtil.getSuperTypes(this); |
| } |
| |
| @NotNull @Override public SmaliField[] getFields() { |
| SmaliField[] fields = getStubOrPsiChildren(SmaliElementTypes.FIELD, new SmaliField[0]); |
| List<SmaliField> filteredFields = null; |
| for (int i=fields.length-1; i>=0; i--) { |
| SmaliField field = fields[i]; |
| if (field.getName() == null) { |
| if (filteredFields == null) { |
| filteredFields = Lists.newArrayList(fields); |
| } |
| filteredFields.remove(i); |
| } |
| } |
| if (filteredFields != null) { |
| return filteredFields.toArray(new SmaliField[filteredFields.size()]); |
| } |
| return fields; |
| } |
| |
| @NotNull @Override public SmaliMethod[] getMethods() { |
| return getStubOrPsiChildren(SmaliElementTypes.METHOD, new SmaliMethod[0]); |
| } |
| |
| @NotNull @Override public PsiMethod[] getConstructors() { |
| return PsiImplUtil.getConstructors(this); |
| } |
| |
| @NotNull @Override public PsiClass[] getInnerClasses() { |
| return new PsiClass[0]; |
| } |
| |
| @NotNull @Override public PsiClassInitializer[] getInitializers() { |
| // TODO: do we need to return the <clinit> method here? |
| return new PsiClassInitializer[0]; |
| } |
| |
| @NotNull @Override public PsiField[] getAllFields() { |
| return PsiClassImplUtil.getAllFields(this); |
| } |
| |
| @NotNull @Override public PsiMethod[] getAllMethods() { |
| return PsiClassImplUtil.getAllMethods(this); |
| } |
| |
| @NotNull @Override public PsiClass[] getAllInnerClasses() { |
| return new PsiClass[0]; |
| } |
| |
| @Nullable @Override public PsiField findFieldByName(@NonNls String name, boolean checkBases) { |
| return PsiClassImplUtil.findFieldByName(this, name, checkBases); |
| } |
| |
| @Nullable @Override public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) { |
| return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases); |
| } |
| |
| @NotNull @Override public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) { |
| return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases); |
| } |
| |
| @NotNull @Override public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) { |
| return PsiClassImplUtil.findMethodsByName(this, name, checkBases); |
| } |
| |
| @NotNull @Override |
| public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) { |
| return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases); |
| } |
| |
| @NotNull @Override public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() { |
| return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD); |
| } |
| |
| @Nullable @Override public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { |
| return null; |
| } |
| |
| @Nullable @Override public PsiElement getLBrace() { |
| return null; |
| } |
| |
| @Nullable @Override public PsiElement getRBrace() { |
| return null; |
| } |
| |
| @Nullable @Override public PsiIdentifier getNameIdentifier() { |
| return null; |
| } |
| |
| @Override public PsiElement getScope() { |
| return null; |
| } |
| |
| @Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) { |
| return false; |
| } |
| |
| @Override public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) { |
| return false; |
| } |
| |
| @Nullable @Override public PsiClass getContainingClass() { |
| return null; |
| } |
| |
| @NotNull @Override public Collection<HierarchicalMethodSignature> getVisibleSignatures() { |
| return null; |
| } |
| |
| @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { |
| return null; |
| } |
| |
| @Nullable @Override public PsiDocComment getDocComment() { |
| return null; |
| } |
| |
| @Override public boolean isDeprecated() { |
| return false; |
| } |
| |
| @Nullable @Override public PsiTypeParameterList getTypeParameterList() { |
| return null; |
| } |
| |
| @NotNull @Override public PsiTypeParameter[] getTypeParameters() { |
| return new PsiTypeParameter[0]; |
| } |
| |
| @Nullable @Override public SmaliModifierList getModifierList() { |
| SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT); |
| if (classStatement == null) { |
| return null; |
| } |
| return classStatement.getModifierList(); |
| } |
| |
| @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) { |
| SmaliModifierList smaliModifierList = getModifierList(); |
| return smaliModifierList != null && smaliModifierList.hasModifierProperty(name); |
| } |
| |
| @NotNull @Override public SmaliAnnotation[] getAnnotations() { |
| return getStubOrPsiChildren(SmaliElementTypes.ANNOTATION, new SmaliAnnotation[0]); |
| } |
| |
| @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() { |
| return getAnnotations(); |
| } |
| |
| @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) { |
| for (SmaliAnnotation annotation: getAnnotations()) { |
| if (qualifiedName.equals(annotation.getQualifiedName())) { |
| return annotation; |
| } |
| } |
| return null; |
| } |
| |
| @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) { |
| // TODO: implement this |
| return null; |
| } |
| |
| @Nullable public Location getLocationForSourcePosition(@Nonnull ReferenceType type, |
| @Nonnull SourcePosition position) { |
| |
| SmaliMethod[] smaliMethods = findChildrenByType(SmaliElementTypes.METHOD, SmaliMethod.class); |
| |
| for (SmaliMethod smaliMethod: smaliMethods) { |
| //TODO: check the start line+end line of the method |
| int offset = smaliMethod.getOffsetForLine(position.getLine()); |
| if (offset != -1) { |
| List<Method> methods = type.methodsByName(smaliMethod.getName(), |
| smaliMethod.getMethodPrototype().getText()); |
| if (methods.size() > 0) { |
| return methods.get(0).locationOfCodeIndex(offset/2); |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, |
| PsiElement lastParent, @NotNull PsiElement place) { |
| return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, |
| PsiUtil.getLanguageLevel(place), false); |
| } |
| |
| @Nullable @Override protected Icon getElementIcon(@IconFlags int flags) { |
| return SmaliIcons.SmaliIcon; |
| } |
| } |