• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Bazel Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 package com.google.devtools.build.android.desugar.testdata.java8;
15 
16 import com.google.common.collect.ImmutableList;
17 import java.util.ArrayList;
18 import java.util.List;
19 
20 /**
21  * Interfaces with default methods are intialized differently from those without default methods.
22  * When we load such an interface, its static intializer will be executed.
23  *
24  * <p>However, interfaces without default methods are only initialized when their non-primitive
25  * fields are accessed.
26  *
27  * <p>Test data for b/38255926
28  */
29 public class DefaultInterfaceMethodWithStaticInitializer {
30 
31   final List<String> initializationOrder = new ArrayList<>();
32 
register(Class<?> enclosingInterfaceClass)33   DefaultInterfaceMethodWithStaticInitializer register(Class<?> enclosingInterfaceClass) {
34     initializationOrder.add(enclosingInterfaceClass.getSimpleName());
35     return this;
36   }
37 
getTime()38   private static long getTime() {
39     return 0;
40   }
41 
42   /** The simplest case: direct implementation. */
43   public static class TestInterfaceSetOne {
44 
45     /**
46      * A writable field so that other interfaces can set it in their static initializers.
47      * (b/64290760)
48      */
49     static long writableStaticField;
50 
51     static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
52         new DefaultInterfaceMethodWithStaticInitializer();
53 
54     /** With a default method, this interface should run clinit. */
55     interface I1 {
56       long NOW = TestInterfaceSetOne.writableStaticField = getTime();
57       DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
58 
defaultM1()59       default int defaultM1() {
60         return 1;
61       }
62     }
63 
64     /** With a default method, this interface should run clinit. */
65     interface I2 {
66       long NOW = TestInterfaceSetOne.writableStaticField = getTime();
67       DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class);
68 
defaultM2()69       default int defaultM2() {
70         return 10;
71       }
72     }
73 
74     /** Class to trigger the clinit. */
75     public static class C implements I1, I2 {
sum()76       public int sum() {
77         return defaultM1() + defaultM2();
78       }
79     }
80 
getExpectedInitializationOrder()81     public static ImmutableList<String> getExpectedInitializationOrder() {
82       return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName());
83     }
84 
getRealInitializationOrder()85     public static ImmutableList<String> getRealInitializationOrder() {
86       return ImmutableList.copyOf(RECORDER.initializationOrder);
87     }
88   }
89 
90   /** Test for initializer execution order. */
91   public static class TestInterfaceSetTwo {
92 
93     static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
94         new DefaultInterfaceMethodWithStaticInitializer();
95 
96     interface I1 {
97       DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
98 
defaultM1()99       default int defaultM1() {
100         return 1;
101       }
102     }
103 
104     interface I2 extends I1 {
105       DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class);
106 
defaultM2()107       default int defaultM2() {
108         return 2;
109       }
110     }
111 
112     /**
113      * Loading this class will trigger the execution of the static initializers of I2 and I1.
114      * However, I1 will be loaded first, as I2 extends I1.
115      */
116     public static class C implements I2, I1 {
117       protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit>
118 
sum()119       public int sum() {
120         return defaultM1() + defaultM2();
121       }
122     }
123 
getExpectedInitializationOrder()124     public static ImmutableList<String> getExpectedInitializationOrder() {
125       return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName());
126     }
127 
getRealInitializationOrder()128     public static ImmutableList<String> getRealInitializationOrder() {
129       return ImmutableList.copyOf(RECORDER.initializationOrder);
130     }
131   }
132 
133   /** Test: I2's <clinit> should not be executed. */
134   public static class TestInterfaceSetThree {
135     static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
136         new DefaultInterfaceMethodWithStaticInitializer();
137 
138     interface I1 {
139       DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
140 
defaultM1()141       default int defaultM1() {
142         return 6;
143       }
144     }
145 
146     interface I2 extends I1 {
defaultM2()147       default int defaultM2() {
148         return 5;
149       }
150     }
151 
152     /**
153      * Loading this class will trigger the execution of the static initializers of I1. I2's will not
154      * execute.
155      */
156     public static class C implements I2, I1 {
157       protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit>
158 
sum()159       public int sum() {
160         return defaultM1() + defaultM2();
161       }
162     }
163 
getExpectedInitializationOrder()164     public static ImmutableList<String> getExpectedInitializationOrder() {
165       return ImmutableList.of(I1.class.getSimpleName());
166     }
167 
getRealInitializationOrder()168     public static ImmutableList<String> getRealInitializationOrder() {
169       return ImmutableList.copyOf(RECORDER.initializationOrder);
170     }
171   }
172 }
173