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; 15 16 import javax.annotation.Nullable; 17 18 /** 19 * Interface for collecting desugaring metadata that we can use to double-check correct desugaring 20 * at the binary level by looking at the metadata written for all Jars on the runtime classpath 21 * (b/65645388). Use {@link NoWriteCollectors} for "no-op" collectors and {@link 22 * com.google.devtools.build.android.desugar.dependencies.MetadataCollector} for writing out 23 * metadata files. 24 */ 25 // TODO(kmb): There could conceivably be a "self-contained" version where we check at the end that 26 // we actually saw all the companion classes (in recordDefaultMethods) that we "assumed"; useful 27 // for one-shot runs over an entire binary. 28 @SuppressWarnings("unused") // default implementations consist of empty method stubs 29 public interface DependencyCollector { 30 31 /** Class name suffix used for interface companion classes. */ 32 public String INTERFACE_COMPANION_SUFFIX = "$$CC"; 33 34 /** 35 * Records that {@code origin} depends on companion class {@code target}. For the resulting 36 * binary to be valid, {@code target} needs to exist, which isn't the case if the corresponding 37 * interface is only available as a compile-time ("neverlink") dependency. 38 */ assumeCompanionClass(String origin, String target)39 default void assumeCompanionClass(String origin, String target) {} 40 41 /** 42 * Records that {@code origin} transitively implements {@code target} but {@code target} isn't 43 * in the classpath. This can lead to wrong desugarings if {@code target} or an interface it 44 * extends defines default methods. 45 */ missingImplementedInterface(String origin, String target)46 default void missingImplementedInterface(String origin, String target) {} 47 48 /** 49 * Records that the given interface extends the given interfaces. 50 * 51 * <p>This information is useful reference to double-check {@link #missingImplementedInterface}s 52 * without reading and parsing .class files, specifically if default methods are defined in 53 * interfaces that a missing interface transitively extends. 54 */ recordExtendedInterfaces(String origin, String... targets)55 default void recordExtendedInterfaces(String origin, String... targets) {} 56 57 /** 58 * Records that the given interface has a companion class that includes the given number of 59 * default methods (0 if there were only static methods). This method should not be called for 60 * purely abstract interfaces, to allow verifying available companion classes against this. 61 * 62 * <p>This information is useful reference to double-check {@link #missingImplementedInterface}s 63 * without reading and parsing .class files with better precision than just looking for 64 * companion classes on the runtime classpath (which may only contain static methods). 65 */ recordDefaultMethods(String origin, int count)66 default void recordDefaultMethods(String origin, int count) {} 67 68 /** 69 * Returns metadata to include into the desugaring output or {@code null} if none. Returning 70 * anything but {@code null} will cause an extra file to be written into the output, including 71 * an empty array. 72 */ toByteArray()73 @Nullable public byte[] toByteArray(); 74 75 /** Simple collectors that don't collect any information. */ 76 public enum NoWriteCollectors implements DependencyCollector { 77 /** Singleton instance that does nothing. */ 78 NOOP, 79 /** 80 * Singleton instance that does nothing besides throwing if {@link #missingImplementedInterface} 81 * is called. 82 */ 83 FAIL_ON_MISSING { 84 @Override missingImplementedInterface(String origin, String target)85 public void missingImplementedInterface(String origin, String target) { 86 throw new IllegalStateException( 87 String.format( 88 "Couldn't find interface %s on the classpath for desugaring %s", target, origin)); 89 } 90 }; 91 92 @Override 93 @Nullable toByteArray()94 public final byte[] toByteArray() { 95 return null; 96 } 97 } 98 } 99