blob: 32b55be1dc4e955d93c39b5f384983bdf5e94977 [file] [log] [blame]
// 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.
*
* <p>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.
*
* <p>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;
}
}
}