• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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;
15 
16 import static com.google.common.truth.Truth.assertThat;
17 import static org.junit.Assert.fail;
18 
19 import org.junit.Test;
20 import org.junit.runner.RunWith;
21 import org.junit.runners.JUnit4;
22 import org.objectweb.asm.ClassReader;
23 import org.objectweb.asm.ClassVisitor;
24 import org.objectweb.asm.MethodVisitor;
25 import org.objectweb.asm.Opcodes;
26 
27 @RunWith(JUnit4.class)
28 public class Java7CompatibilityTest {
29 
30   @Test
testJava7CompatibleInterface()31   public void testJava7CompatibleInterface() throws Exception {
32     ClassReader reader = new ClassReader(ExtendsDefault.class.getName());
33     ClassTester tester = new ClassTester();
34     reader.accept(new Java7Compatibility(tester, null, null), 0);
35     assertThat(tester.version).isEqualTo(Opcodes.V1_7);
36     assertThat(tester.bridgeMethods).isEqualTo(0); // make sure we strip bridge methods
37     assertThat(tester.clinitMethods).isEqualTo(1); // make sure we don't strip <clinit>
38   }
39 
40   @Test
testDefaultMethodFails()41   public void testDefaultMethodFails() throws Exception {
42     ClassReader reader = new ClassReader(WithDefault.class.getName());
43     try {
44       reader.accept(new Java7Compatibility(null, null, null), 0);
45       fail("IllegalArgumentException expected");
46     } catch (IllegalArgumentException expected) {
47       assertThat(expected).hasMessageThat().contains("getVersion()I");
48     }
49   }
50 
51   /**
52    * Tests that a class implementing interfaces with bridge methods redeclares those bridges.
53    * This is behavior of javac that we rely on.
54    */
55   @Test
testConcreteClassRedeclaresBridges()56   public void testConcreteClassRedeclaresBridges() throws Exception {
57     ClassReader reader = new ClassReader(Impl.class.getName());
58     ClassTester tester = new ClassTester();
59     reader.accept(new Java7Compatibility(tester, null, null), 0);
60     assertThat(tester.version).isEqualTo(Opcodes.V1_7);
61     assertThat(tester.bridgeMethods).isEqualTo(2);
62   }
63 
64   private static class ClassTester extends ClassVisitor {
65 
66     int version;
67     int bridgeMethods;
68     int clinitMethods;
69 
ClassTester()70     private ClassTester() {
71       super(Opcodes.ASM5, null);
72     }
73 
74     @Override
visit( int version, int access, String name, String signature, String superName, String[] interfaces)75     public void visit(
76         int version,
77         int access,
78         String name,
79         String signature,
80         String superName,
81         String[] interfaces) {
82       this.version = version;
83       super.visit(version, access, name, signature, superName, interfaces);
84     }
85 
86     @Override
visitMethod( int access, String name, String desc, String signature, String[] exceptions)87     public MethodVisitor visitMethod(
88         int access, String name, String desc, String signature, String[] exceptions) {
89       if (BitFlags.isSet(access, Opcodes.ACC_BRIDGE)) {
90         ++bridgeMethods;
91       }
92       if ("<clinit>".equals(name)) {
93         ++clinitMethods;
94       }
95       return super.visitMethod(access, name, desc, signature, exceptions);
96     }
97   }
98 
99   interface WithDefault<T> {
getVersion()100     default int getVersion() {
101       return 18;
102     }
get()103     T get();
104   }
105 
106   // Javac will generate a default bridge method "Object get()" that Java7Compatibility will remove
107   interface ExtendsDefault<T extends Number> extends WithDefault<T> {
108     public static final Integer X = Integer.valueOf(37);
name()109     String name();
get()110     @Override T get();
111   }
112 
113   // Javac will generate 2 bridge methods that we *don't* want to remove
114   static class Impl implements ExtendsDefault<Integer> {
get()115     @Override public Integer get() {
116       return X;
117     }
name()118     @Override public String name() {
119       return "test";
120     }
121   }
122 }
123