Home | History | Annotate | Download | only in dexlib
      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.dexlib;
     33 
     34 import com.google.common.base.Function;
     35 import com.google.common.collect.ImmutableList;
     36 import com.google.common.collect.ImmutableSet;
     37 import com.google.common.collect.Lists;
     38 import com.intellij.psi.PsiClass;
     39 import com.intellij.psi.PsiMethod;
     40 import com.intellij.psi.PsiModifierList;
     41 import com.intellij.psi.PsiParameter;
     42 import org.jetbrains.annotations.NotNull;
     43 import org.jetbrains.annotations.Nullable;
     44 import org.jf.dexlib2.AccessFlags;
     45 import org.jf.dexlib2.base.reference.BaseMethodReference;
     46 import org.jf.dexlib2.iface.*;
     47 import org.jf.dexlib2.iface.debug.DebugItem;
     48 import org.jf.dexlib2.iface.instruction.Instruction;
     49 import org.jf.smalidea.dexlib.instruction.SmalideaInstruction;
     50 import org.jf.smalidea.psi.impl.SmaliCatchStatement;
     51 import org.jf.smalidea.psi.impl.SmaliInstruction;
     52 import org.jf.smalidea.psi.impl.SmaliMethod;
     53 import org.jf.smalidea.util.NameUtils;
     54 
     55 import javax.annotation.Nonnull;
     56 import java.util.Arrays;
     57 import java.util.List;
     58 import java.util.Set;
     59 
     60 public class SmalideaMethod extends BaseMethodReference implements Method {
     61     private final PsiMethod psiMethod;
     62 
     63     public SmalideaMethod(@NotNull PsiMethod psiMethod) {
     64         this.psiMethod = psiMethod;
     65     }
     66 
     67     @Nonnull @Override public String getDefiningClass() {
     68         PsiClass cls = psiMethod.getContainingClass();
     69         assert cls != null;
     70         return NameUtils.javaToSmaliType(cls);
     71     }
     72 
     73     @Nonnull @Override public List<? extends MethodParameter> getParameters() {
     74         PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
     75 
     76         return Lists.transform(Arrays.asList(parameters), new Function<PsiParameter, MethodParameter>() {
     77             @Nullable @Override
     78             public MethodParameter apply(@Nullable PsiParameter psiParameter) {
     79                 if (psiParameter == null) {
     80                     return null;
     81                 }
     82                 return new SmalideaMethodParameter(psiParameter);
     83             }
     84         });
     85     }
     86 
     87     @Override public int getAccessFlags() {
     88         if (psiMethod instanceof SmaliMethod) {
     89             return ((SmaliMethod)psiMethod).getModifierList().getAccessFlags();
     90         } else {
     91             int flags = 0;
     92             PsiModifierList modifierList = psiMethod.getModifierList();
     93             if (modifierList.hasModifierProperty("public")) {
     94                 flags |= AccessFlags.PUBLIC.getValue();
     95             } else if (modifierList.hasModifierProperty("protected")) {
     96                 flags |= AccessFlags.PROTECTED.getValue();
     97             } else if (modifierList.hasModifierProperty("private")) {
     98                 flags |= AccessFlags.PRIVATE.getValue();
     99             }
    100 
    101             if (modifierList.hasModifierProperty("static")) {
    102                 flags |= AccessFlags.STATIC.getValue();
    103             }
    104 
    105             if (modifierList.hasModifierProperty("final")) {
    106                 flags |= AccessFlags.FINAL.getValue();
    107             }
    108 
    109             boolean isNative = false;
    110             if (modifierList.hasModifierProperty("native")) {
    111                 flags |= AccessFlags.NATIVE.getValue();
    112                 isNative = true;
    113             }
    114 
    115             if (modifierList.hasModifierProperty("synchronized")) {
    116                 if (isNative) {
    117                     flags |= AccessFlags.SYNCHRONIZED.getValue();
    118                 } else {
    119                     flags |= AccessFlags.DECLARED_SYNCHRONIZED.getValue();
    120                 }
    121             }
    122 
    123             if (psiMethod.isVarArgs()) {
    124                 flags |= AccessFlags.VARARGS.getValue();
    125             }
    126 
    127             if (modifierList.hasModifierProperty("abstract")) {
    128                 flags |= AccessFlags.ABSTRACT.getValue();
    129             }
    130 
    131             if (modifierList.hasModifierProperty("strictfp")) {
    132                 flags |= AccessFlags.STRICTFP.getValue();
    133             }
    134 
    135             if (psiMethod.isConstructor()) {
    136                 flags |= AccessFlags.CONSTRUCTOR.getValue();
    137             }
    138             return flags;
    139         }
    140     }
    141 
    142     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
    143         // TODO: implement this
    144         return ImmutableSet.of();
    145     }
    146 
    147     @Nullable @Override public MethodImplementation getImplementation() {
    148         if (psiMethod instanceof SmaliMethod) {
    149             final SmaliMethod smaliMethod = (SmaliMethod)this.psiMethod;
    150 
    151             List<SmaliInstruction> instructions = smaliMethod.getInstructions();
    152             if (instructions.size() == 0) {
    153                 return null;
    154             }
    155 
    156             // TODO: cache this?
    157             return new MethodImplementation() {
    158                 @Override public int getRegisterCount() {
    159                     return smaliMethod.getRegisterCount();
    160                 }
    161 
    162                 @Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
    163                     return Lists.transform(smaliMethod.getInstructions(),
    164                             new Function<SmaliInstruction, Instruction>() {
    165                                 @Override
    166                                 public Instruction apply(SmaliInstruction smaliInstruction) {
    167                                     return SmalideaInstruction.of(smaliInstruction);
    168                                 }
    169                             });
    170                 }
    171 
    172                 @Nonnull @Override public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
    173                     return Lists.transform(smaliMethod.getCatchStatements(),
    174                             new Function<SmaliCatchStatement, TryBlock<? extends ExceptionHandler>>() {
    175                                 @Override
    176                                 public TryBlock<? extends ExceptionHandler> apply(
    177                                         SmaliCatchStatement smaliCatchStatement) {
    178                                     assert smaliCatchStatement != null;
    179                                     return new SmalideaTryBlock(smaliCatchStatement);
    180                                 }
    181                             });
    182                 }
    183 
    184                 @Nonnull @Override public Iterable<? extends DebugItem> getDebugItems() {
    185                     // TODO: implement this
    186                     return ImmutableList.of();
    187                 }
    188             };
    189         }
    190         return null;
    191     }
    192 
    193     @Nonnull @Override public String getName() {
    194         return psiMethod.getName();
    195     }
    196 
    197     @Nonnull @Override public List<? extends CharSequence> getParameterTypes() {
    198         PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
    199 
    200         return Lists.transform(Arrays.asList(parameters), new Function<PsiParameter, CharSequence>() {
    201             @Nullable @Override
    202             public CharSequence apply(@Nullable PsiParameter psiParameter) {
    203                 if (psiParameter == null) {
    204                     return null;
    205                 }
    206                 return psiParameter.getText();
    207             }
    208         });
    209     }
    210 
    211     @Nonnull @Override public String getReturnType() {
    212         return psiMethod.getReturnTypeElement().getText();
    213     }
    214 }
    215