blob: befc7676861fbae288c2dd2963a59b08bcebbec8 [file] [log] [blame]
// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
import java.util.concurrent.ExecutorService;
/**
* Tool to extract the list of methods which is backported by the D8 and R8 compilers.
*
* <p>The D8 and R8 compilers will backport some simple Java APIs which are not present on all API
* levels. One example of this is the static method <code>int Integer.divideUnsigned(int a, int b)
* </code> which was added from API level 26.
*
* <p>As these backported methods is supported on all API levels, tools like linters and code
* checkers need this information to avoid false negatives when analyzing code.
*
* <p>This tool will generate a list of all the backported methods for the associated version of D8
* and R8.
*
* <p>This tool will <strong>not</strong> provide information about the APIs supported when using
* library desugaring. That information is provided in the dependencies used for library desugaring.
* However, in place of library desugaring backporting will be able to backport additional methods.
* If library desugaring is used, then passing information about that to this tool will provide the
* more precise list. See b/149078312.
*
* <p>The tool is invoked by calling {@link #run(BackportedMethodListCommand)
* BackportedMethodList.run} with an appropriate {@link BackportedMethodListCommand}.
*
* <p>For example:
*
* <pre>
* BackportedMethodList.run(BackportedMethodListCommand.builder()
* .setMinApiLevel(apiLevel)
* .setOutputPath(Paths.get("methods-list.txt"))
* .build());
* </pre>
*
* The above generates the list of backported methods for a compilation with a min API of <code>
* apiLevel</code> into the file <code>methods-list.txt</code>.
*/
@Keep
public class BackportedMethodList {
static final String USAGE_MESSAGE =
StringUtils.joinLines(
"Usage: BackportedMethodList [options]",
" Options are:",
" --output <file> # Output result in <file>.",
" --min-api <number> # Minimum Android API level for the application",
" --desugared-lib <file> # Desugared library configuration (JSON from the",
" # configuration)",
" --lib <file> # The compilation SDK library (android.jar)",
" --version # Print the version of BackportedMethodList.",
" --help # Print this message.");
private static String formatMethod(DexMethod method) {
return DescriptorUtils.getClassBinaryNameFromDescriptor(method.holder.descriptor.toString())
+ '#'
+ method.name
+ method.proto.toDescriptorString();
}
public static void run(BackportedMethodListCommand command) throws CompilationFailedException {
if (command.isPrintHelp()) {
System.out.println(USAGE_MESSAGE);
return;
}
if (command.isPrintVersion()) {
System.out.println("BackportedMethodList " + Version.getVersionString());
return;
}
InternalOptions options = command.getInternalOptions();
ExecutorService executorService = ThreadUtils.getExecutorService(options);
try {
ExceptionUtils.withD8CompilationHandler(
command.getReporter(),
() -> {
BackportedMethodRewriter.generateListOfBackportedMethods(
command.getInputApp(), options, executorService)
.stream()
.map(BackportedMethodList::formatMethod)
.sorted()
.forEach(
formattedMethod ->
command
.getBackportedMethodListConsumer()
.accept(formattedMethod, command.getReporter()));
command.getBackportedMethodListConsumer().finished(command.getReporter());
});
} finally {
executorService.shutdown();
}
}
public static void run(String[] args) throws CompilationFailedException {
run(BackportedMethodListCommand.parse(args).build());
}
public static void main(String[] args) {
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
}