xref: /aosp_15_r20/art/test/968-default-partial-compile-gen/util-src/generate_smali.py (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/python3
2*795d594fSAndroid Build Coastguard Worker#
3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project
4*795d594fSAndroid Build Coastguard Worker#
5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*795d594fSAndroid Build Coastguard Worker#
9*795d594fSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*795d594fSAndroid Build Coastguard Worker#
11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*795d594fSAndroid Build Coastguard Worker# limitations under the License.
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker"""
18*795d594fSAndroid Build Coastguard WorkerGenerate Smali test files for test 967.
19*795d594fSAndroid Build Coastguard Worker"""
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Workerimport os
22*795d594fSAndroid Build Coastguard Workerimport sys
23*795d594fSAndroid Build Coastguard Workerfrom pathlib import Path
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard WorkerBUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
26*795d594fSAndroid Build Coastguard Workerif BUILD_TOP is None:
27*795d594fSAndroid Build Coastguard Worker  print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
28*795d594fSAndroid Build Coastguard Worker  sys.exit(1)
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker# Allow us to import utils and mixins.
31*795d594fSAndroid Build Coastguard Workersys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python"))
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Workerfrom testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks
34*795d594fSAndroid Build Coastguard Workerimport testgen.mixins as mixins
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Workerfrom enum import Enum
37*795d594fSAndroid Build Coastguard Workerfrom functools import total_ordering
38*795d594fSAndroid Build Coastguard Workerimport itertools
39*795d594fSAndroid Build Coastguard Workerimport string
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker# The max depth the type tree can have.
42*795d594fSAndroid Build Coastguard WorkerMAX_IFACE_DEPTH = 3
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Workerclass MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
45*795d594fSAndroid Build Coastguard Worker  """
46*795d594fSAndroid Build Coastguard Worker  A Main.smali file containing the Main class and the main function. It will run
47*795d594fSAndroid Build Coastguard Worker  all the test functions we have.
48*795d594fSAndroid Build Coastguard Worker  """
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker  MAIN_CLASS_TEMPLATE = """{copyright}
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker.class public LMain;
53*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker# class Main {{
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V
58*795d594fSAndroid Build Coastguard Worker    .registers 1
59*795d594fSAndroid Build Coastguard Worker    invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
60*795d594fSAndroid Build Coastguard Worker    return-void
61*795d594fSAndroid Build Coastguard Worker.end method
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker{test_funcs}
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker{main_func}
66*795d594fSAndroid Build Coastguard Worker
67*795d594fSAndroid Build Coastguard Worker# }}
68*795d594fSAndroid Build Coastguard Worker"""
69*795d594fSAndroid Build Coastguard Worker
70*795d594fSAndroid Build Coastguard Worker  MAIN_FUNCTION_TEMPLATE = """
71*795d594fSAndroid Build Coastguard Worker#   public static void main(String[] args) {{
72*795d594fSAndroid Build Coastguard Worker.method public static main([Ljava/lang/String;)V
73*795d594fSAndroid Build Coastguard Worker    .locals 0
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker    {test_group_invoke}
76*795d594fSAndroid Build Coastguard Worker
77*795d594fSAndroid Build Coastguard Worker    return-void
78*795d594fSAndroid Build Coastguard Worker.end method
79*795d594fSAndroid Build Coastguard Worker#   }}
80*795d594fSAndroid Build Coastguard Worker"""
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker  TEST_GROUP_INVOKE_TEMPLATE = """
83*795d594fSAndroid Build Coastguard Worker#     {test_name}();
84*795d594fSAndroid Build Coastguard Worker    invoke-static {{}}, {test_name}()V
85*795d594fSAndroid Build Coastguard Worker"""
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker  def __init__(self):
88*795d594fSAndroid Build Coastguard Worker    """
89*795d594fSAndroid Build Coastguard Worker    Initialize this MainClass. We start out with no tests.
90*795d594fSAndroid Build Coastguard Worker    """
91*795d594fSAndroid Build Coastguard Worker    self.tests = set()
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
94*795d594fSAndroid Build Coastguard Worker    """
95*795d594fSAndroid Build Coastguard Worker    Get the expected output of this test.
96*795d594fSAndroid Build Coastguard Worker    """
97*795d594fSAndroid Build Coastguard Worker    all_tests = sorted(self.tests)
98*795d594fSAndroid Build Coastguard Worker    return filter_blanks("\n".join(a.get_expected() for a in all_tests))
99*795d594fSAndroid Build Coastguard Worker
100*795d594fSAndroid Build Coastguard Worker  def add_test(self, ty):
101*795d594fSAndroid Build Coastguard Worker    """
102*795d594fSAndroid Build Coastguard Worker    Add a test for the concrete type 'ty'
103*795d594fSAndroid Build Coastguard Worker    """
104*795d594fSAndroid Build Coastguard Worker    self.tests.add(Func(ty))
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker  def get_name(self):
107*795d594fSAndroid Build Coastguard Worker    """
108*795d594fSAndroid Build Coastguard Worker    Get the name of this class
109*795d594fSAndroid Build Coastguard Worker    """
110*795d594fSAndroid Build Coastguard Worker    return "Main"
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker  def __str__(self):
113*795d594fSAndroid Build Coastguard Worker    """
114*795d594fSAndroid Build Coastguard Worker    Print the MainClass smali code.
115*795d594fSAndroid Build Coastguard Worker    """
116*795d594fSAndroid Build Coastguard Worker    all_tests = sorted(self.tests)
117*795d594fSAndroid Build Coastguard Worker    test_invoke = ""
118*795d594fSAndroid Build Coastguard Worker    test_funcs = ""
119*795d594fSAndroid Build Coastguard Worker    for t in all_tests:
120*795d594fSAndroid Build Coastguard Worker      test_funcs += str(t)
121*795d594fSAndroid Build Coastguard Worker    for t in all_tests:
122*795d594fSAndroid Build Coastguard Worker      test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name())
123*795d594fSAndroid Build Coastguard Worker    main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke)
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker    return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"),
126*795d594fSAndroid Build Coastguard Worker                                           test_funcs = test_funcs,
127*795d594fSAndroid Build Coastguard Worker                                           main_func = main_func)
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Workerclass Func(mixins.Named, mixins.NameComparableMixin):
130*795d594fSAndroid Build Coastguard Worker  """
131*795d594fSAndroid Build Coastguard Worker  A function that tests the functionality of a concrete type. Should only be
132*795d594fSAndroid Build Coastguard Worker  constructed by MainClass.add_test.
133*795d594fSAndroid Build Coastguard Worker  """
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker  TEST_FUNCTION_TEMPLATE = """
136*795d594fSAndroid Build Coastguard Worker#   public static void {fname}() {{
137*795d594fSAndroid Build Coastguard Worker#     {farg} v = null;
138*795d594fSAndroid Build Coastguard Worker#     try {{
139*795d594fSAndroid Build Coastguard Worker#       v = new {farg}();
140*795d594fSAndroid Build Coastguard Worker#     }} catch (Throwable e) {{
141*795d594fSAndroid Build Coastguard Worker#       System.out.println("Unexpected error occurred which creating {farg} instance");
142*795d594fSAndroid Build Coastguard Worker#       e.printStackTrace(System.out);
143*795d594fSAndroid Build Coastguard Worker#       return;
144*795d594fSAndroid Build Coastguard Worker#     }}
145*795d594fSAndroid Build Coastguard Worker#     try {{
146*795d594fSAndroid Build Coastguard Worker#       System.out.printf("{tree} calls %s\\n", v.getName());
147*795d594fSAndroid Build Coastguard Worker#       return;
148*795d594fSAndroid Build Coastguard Worker#     }} catch (AbstractMethodError e) {{
149*795d594fSAndroid Build Coastguard Worker#       System.out.println("{tree} threw AbstractMethodError");
150*795d594fSAndroid Build Coastguard Worker#     }} catch (NoSuchMethodError e) {{
151*795d594fSAndroid Build Coastguard Worker#       System.out.println("{tree} threw NoSuchMethodError");
152*795d594fSAndroid Build Coastguard Worker#     }} catch (IncompatibleClassChangeError e) {{
153*795d594fSAndroid Build Coastguard Worker#       System.out.println("{tree} threw IncompatibleClassChangeError");
154*795d594fSAndroid Build Coastguard Worker#     }} catch (Throwable e) {{
155*795d594fSAndroid Build Coastguard Worker#       e.printStackTrace(System.out);
156*795d594fSAndroid Build Coastguard Worker#       return;
157*795d594fSAndroid Build Coastguard Worker#     }}
158*795d594fSAndroid Build Coastguard Worker#   }}
159*795d594fSAndroid Build Coastguard Worker.method public static {fname}()V
160*795d594fSAndroid Build Coastguard Worker    .locals 7
161*795d594fSAndroid Build Coastguard Worker    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker    :new_{fname}_try_start
164*795d594fSAndroid Build Coastguard Worker      new-instance v0, L{farg};
165*795d594fSAndroid Build Coastguard Worker      invoke-direct {{v0}}, L{farg};-><init>()V
166*795d594fSAndroid Build Coastguard Worker      goto :call_{fname}_try_start
167*795d594fSAndroid Build Coastguard Worker    :new_{fname}_try_end
168*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/Throwable; {{:new_{fname}_try_start .. :new_{fname}_try_end}} :new_error_{fname}_start
169*795d594fSAndroid Build Coastguard Worker    :new_error_{fname}_start
170*795d594fSAndroid Build Coastguard Worker      move-exception v6
171*795d594fSAndroid Build Coastguard Worker      const-string v5, "Unexpected error occurred which creating {farg} instance"
172*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
173*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
174*795d594fSAndroid Build Coastguard Worker      return-void
175*795d594fSAndroid Build Coastguard Worker    :call_{fname}_try_start
176*795d594fSAndroid Build Coastguard Worker      const/4 v1, 1
177*795d594fSAndroid Build Coastguard Worker      new-array v2,v1, [Ljava/lang/Object;
178*795d594fSAndroid Build Coastguard Worker      const/4 v1, 0
179*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0}}, L{farg};->getName()Ljava/lang/String;
180*795d594fSAndroid Build Coastguard Worker      move-result-object v3
181*795d594fSAndroid Build Coastguard Worker      aput-object v3,v2,v1
182*795d594fSAndroid Build Coastguard Worker
183*795d594fSAndroid Build Coastguard Worker      const-string v5, "{tree} calls %s\\n"
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5,v2}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
186*795d594fSAndroid Build Coastguard Worker      return-void
187*795d594fSAndroid Build Coastguard Worker    :call_{fname}_try_end
188*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/AbstractMethodError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :AME_{fname}_start
189*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/NoSuchMethodError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :NSME_{fname}_start
190*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/IncompatibleClassChangeError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :ICCE_{fname}_start
191*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/Throwable; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start
192*795d594fSAndroid Build Coastguard Worker    :AME_{fname}_start
193*795d594fSAndroid Build Coastguard Worker      const-string v5, "{tree} threw AbstractMethodError"
194*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
195*795d594fSAndroid Build Coastguard Worker      return-void
196*795d594fSAndroid Build Coastguard Worker    :NSME_{fname}_start
197*795d594fSAndroid Build Coastguard Worker      const-string v5, "{tree} threw NoSuchMethodError"
198*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
199*795d594fSAndroid Build Coastguard Worker      return-void
200*795d594fSAndroid Build Coastguard Worker    :ICCE_{fname}_start
201*795d594fSAndroid Build Coastguard Worker      const-string v5, "{tree} threw IncompatibleClassChangeError"
202*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
203*795d594fSAndroid Build Coastguard Worker      return-void
204*795d594fSAndroid Build Coastguard Worker    :error_{fname}_start
205*795d594fSAndroid Build Coastguard Worker      move-exception v6
206*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
207*795d594fSAndroid Build Coastguard Worker      return-void
208*795d594fSAndroid Build Coastguard Worker.end method
209*795d594fSAndroid Build Coastguard Worker"""
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker  NSME_RESULT_TEMPLATE = "{tree} threw NoSuchMethodError"
212*795d594fSAndroid Build Coastguard Worker  ICCE_RESULT_TEMPLATE = "{tree} threw IncompatibleClassChangeError"
213*795d594fSAndroid Build Coastguard Worker  AME_RESULT_TEMPLATE = "{tree} threw AbstractMethodError"
214*795d594fSAndroid Build Coastguard Worker  NORMAL_RESULT_TEMPLATE = "{tree} calls {result}"
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker  def __init__(self, farg):
217*795d594fSAndroid Build Coastguard Worker    """
218*795d594fSAndroid Build Coastguard Worker    Initialize a test function for the given argument
219*795d594fSAndroid Build Coastguard Worker    """
220*795d594fSAndroid Build Coastguard Worker    self.farg = farg
221*795d594fSAndroid Build Coastguard Worker
222*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
223*795d594fSAndroid Build Coastguard Worker    """
224*795d594fSAndroid Build Coastguard Worker    Get the expected output calling this function.
225*795d594fSAndroid Build Coastguard Worker    """
226*795d594fSAndroid Build Coastguard Worker    exp = self.farg.get_called()
227*795d594fSAndroid Build Coastguard Worker    if exp.is_empty():
228*795d594fSAndroid Build Coastguard Worker      return self.NSME_RESULT_TEMPLATE.format(tree = self.farg.get_tree())
229*795d594fSAndroid Build Coastguard Worker    elif exp.is_abstract():
230*795d594fSAndroid Build Coastguard Worker      return self.AME_RESULT_TEMPLATE.format(tree = self.farg.get_tree())
231*795d594fSAndroid Build Coastguard Worker    elif exp.is_conflict():
232*795d594fSAndroid Build Coastguard Worker      return self.ICCE_RESULT_TEMPLATE.format(tree = self.farg.get_tree())
233*795d594fSAndroid Build Coastguard Worker    else:
234*795d594fSAndroid Build Coastguard Worker      assert exp.is_default()
235*795d594fSAndroid Build Coastguard Worker      return self.NORMAL_RESULT_TEMPLATE.format(tree = self.farg.get_tree(),
236*795d594fSAndroid Build Coastguard Worker                                                result = exp.get_tree())
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker  def get_name(self):
239*795d594fSAndroid Build Coastguard Worker    """
240*795d594fSAndroid Build Coastguard Worker    Get the name of this function
241*795d594fSAndroid Build Coastguard Worker    """
242*795d594fSAndroid Build Coastguard Worker    return "TEST_FUNC_{}".format(self.farg.get_name())
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker  def __str__(self):
245*795d594fSAndroid Build Coastguard Worker    """
246*795d594fSAndroid Build Coastguard Worker    Print the smali code of this function.
247*795d594fSAndroid Build Coastguard Worker    """
248*795d594fSAndroid Build Coastguard Worker    return self.TEST_FUNCTION_TEMPLATE.format(tree = self.farg.get_tree(),
249*795d594fSAndroid Build Coastguard Worker                                              fname = self.get_name(),
250*795d594fSAndroid Build Coastguard Worker                                              farg = self.farg.get_name())
251*795d594fSAndroid Build Coastguard Worker
252*795d594fSAndroid Build Coastguard Workerclass TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
253*795d594fSAndroid Build Coastguard Worker  """
254*795d594fSAndroid Build Coastguard Worker  A class that will be instantiated to test default method resolution order.
255*795d594fSAndroid Build Coastguard Worker  """
256*795d594fSAndroid Build Coastguard Worker
257*795d594fSAndroid Build Coastguard Worker  TEST_CLASS_TEMPLATE = """{copyright}
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker.class public L{class_name};
260*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
261*795d594fSAndroid Build Coastguard Worker.implements L{iface_name};
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker# public class {class_name} implements {iface_name} {{
264*795d594fSAndroid Build Coastguard Worker
265*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V
266*795d594fSAndroid Build Coastguard Worker  .registers 1
267*795d594fSAndroid Build Coastguard Worker  invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
268*795d594fSAndroid Build Coastguard Worker  return-void
269*795d594fSAndroid Build Coastguard Worker.end method
270*795d594fSAndroid Build Coastguard Worker
271*795d594fSAndroid Build Coastguard Worker{funcs}
272*795d594fSAndroid Build Coastguard Worker
273*795d594fSAndroid Build Coastguard Worker# }}
274*795d594fSAndroid Build Coastguard Worker"""
275*795d594fSAndroid Build Coastguard Worker
276*795d594fSAndroid Build Coastguard Worker  def __init__(self, iface):
277*795d594fSAndroid Build Coastguard Worker    """
278*795d594fSAndroid Build Coastguard Worker    Initialize this test class which implements the given interface
279*795d594fSAndroid Build Coastguard Worker    """
280*795d594fSAndroid Build Coastguard Worker    self.iface = iface
281*795d594fSAndroid Build Coastguard Worker    self.class_name = "CLASS_"+gensym()
282*795d594fSAndroid Build Coastguard Worker
283*795d594fSAndroid Build Coastguard Worker  def get_name(self):
284*795d594fSAndroid Build Coastguard Worker    """
285*795d594fSAndroid Build Coastguard Worker    Get the name of this class
286*795d594fSAndroid Build Coastguard Worker    """
287*795d594fSAndroid Build Coastguard Worker    return self.class_name
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker  def get_tree(self):
290*795d594fSAndroid Build Coastguard Worker    """
291*795d594fSAndroid Build Coastguard Worker    Print out a representation of the type tree of this class
292*795d594fSAndroid Build Coastguard Worker    """
293*795d594fSAndroid Build Coastguard Worker    return "[{class_name} {iface_tree}]".format(class_name = self.class_name,
294*795d594fSAndroid Build Coastguard Worker                                                iface_tree = self.iface.get_tree())
295*795d594fSAndroid Build Coastguard Worker
296*795d594fSAndroid Build Coastguard Worker  def __iter__(self):
297*795d594fSAndroid Build Coastguard Worker    """
298*795d594fSAndroid Build Coastguard Worker    Step through all interfaces implemented transitively by this class
299*795d594fSAndroid Build Coastguard Worker    """
300*795d594fSAndroid Build Coastguard Worker    yield self.iface
301*795d594fSAndroid Build Coastguard Worker    yield from self.iface
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker  def get_called(self):
304*795d594fSAndroid Build Coastguard Worker    """
305*795d594fSAndroid Build Coastguard Worker    Returns the interface that will be called when the method on this class is invoked or
306*795d594fSAndroid Build Coastguard Worker    CONFLICT_TYPE if there is no interface that will be called.
307*795d594fSAndroid Build Coastguard Worker    """
308*795d594fSAndroid Build Coastguard Worker    return self.iface.get_called()
309*795d594fSAndroid Build Coastguard Worker
310*795d594fSAndroid Build Coastguard Worker  def __str__(self):
311*795d594fSAndroid Build Coastguard Worker    """
312*795d594fSAndroid Build Coastguard Worker    Print the smali code of this class.
313*795d594fSAndroid Build Coastguard Worker    """
314*795d594fSAndroid Build Coastguard Worker    return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
315*795d594fSAndroid Build Coastguard Worker                                           iface_name = self.iface.get_name(),
316*795d594fSAndroid Build Coastguard Worker                                           tree = self.get_tree(),
317*795d594fSAndroid Build Coastguard Worker                                           class_name = self.class_name,
318*795d594fSAndroid Build Coastguard Worker                                           funcs = "")
319*795d594fSAndroid Build Coastguard Worker
320*795d594fSAndroid Build Coastguard Workerclass InterfaceType(Enum):
321*795d594fSAndroid Build Coastguard Worker  """
322*795d594fSAndroid Build Coastguard Worker  An enumeration of all the different types of interfaces we can have.
323*795d594fSAndroid Build Coastguard Worker
324*795d594fSAndroid Build Coastguard Worker  default: It has a default method
325*795d594fSAndroid Build Coastguard Worker  abstract: It has a method declared but not defined
326*795d594fSAndroid Build Coastguard Worker  empty: It does not have the method
327*795d594fSAndroid Build Coastguard Worker  """
328*795d594fSAndroid Build Coastguard Worker  default = 0
329*795d594fSAndroid Build Coastguard Worker  abstract = 1
330*795d594fSAndroid Build Coastguard Worker  empty = 2
331*795d594fSAndroid Build Coastguard Worker
332*795d594fSAndroid Build Coastguard Worker  def get_suffix(self):
333*795d594fSAndroid Build Coastguard Worker    if self == InterfaceType.default:
334*795d594fSAndroid Build Coastguard Worker      return "_DEFAULT"
335*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceType.abstract:
336*795d594fSAndroid Build Coastguard Worker      return "_ABSTRACT"
337*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceType.empty:
338*795d594fSAndroid Build Coastguard Worker      return "_EMPTY"
339*795d594fSAndroid Build Coastguard Worker    else:
340*795d594fSAndroid Build Coastguard Worker      raise TypeError("Interface type had illegal value.")
341*795d594fSAndroid Build Coastguard Worker
342*795d594fSAndroid Build Coastguard Workerclass ConflictInterface:
343*795d594fSAndroid Build Coastguard Worker  """
344*795d594fSAndroid Build Coastguard Worker  A singleton representing a conflict of default methods.
345*795d594fSAndroid Build Coastguard Worker  """
346*795d594fSAndroid Build Coastguard Worker
347*795d594fSAndroid Build Coastguard Worker  def is_conflict(self):
348*795d594fSAndroid Build Coastguard Worker    """
349*795d594fSAndroid Build Coastguard Worker    Returns true if this is a conflict interface and calling the method on this interface will
350*795d594fSAndroid Build Coastguard Worker    result in an IncompatibleClassChangeError.
351*795d594fSAndroid Build Coastguard Worker    """
352*795d594fSAndroid Build Coastguard Worker    return True
353*795d594fSAndroid Build Coastguard Worker
354*795d594fSAndroid Build Coastguard Worker  def is_abstract(self):
355*795d594fSAndroid Build Coastguard Worker    """
356*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
357*795d594fSAndroid Build Coastguard Worker    result in an AbstractMethodError.
358*795d594fSAndroid Build Coastguard Worker    """
359*795d594fSAndroid Build Coastguard Worker    return False
360*795d594fSAndroid Build Coastguard Worker
361*795d594fSAndroid Build Coastguard Worker  def is_empty(self):
362*795d594fSAndroid Build Coastguard Worker    """
363*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
364*795d594fSAndroid Build Coastguard Worker    result in a NoSuchMethodError.
365*795d594fSAndroid Build Coastguard Worker    """
366*795d594fSAndroid Build Coastguard Worker    return False
367*795d594fSAndroid Build Coastguard Worker
368*795d594fSAndroid Build Coastguard Worker  def is_default(self):
369*795d594fSAndroid Build Coastguard Worker    """
370*795d594fSAndroid Build Coastguard Worker    Returns true if this is a default interface and calling the method on this interface will
371*795d594fSAndroid Build Coastguard Worker    result in a method actually being called.
372*795d594fSAndroid Build Coastguard Worker    """
373*795d594fSAndroid Build Coastguard Worker    return False
374*795d594fSAndroid Build Coastguard Worker
375*795d594fSAndroid Build Coastguard WorkerCONFLICT_TYPE = ConflictInterface()
376*795d594fSAndroid Build Coastguard Worker
377*795d594fSAndroid Build Coastguard Workerclass TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
378*795d594fSAndroid Build Coastguard Worker  """
379*795d594fSAndroid Build Coastguard Worker  An interface that will be used to test default method resolution order.
380*795d594fSAndroid Build Coastguard Worker  """
381*795d594fSAndroid Build Coastguard Worker
382*795d594fSAndroid Build Coastguard Worker  TEST_INTERFACE_TEMPLATE = """{copyright}
383*795d594fSAndroid Build Coastguard Worker.class public abstract interface L{class_name};
384*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
385*795d594fSAndroid Build Coastguard Worker{implements_spec}
386*795d594fSAndroid Build Coastguard Worker
387*795d594fSAndroid Build Coastguard Worker# public interface {class_name} {extends} {ifaces} {{
388*795d594fSAndroid Build Coastguard Worker
389*795d594fSAndroid Build Coastguard Worker{funcs}
390*795d594fSAndroid Build Coastguard Worker
391*795d594fSAndroid Build Coastguard Worker# }}
392*795d594fSAndroid Build Coastguard Worker"""
393*795d594fSAndroid Build Coastguard Worker
394*795d594fSAndroid Build Coastguard Worker  DEFAULT_FUNC_TEMPLATE = """
395*795d594fSAndroid Build Coastguard Worker#   public default String getName() {{
396*795d594fSAndroid Build Coastguard Worker#     return "{tree}";
397*795d594fSAndroid Build Coastguard Worker#   }}
398*795d594fSAndroid Build Coastguard Worker.method public getName()Ljava/lang/String;
399*795d594fSAndroid Build Coastguard Worker  .locals 1
400*795d594fSAndroid Build Coastguard Worker  const-string v0, "{tree}"
401*795d594fSAndroid Build Coastguard Worker  return-object v0
402*795d594fSAndroid Build Coastguard Worker.end method
403*795d594fSAndroid Build Coastguard Worker"""
404*795d594fSAndroid Build Coastguard Worker
405*795d594fSAndroid Build Coastguard Worker  ABSTRACT_FUNC_TEMPLATE = """
406*795d594fSAndroid Build Coastguard Worker#   public String getName();
407*795d594fSAndroid Build Coastguard Worker.method public abstract getName()Ljava/lang/String;
408*795d594fSAndroid Build Coastguard Worker.end method
409*795d594fSAndroid Build Coastguard Worker"""
410*795d594fSAndroid Build Coastguard Worker
411*795d594fSAndroid Build Coastguard Worker  EMPTY_FUNC_TEMPLATE = """"""
412*795d594fSAndroid Build Coastguard Worker
413*795d594fSAndroid Build Coastguard Worker  IMPLEMENTS_TEMPLATE = """
414*795d594fSAndroid Build Coastguard Worker.implements L{iface_name};
415*795d594fSAndroid Build Coastguard Worker"""
416*795d594fSAndroid Build Coastguard Worker
417*795d594fSAndroid Build Coastguard Worker  def __init__(self, ifaces, iface_type, full_name = None):
418*795d594fSAndroid Build Coastguard Worker    """
419*795d594fSAndroid Build Coastguard Worker    Initialize interface with the given super-interfaces
420*795d594fSAndroid Build Coastguard Worker    """
421*795d594fSAndroid Build Coastguard Worker    self.ifaces = sorted(ifaces)
422*795d594fSAndroid Build Coastguard Worker    self.iface_type = iface_type
423*795d594fSAndroid Build Coastguard Worker    if full_name is None:
424*795d594fSAndroid Build Coastguard Worker      end = self.iface_type.get_suffix()
425*795d594fSAndroid Build Coastguard Worker      self.class_name = "INTERFACE_"+gensym()+end
426*795d594fSAndroid Build Coastguard Worker    else:
427*795d594fSAndroid Build Coastguard Worker      self.class_name = full_name
428*795d594fSAndroid Build Coastguard Worker
429*795d594fSAndroid Build Coastguard Worker  def get_specific_version(self, v):
430*795d594fSAndroid Build Coastguard Worker    """
431*795d594fSAndroid Build Coastguard Worker    Returns a copy of this interface of the given type for use in partial compilation.
432*795d594fSAndroid Build Coastguard Worker    """
433*795d594fSAndroid Build Coastguard Worker    return TestInterface(self.ifaces, v, full_name = self.class_name)
434*795d594fSAndroid Build Coastguard Worker
435*795d594fSAndroid Build Coastguard Worker  def get_super_types(self):
436*795d594fSAndroid Build Coastguard Worker    """
437*795d594fSAndroid Build Coastguard Worker    Returns a set of all the supertypes of this interface
438*795d594fSAndroid Build Coastguard Worker    """
439*795d594fSAndroid Build Coastguard Worker    return set(i2 for i2 in self)
440*795d594fSAndroid Build Coastguard Worker
441*795d594fSAndroid Build Coastguard Worker  def is_conflict(self):
442*795d594fSAndroid Build Coastguard Worker    """
443*795d594fSAndroid Build Coastguard Worker    Returns true if this is a conflict interface and calling the method on this interface will
444*795d594fSAndroid Build Coastguard Worker    result in an IncompatibleClassChangeError.
445*795d594fSAndroid Build Coastguard Worker    """
446*795d594fSAndroid Build Coastguard Worker    return False
447*795d594fSAndroid Build Coastguard Worker
448*795d594fSAndroid Build Coastguard Worker  def is_abstract(self):
449*795d594fSAndroid Build Coastguard Worker    """
450*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
451*795d594fSAndroid Build Coastguard Worker    result in an AbstractMethodError.
452*795d594fSAndroid Build Coastguard Worker    """
453*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.abstract
454*795d594fSAndroid Build Coastguard Worker
455*795d594fSAndroid Build Coastguard Worker  def is_empty(self):
456*795d594fSAndroid Build Coastguard Worker    """
457*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
458*795d594fSAndroid Build Coastguard Worker    result in a NoSuchMethodError.
459*795d594fSAndroid Build Coastguard Worker    """
460*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.empty
461*795d594fSAndroid Build Coastguard Worker
462*795d594fSAndroid Build Coastguard Worker  def is_default(self):
463*795d594fSAndroid Build Coastguard Worker    """
464*795d594fSAndroid Build Coastguard Worker    Returns true if this is a default interface and calling the method on this interface will
465*795d594fSAndroid Build Coastguard Worker    result in a method actually being called.
466*795d594fSAndroid Build Coastguard Worker    """
467*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.default
468*795d594fSAndroid Build Coastguard Worker
469*795d594fSAndroid Build Coastguard Worker  def get_called(self):
470*795d594fSAndroid Build Coastguard Worker    """
471*795d594fSAndroid Build Coastguard Worker    Returns the interface that will be called when the method on this class is invoked or
472*795d594fSAndroid Build Coastguard Worker    CONFLICT_TYPE if there is no interface that will be called.
473*795d594fSAndroid Build Coastguard Worker    """
474*795d594fSAndroid Build Coastguard Worker    if not self.is_empty() or len(self.ifaces) == 0:
475*795d594fSAndroid Build Coastguard Worker      return self
476*795d594fSAndroid Build Coastguard Worker    else:
477*795d594fSAndroid Build Coastguard Worker      best = self
478*795d594fSAndroid Build Coastguard Worker      for super_iface in self.ifaces:
479*795d594fSAndroid Build Coastguard Worker        super_best = super_iface.get_called()
480*795d594fSAndroid Build Coastguard Worker        if super_best.is_conflict():
481*795d594fSAndroid Build Coastguard Worker          return CONFLICT_TYPE
482*795d594fSAndroid Build Coastguard Worker        elif best.is_default():
483*795d594fSAndroid Build Coastguard Worker          if super_best.is_default():
484*795d594fSAndroid Build Coastguard Worker            return CONFLICT_TYPE
485*795d594fSAndroid Build Coastguard Worker        elif best.is_abstract():
486*795d594fSAndroid Build Coastguard Worker          if super_best.is_default():
487*795d594fSAndroid Build Coastguard Worker            best = super_best
488*795d594fSAndroid Build Coastguard Worker        else:
489*795d594fSAndroid Build Coastguard Worker          assert best.is_empty()
490*795d594fSAndroid Build Coastguard Worker          best = super_best
491*795d594fSAndroid Build Coastguard Worker      return best
492*795d594fSAndroid Build Coastguard Worker
493*795d594fSAndroid Build Coastguard Worker  def get_name(self):
494*795d594fSAndroid Build Coastguard Worker    """
495*795d594fSAndroid Build Coastguard Worker    Get the name of this class
496*795d594fSAndroid Build Coastguard Worker    """
497*795d594fSAndroid Build Coastguard Worker    return self.class_name
498*795d594fSAndroid Build Coastguard Worker
499*795d594fSAndroid Build Coastguard Worker  def get_tree(self):
500*795d594fSAndroid Build Coastguard Worker    """
501*795d594fSAndroid Build Coastguard Worker    Print out a representation of the type tree of this class
502*795d594fSAndroid Build Coastguard Worker    """
503*795d594fSAndroid Build Coastguard Worker    return "[{class_name} {iftree}]".format(class_name = self.get_name(),
504*795d594fSAndroid Build Coastguard Worker                                            iftree = print_tree(self.ifaces))
505*795d594fSAndroid Build Coastguard Worker
506*795d594fSAndroid Build Coastguard Worker  def __iter__(self):
507*795d594fSAndroid Build Coastguard Worker    """
508*795d594fSAndroid Build Coastguard Worker    Performs depth-first traversal of the interface tree this interface is the
509*795d594fSAndroid Build Coastguard Worker    root of. Does not filter out repeats.
510*795d594fSAndroid Build Coastguard Worker    """
511*795d594fSAndroid Build Coastguard Worker    for i in self.ifaces:
512*795d594fSAndroid Build Coastguard Worker      yield i
513*795d594fSAndroid Build Coastguard Worker      yield from i
514*795d594fSAndroid Build Coastguard Worker
515*795d594fSAndroid Build Coastguard Worker  def __str__(self):
516*795d594fSAndroid Build Coastguard Worker    """
517*795d594fSAndroid Build Coastguard Worker    Print the smali code of this interface.
518*795d594fSAndroid Build Coastguard Worker    """
519*795d594fSAndroid Build Coastguard Worker    s_ifaces = " "
520*795d594fSAndroid Build Coastguard Worker    j_ifaces = " "
521*795d594fSAndroid Build Coastguard Worker    for i in self.ifaces:
522*795d594fSAndroid Build Coastguard Worker      s_ifaces += self.IMPLEMENTS_TEMPLATE.format(iface_name = i.get_name())
523*795d594fSAndroid Build Coastguard Worker      j_ifaces += " {},".format(i.get_name())
524*795d594fSAndroid Build Coastguard Worker    j_ifaces = j_ifaces[0:-1]
525*795d594fSAndroid Build Coastguard Worker    if self.is_default():
526*795d594fSAndroid Build Coastguard Worker      funcs = self.DEFAULT_FUNC_TEMPLATE.format(tree = self.get_tree())
527*795d594fSAndroid Build Coastguard Worker    elif self.is_abstract():
528*795d594fSAndroid Build Coastguard Worker      funcs = self.ABSTRACT_FUNC_TEMPLATE.format()
529*795d594fSAndroid Build Coastguard Worker    else:
530*795d594fSAndroid Build Coastguard Worker      funcs = ""
531*795d594fSAndroid Build Coastguard Worker    return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'),
532*795d594fSAndroid Build Coastguard Worker                                               implements_spec = s_ifaces,
533*795d594fSAndroid Build Coastguard Worker                                               extends = "extends" if len(self.ifaces) else "",
534*795d594fSAndroid Build Coastguard Worker                                               ifaces = j_ifaces,
535*795d594fSAndroid Build Coastguard Worker                                               funcs = funcs,
536*795d594fSAndroid Build Coastguard Worker                                               tree = self.get_tree(),
537*795d594fSAndroid Build Coastguard Worker                                               class_name = self.class_name)
538*795d594fSAndroid Build Coastguard Worker
539*795d594fSAndroid Build Coastguard Workerdef print_tree(ifaces):
540*795d594fSAndroid Build Coastguard Worker  """
541*795d594fSAndroid Build Coastguard Worker  Prints a list of iface trees
542*795d594fSAndroid Build Coastguard Worker  """
543*795d594fSAndroid Build Coastguard Worker  return " ".join(i.get_tree() for i in ifaces)
544*795d594fSAndroid Build Coastguard Worker
545*795d594fSAndroid Build Coastguard Worker# The deduplicated output of subtree_sizes for each size up to
546*795d594fSAndroid Build Coastguard Worker# MAX_LEAF_IFACE_PER_OBJECT.
547*795d594fSAndroid Build Coastguard WorkerSUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i))
548*795d594fSAndroid Build Coastguard Worker            for i in range(MAX_IFACE_DEPTH + 1)]
549*795d594fSAndroid Build Coastguard Worker
550*795d594fSAndroid Build Coastguard Workerdef create_test_classes():
551*795d594fSAndroid Build Coastguard Worker  """
552*795d594fSAndroid Build Coastguard Worker  Yield all the test classes with the different interface trees
553*795d594fSAndroid Build Coastguard Worker  """
554*795d594fSAndroid Build Coastguard Worker  for num in range(1, MAX_IFACE_DEPTH + 1):
555*795d594fSAndroid Build Coastguard Worker    for iface in create_interface_trees(num):
556*795d594fSAndroid Build Coastguard Worker      yield TestClass(iface)
557*795d594fSAndroid Build Coastguard Worker
558*795d594fSAndroid Build Coastguard Workerdef create_interface_trees(num):
559*795d594fSAndroid Build Coastguard Worker  """
560*795d594fSAndroid Build Coastguard Worker  Yield all the interface trees up to 'num' depth.
561*795d594fSAndroid Build Coastguard Worker  """
562*795d594fSAndroid Build Coastguard Worker  if num == 0:
563*795d594fSAndroid Build Coastguard Worker    for iftype in InterfaceType:
564*795d594fSAndroid Build Coastguard Worker      yield TestInterface(tuple(), iftype)
565*795d594fSAndroid Build Coastguard Worker    return
566*795d594fSAndroid Build Coastguard Worker  for split in SUBTREES[num]:
567*795d594fSAndroid Build Coastguard Worker    ifaces = []
568*795d594fSAndroid Build Coastguard Worker    for sub in split:
569*795d594fSAndroid Build Coastguard Worker      ifaces.append(list(create_interface_trees(sub)))
570*795d594fSAndroid Build Coastguard Worker    yield TestInterface(tuple(), InterfaceType.default)
571*795d594fSAndroid Build Coastguard Worker    for supers in itertools.product(*ifaces):
572*795d594fSAndroid Build Coastguard Worker      for iftype in InterfaceType:
573*795d594fSAndroid Build Coastguard Worker        if iftype == InterfaceType.default:
574*795d594fSAndroid Build Coastguard Worker          # We can just stop at defaults. We have other tests that a default can override an
575*795d594fSAndroid Build Coastguard Worker          # abstract and this cuts down on the number of cases significantly, improving speed of
576*795d594fSAndroid Build Coastguard Worker          # this test.
577*795d594fSAndroid Build Coastguard Worker          continue
578*795d594fSAndroid Build Coastguard Worker        yield TestInterface(supers, iftype)
579*795d594fSAndroid Build Coastguard Worker
580*795d594fSAndroid Build Coastguard Workerdef create_all_test_files():
581*795d594fSAndroid Build Coastguard Worker  """
582*795d594fSAndroid Build Coastguard Worker  Creates all the objects representing the files in this test. They just need to
583*795d594fSAndroid Build Coastguard Worker  be dumped.
584*795d594fSAndroid Build Coastguard Worker  """
585*795d594fSAndroid Build Coastguard Worker  mc = MainClass()
586*795d594fSAndroid Build Coastguard Worker  classes = {mc}
587*795d594fSAndroid Build Coastguard Worker  for clazz in create_test_classes():
588*795d594fSAndroid Build Coastguard Worker    classes.add(clazz)
589*795d594fSAndroid Build Coastguard Worker    for i in clazz:
590*795d594fSAndroid Build Coastguard Worker      classes.add(i)
591*795d594fSAndroid Build Coastguard Worker    mc.add_test(clazz)
592*795d594fSAndroid Build Coastguard Worker  return mc, classes
593*795d594fSAndroid Build Coastguard Worker
594*795d594fSAndroid Build Coastguard Workerdef main(argv):
595*795d594fSAndroid Build Coastguard Worker  smali_dir = Path(argv[1])
596*795d594fSAndroid Build Coastguard Worker  if not smali_dir.exists() or not smali_dir.is_dir():
597*795d594fSAndroid Build Coastguard Worker    print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr)
598*795d594fSAndroid Build Coastguard Worker    sys.exit(1)
599*795d594fSAndroid Build Coastguard Worker  expected_txt = Path(argv[2])
600*795d594fSAndroid Build Coastguard Worker  mainclass, all_files = create_all_test_files()
601*795d594fSAndroid Build Coastguard Worker  with expected_txt.open('w') as out:
602*795d594fSAndroid Build Coastguard Worker    print(mainclass.get_expected(), file=out)
603*795d594fSAndroid Build Coastguard Worker  for f in all_files:
604*795d594fSAndroid Build Coastguard Worker    f.dump(smali_dir)
605*795d594fSAndroid Build Coastguard Worker
606*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__':
607*795d594fSAndroid Build Coastguard Worker  main(sys.argv)
608