// Copyright 2017 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.android.desugar; import javax.annotation.Nullable; /** * Interface for collecting desugaring metadata that we can use to double-check correct desugaring * at the binary level by looking at the metadata written for all Jars on the runtime classpath * (b/65645388). Use {@link NoWriteCollectors} for "no-op" collectors and {@link * com.google.devtools.build.android.desugar.dependencies.MetadataCollector} for writing out * metadata files. */ // TODO(kmb): There could conceivably be a "self-contained" version where we check at the end that // we actually saw all the companion classes (in recordDefaultMethods) that we "assumed"; useful // for one-shot runs over an entire binary. @SuppressWarnings("unused") // default implementations consist of empty method stubs public interface DependencyCollector { /** Class name suffix used for interface companion classes. */ public String INTERFACE_COMPANION_SUFFIX = "$$CC"; /** * Records that {@code origin} depends on companion class {@code target}. For the resulting * binary to be valid, {@code target} needs to exist, which isn't the case if the corresponding * interface is only available as a compile-time ("neverlink") dependency. */ default void assumeCompanionClass(String origin, String target) {} /** * Records that {@code origin} transitively implements {@code target} but {@code target} isn't * in the classpath. This can lead to wrong desugarings if {@code target} or an interface it * extends defines default methods. */ default void missingImplementedInterface(String origin, String target) {} /** * Records that the given interface extends the given interfaces. * *

This information is useful reference to double-check {@link #missingImplementedInterface}s * without reading and parsing .class files, specifically if default methods are defined in * interfaces that a missing interface transitively extends. */ default void recordExtendedInterfaces(String origin, String... targets) {} /** * Records that the given interface has a companion class that includes the given number of * default methods (0 if there were only static methods). This method should not be called for * purely abstract interfaces, to allow verifying available companion classes against this. * *

This information is useful reference to double-check {@link #missingImplementedInterface}s * without reading and parsing .class files with better precision than just looking for * companion classes on the runtime classpath (which may only contain static methods). */ default void recordDefaultMethods(String origin, int count) {} /** * Returns metadata to include into the desugaring output or {@code null} if none. Returning * anything but {@code null} will cause an extra file to be written into the output, including * an empty array. */ @Nullable public byte[] toByteArray(); /** Simple collectors that don't collect any information. */ public enum NoWriteCollectors implements DependencyCollector { /** Singleton instance that does nothing. */ NOOP, /** * Singleton instance that does nothing besides throwing if {@link #missingImplementedInterface} * is called. */ FAIL_ON_MISSING { @Override public void missingImplementedInterface(String origin, String target) { throw new IllegalStateException( String.format( "Couldn't find interface %s on the classpath for desugaring %s", target, origin)); } }; @Override @Nullable public final byte[] toByteArray() { return null; } } }