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