1 /* 2 * Copyright 2013, 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.analysis; 32 33 import com.google.common.collect.ImmutableSet; 34 import com.google.common.collect.Lists; 35 import com.android.tools.smali.dexlib2.Opcodes; 36 import com.android.tools.smali.dexlib2.iface.ClassDef; 37 import com.android.tools.smali.dexlib2.immutable.ImmutableDexFile; 38 import org.junit.Assert; 39 import org.junit.Test; 40 41 import java.io.IOException; 42 43 public class CommonSuperclassTest { 44 // object tree: 45 // object 46 // one 47 // onetwo 48 // onetwothree 49 // onethree 50 // five (undefined class) 51 // fivetwo 52 // fivetwothree 53 // fivethree 54 55 private final ClassPath oldClassPath; 56 private final ClassPath newClassPath; 57 58 CommonSuperclassTest()59 public CommonSuperclassTest() throws IOException { 60 ImmutableSet<ClassDef> classes = ImmutableSet.of( 61 TestUtils.makeClassDef("Ljava/lang/Object;", null), 62 TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"), 63 TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"), 64 TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"), 65 TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"), 66 TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"), 67 TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"), 68 TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"), 69 TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"), 70 TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"), 71 TestUtils.makeInterfaceDef("Ljava/io/Serializable;"), 72 73 // basic class and interface 74 TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"), 75 TestUtils.makeInterfaceDef("Liface/iface1;"), 76 77 // a more complex interface tree 78 TestUtils.makeInterfaceDef("Liface/base1;"), 79 // implements undefined interface 80 TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"), 81 // this implements sub1, so that its interfaces can't be fully resolved either 82 TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"), 83 TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"), 84 TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"), 85 TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"), 86 TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"), 87 TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;", 88 "Liface/base;"), 89 TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;", 90 "Liface/sub4;"), 91 TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"), 92 TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;", 93 "Liface/sub2;", "Liface/sub3;", "Liface/sub4;")); 94 95 oldClassPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), classes))); 96 newClassPath = new ClassPath(Lists.newArrayList(new DexClassProvider( 97 new ImmutableDexFile(Opcodes.forArtVersion(72), classes))), true, 72); 98 } 99 superclassTest(ClassPath classPath, String commonSuperclass, String type1, String type2)100 public void superclassTest(ClassPath classPath, String commonSuperclass, 101 String type1, String type2) { 102 TypeProto commonSuperclassProto = classPath.getClass(commonSuperclass); 103 TypeProto type1Proto = classPath.getClass(type1); 104 TypeProto type2Proto = classPath.getClass(type2); 105 106 Assert.assertSame(commonSuperclassProto, type1Proto.getCommonSuperclass(type2Proto)); 107 Assert.assertSame(commonSuperclassProto, type2Proto.getCommonSuperclass(type1Proto)); 108 } 109 superclassTest(String commonSuperclass, String type1, String type2)110 public void superclassTest(String commonSuperclass, String type1, String type2) { 111 superclassTest(oldClassPath, commonSuperclass, type1, type2); 112 superclassTest(newClassPath, commonSuperclass, type1, type2); 113 } 114 115 @Test testGetCommonSuperclass()116 public void testGetCommonSuperclass() throws IOException { 117 String object = "Ljava/lang/Object;"; 118 String unknown = "Ujava/lang/Object;"; 119 String one = "Ltest/one;"; 120 String two = "Ltest/two;"; 121 String onetwo = "Ltest/onetwo;"; 122 String onetwothree = "Ltest/onetwothree;"; 123 String onethree = "Ltest/onethree;"; 124 String five = "Ltest/five;"; 125 String fivetwo = "Ltest/fivetwo;"; 126 String fivetwothree = "Ltest/fivetwothree;"; 127 String fivethree = "Ltest/fivethree;"; 128 129 // same object 130 superclassTest(object, object, object); 131 superclassTest(unknown, unknown, unknown); 132 superclassTest(one, one, one); 133 superclassTest(onetwo, onetwo, onetwo); 134 superclassTest(onetwothree, onetwothree, onetwothree); 135 superclassTest(onethree, onethree, onethree); 136 superclassTest(five, five, five); 137 superclassTest(fivetwo, fivetwo, fivetwo); 138 superclassTest(fivetwothree, fivetwothree, fivetwothree); 139 superclassTest(fivethree, fivethree, fivethree); 140 141 // same value, but different object 142 Assert.assertEquals( 143 onetwo, 144 oldClassPath.getClass(onetwo).getCommonSuperclass(new ClassProto(oldClassPath, onetwo)).getType()); 145 146 Assert.assertEquals( 147 onetwo, 148 newClassPath.getClass(onetwo).getCommonSuperclass(new ClassProto(newClassPath, onetwo)).getType()); 149 150 // other object is superclass 151 superclassTest(object, object, one); 152 153 // other object is superclass two levels up 154 superclassTest(object, object, onetwo); 155 156 // unknown and non-object class 157 superclassTest(unknown, one, unknown); 158 159 // unknown and object class 160 superclassTest(object, object, unknown); 161 162 // siblings 163 superclassTest(one, onetwo, onethree); 164 165 // nephew 166 superclassTest(one, onethree, onetwothree); 167 168 // unrelated 169 superclassTest(object, one, two); 170 171 // undefined superclass and object 172 superclassTest(object, fivetwo, object); 173 174 // undefined class and unrelated type 175 superclassTest(unknown, one, five); 176 177 // undefined superclass and unrelated type 178 superclassTest(unknown, one, fivetwo); 179 180 // undefined ancestor and unrelated type 181 superclassTest(unknown, one, fivetwothree); 182 183 // undefined class and direct subclass 184 superclassTest(five, five, fivetwo); 185 186 // undefined class and descendent 187 superclassTest(five, five, fivetwothree); 188 189 // undefined superclass and direct subclass 190 superclassTest(fivetwo, fivetwo, fivetwothree); 191 192 // siblings with undefined superclass 193 superclassTest(five, fivetwo, fivethree); 194 195 // undefined superclass and nephew 196 superclassTest(five, fivethree, fivetwothree); 197 } 198 199 @Test testGetCommonSuperclass_interfaces()200 public void testGetCommonSuperclass_interfaces() { 201 String classiface1 = "Liface/classiface1;"; 202 String iface1 = "Liface/iface1;"; 203 String base1 = "Liface/base1;"; 204 String base2 = "Liface/base2;"; 205 String sub1 = "Liface/sub1;"; 206 String sub2 = "Liface/sub2;"; 207 String sub3 = "Liface/sub3;"; 208 String sub4 = "Liface/sub4;"; 209 String classsub1 = "Liface/classsub1;"; 210 String classsub2 = "Liface/classsub2;"; 211 String classsub3 = "Liface/classsub3;"; 212 String classsub4 = "Liface/classsub4;"; 213 String classsubsub4 = "Liface/classsubsub4;"; 214 String classsub1234 = "Liface/classsub1234;"; 215 String object = "Ljava/lang/Object;"; 216 String unknown = "Ujava/lang/Object;"; 217 218 superclassTest(iface1, classiface1, iface1); 219 220 superclassTest(base1, base1, base1); 221 superclassTest(base1, base1, sub1); 222 superclassTest(base1, base1, classsub1); 223 superclassTest(base1, base1, sub2); 224 superclassTest(base1, base1, classsub2); 225 superclassTest(base1, base1, sub3); 226 superclassTest(base1, base1, classsub3); 227 superclassTest(base1, base1, sub4); 228 superclassTest(base1, base1, classsub4); 229 superclassTest(base1, base1, classsubsub4); 230 superclassTest(base1, base1, classsub1234); 231 232 superclassTest(object, sub3, iface1); 233 superclassTest(unknown, sub2, iface1); 234 superclassTest(unknown, sub1, iface1); 235 236 superclassTest(base2, base2, sub1); 237 superclassTest(base2, base2, classsub1); 238 superclassTest(base2, base2, sub2); 239 superclassTest(base2, base2, classsub2); 240 superclassTest(base2, base2, classsub1234); 241 242 superclassTest(unknown, iface1, classsub1234); 243 244 superclassTest(sub1, sub1, classsub1); 245 246 superclassTest(sub2, sub2, classsub2); 247 superclassTest(sub1, sub1, classsub2); 248 249 superclassTest(sub3, sub3, classsub3); 250 251 superclassTest(sub4, sub4, classsub4); 252 superclassTest(sub3, sub3, classsub4); 253 superclassTest(object, sub2, classsub4); 254 superclassTest(object, sub1, classsub4); 255 256 superclassTest(sub1, sub2, sub1); 257 258 superclassTest(sub1, sub1, classsub1234); 259 superclassTest(sub2, sub2, classsub1234); 260 superclassTest(sub3, sub3, classsub1234); 261 superclassTest(sub4, sub4, classsub1234); 262 263 superclassTest(unknown, sub3, classsub1); 264 superclassTest(unknown, sub4, classsub1); 265 superclassTest(unknown, sub3, classsub2); 266 superclassTest(unknown, sub4, classsub2); 267 268 superclassTest(unknown, sub4, base2); 269 superclassTest(unknown, classsub4, base2); 270 } 271 272 @Test testGetCommonSuperclass_arrays()273 public void testGetCommonSuperclass_arrays() throws IOException { 274 String object = "Ljava/lang/Object;"; 275 String one = "Ltest/one;"; 276 String unknown = "Ujava/lang/Object;"; 277 278 String cloneable = "Ljava/lang/Cloneable;"; 279 String serializable = "Ljava/io/Serializable;"; 280 281 String object1 = "[Ljava/lang/Object;"; 282 String one1 = "[Ltest/one;"; 283 String one2 = "[[Ltest/one;"; 284 String two1 = "[Ltest/two;"; 285 String onetwo1 = "[Ltest/onetwo;"; 286 String onetwo2 = "[[Ltest/onetwo;"; 287 String onethree1 = "[Ltest/onethree;"; 288 String onethree2 = "[[Ltest/onethree;"; 289 String five = "Ltest/five;"; 290 String five1 = "[Ltest/five;"; 291 String unknown1 = "[Ujava/lang/Object;"; 292 293 String int1 = "[I"; 294 String int2 = "[[I"; 295 String float1 = "[F"; 296 297 superclassTest(one1, one1, one1); 298 superclassTest(object1, object1, one1); 299 superclassTest(one1, onetwo1, onethree1); 300 superclassTest(one1, one1, onethree1); 301 superclassTest(object1, one1, two1); 302 303 superclassTest(one2, one2, one2); 304 superclassTest(one2, one2, onetwo2); 305 superclassTest(one2, onetwo2, onethree2); 306 superclassTest(object1, one1, one2); 307 superclassTest(object1, two1, one2); 308 309 superclassTest(unknown1, five1, one1); 310 superclassTest(object1, five1, one2); 311 312 superclassTest(unknown1, one1, unknown1); 313 314 superclassTest(object, one1, one); 315 superclassTest(object, object1, one); 316 superclassTest(object, onetwo1, one); 317 superclassTest(object, five1, one); 318 superclassTest(object, one2, one); 319 320 superclassTest(object, one1, unknown); 321 superclassTest(object, unknown1, unknown); 322 323 superclassTest(cloneable, one1, cloneable); 324 superclassTest(serializable, one1, serializable); 325 326 superclassTest(object, one1, five); 327 328 superclassTest(int1, int1, int1); 329 superclassTest(object, int1, float1); 330 superclassTest(object, int1, int2); 331 } 332 } 333