1 /* 2 * Copyright 2012, Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google LLC nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 package com.android.tools.smali.dexlib2.util; 32 33 import com.android.tools.smali.dexlib2.AccessFlags; 34 import com.android.tools.smali.dexlib2.iface.Method; 35 import com.android.tools.smali.dexlib2.iface.reference.MethodReference; 36 import com.android.tools.smali.util.CharSequenceUtils; 37 38 import javax.annotation.Nonnull; 39 import javax.annotation.Nullable; 40 import java.util.Collection; 41 import java.util.function.Predicate; 42 43 public final class MethodUtil { 44 private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() | 45 AccessFlags.CONSTRUCTOR.getValue(); 46 47 public static Predicate<Method> METHOD_IS_DIRECT = new Predicate<Method>() { 48 @Override public boolean test(@Nullable Method input) { 49 return input != null && isDirect(input); 50 } 51 }; 52 53 public static Predicate<Method> METHOD_IS_VIRTUAL = new Predicate<Method>() { 54 @Override public boolean test(@Nullable Method input) { 55 return input != null && !isDirect(input); 56 } 57 }; 58 isDirect(@onnull Method method)59 public static boolean isDirect(@Nonnull Method method) { 60 return (method.getAccessFlags() & directMask) != 0; 61 } 62 isStatic(@onnull Method method)63 public static boolean isStatic(@Nonnull Method method) { 64 return AccessFlags.STATIC.isSet(method.getAccessFlags()); 65 } 66 isConstructor(@onnull MethodReference methodReference)67 public static boolean isConstructor(@Nonnull MethodReference methodReference) { 68 return methodReference.getName().equals("<init>"); 69 } 70 isPackagePrivate(@onnull Method method)71 public static boolean isPackagePrivate(@Nonnull Method method) { 72 return (method.getAccessFlags() & (AccessFlags.PRIVATE.getValue() | 73 AccessFlags.PROTECTED.getValue() | 74 AccessFlags.PUBLIC.getValue())) == 0; 75 } 76 getParameterRegisterCount(@onnull Method method)77 public static int getParameterRegisterCount(@Nonnull Method method) { 78 return getParameterRegisterCount(method, MethodUtil.isStatic(method)); 79 } 80 getParameterRegisterCount(@onnull MethodReference methodRef, boolean isStatic)81 public static int getParameterRegisterCount(@Nonnull MethodReference methodRef, boolean isStatic) { 82 return getParameterRegisterCount(methodRef.getParameterTypes(), isStatic); 83 } 84 getParameterRegisterCount(@onnull Collection<? extends CharSequence> parameterTypes, boolean isStatic)85 public static int getParameterRegisterCount(@Nonnull Collection<? extends CharSequence> parameterTypes, 86 boolean isStatic) { 87 int regCount = 0; 88 for (CharSequence paramType: parameterTypes) { 89 int firstChar = paramType.charAt(0); 90 if (firstChar == 'J' || firstChar == 'D') { 91 regCount += 2; 92 } else { 93 regCount++; 94 } 95 } 96 if (!isStatic) { 97 regCount++; 98 } 99 return regCount; 100 } 101 getShortyType(CharSequence type)102 private static char getShortyType(CharSequence type) { 103 if (type.length() > 1) { 104 return 'L'; 105 } 106 return type.charAt(0); 107 } 108 getShorty(Collection<? extends CharSequence> params, String returnType)109 public static String getShorty(Collection<? extends CharSequence> params, String returnType) { 110 StringBuilder sb = new StringBuilder(params.size() + 1); 111 sb.append(getShortyType(returnType)); 112 for (CharSequence typeRef: params) { 113 sb.append(getShortyType(typeRef)); 114 } 115 return sb.toString(); 116 } 117 methodSignaturesMatch(@onnull MethodReference a, @Nonnull MethodReference b)118 public static boolean methodSignaturesMatch(@Nonnull MethodReference a, @Nonnull MethodReference b) { 119 return (a.getName().equals(b.getName()) && 120 a.getReturnType().equals(b.getReturnType()) && 121 CharSequenceUtils.listEquals(a.getParameterTypes(), b.getParameterTypes())); 122 } 123 MethodUtil()124 private MethodUtil() {} 125 } 126