Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      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
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     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.
     15  */
     16 package android.signature.cts;
     17 
     18 import java.util.ArrayList;
     19 import java.util.List;
     20 import java.util.regex.Matcher;
     21 import java.util.regex.Pattern;
     22 import java.util.stream.Collectors;
     23 
     24 public class DexMethod extends DexMember {
     25   private final List<String> mParamTypeList;
     26 
     27   public DexMethod(String className, String name, String signature) {
     28       super(className, name, parseDexReturnType(signature));
     29       mParamTypeList = parseDexTypeList(signature);
     30   }
     31 
     32   public String getDexSignature() {
     33       return "(" + String.join("", mParamTypeList) + ")" + getDexType();
     34   }
     35 
     36   public List<String> getJavaParameterTypes() {
     37       return mParamTypeList.stream().map(DexMember::dexToJavaType).collect(Collectors.toList());
     38   }
     39 
     40   public boolean isConstructor() {
     41       return "<init>".equals(getName()) && "V".equals(getDexType());
     42   }
     43 
     44   public boolean isStaticConstructor() {
     45       return "<clinit>".equals(getName()) && "V".equals(getDexType());
     46   }
     47 
     48   @Override
     49   public String toString() {
     50       return getJavaType() + " " + getJavaClassName() + "." + getName()
     51               + "(" + String.join(", ", getJavaParameterTypes()) + ")";
     52   }
     53 
     54   private static Matcher matchSignature(String signature) {
     55       Matcher m = Pattern.compile("^\\((.*)\\)(.*)$").matcher(signature);
     56       if (!m.matches()) {
     57           throw new RuntimeException("Could not parse method signature: " + signature);
     58       }
     59       return m;
     60   }
     61 
     62   private static String parseDexReturnType(String signature) {
     63       return matchSignature(signature).group(2);
     64   }
     65 
     66   private static List<String> parseDexTypeList(String signature) {
     67       String typeSequence = matchSignature(signature).group(1);
     68       List<String> list = new ArrayList<String>();
     69       while (!typeSequence.isEmpty()) {
     70           String type = firstDexTypeFromList(typeSequence);
     71           list.add(type);
     72           typeSequence = typeSequence.substring(type.length());
     73       }
     74       return list;
     75   }
     76 
     77   /**
     78    * Returns the first dex type in `typeList` or throws a ParserException
     79    * if a dex type is not recognized. The input is not changed.
     80    */
     81   private static String firstDexTypeFromList(String typeList) {
     82       String dexDimension = "";
     83       while (typeList.startsWith("[")) {
     84           dexDimension += "[";
     85           typeList = typeList.substring(1);
     86       }
     87 
     88       String type = null;
     89       if (typeList.startsWith("V")
     90               || typeList.startsWith("Z")
     91               || typeList.startsWith("B")
     92               || typeList.startsWith("C")
     93               || typeList.startsWith("S")
     94               || typeList.startsWith("I")
     95               || typeList.startsWith("J")
     96               || typeList.startsWith("F")
     97               || typeList.startsWith("D")) {
     98           type = typeList.substring(0, 1);
     99       } else if (typeList.startsWith("L") && typeList.indexOf(";") > 0) {
    100           type = typeList.substring(0, typeList.indexOf(";") + 1);
    101       } else {
    102           throw new RuntimeException("Unexpected dex type in \"" + typeList + "\"");
    103       }
    104 
    105       return dexDimension + type;
    106   }
    107 }
    108