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