blob: b5c6375477f32aa138e1664e7db862ccb8fa81e3 [file] [log] [blame]
// Copyright (c) 2020, 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.tracereferences;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.Keep;
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.Version;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.utils.AndroidApp;
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.Timing;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
@Keep
public class TraceReferences {
public static void run(TraceReferencesCommand command) throws CompilationFailedException {
ExceptionUtils.withCompilationHandler(command.getReporter(), () -> runInternal(command));
}
private static void forEachDescriptor(ProgramResourceProvider provider, Consumer<String> consumer)
throws ResourceException, IOException {
for (ProgramResource programResource : provider.getProgramResources()) {
if (programResource.getKind() == Kind.DEX) {
assert programResource.getClassDescriptors() == null;
for (DexProgramClass clazz :
new ApplicationReader(
AndroidApp.builder()
.addDexProgramData(ImmutableList.of(programResource.getBytes()))
.build(),
new InternalOptions(),
Timing.empty())
.read()
.classes()) {
consumer.accept(clazz.getType().toDescriptorString());
}
} else {
assert programResource.getClassDescriptors() != null;
programResource.getClassDescriptors().forEach(consumer);
}
}
}
private static void runInternal(TraceReferencesCommand command)
throws IOException, ResourceException {
AndroidApp.Builder builder = AndroidApp.builder();
command.getLibrary().forEach(builder::addLibraryResourceProvider);
command.getTarget().forEach(builder::addLibraryResourceProvider);
command.getSource().forEach(builder::addProgramResourceProvider);
Set<String> targetDescriptors = new HashSet<>();
command
.getTarget()
.forEach(provider -> targetDescriptors.addAll(provider.getClassDescriptors()));
for (ProgramResourceProvider provider : command.getSource()) {
forEachDescriptor(provider, targetDescriptors::remove);
}
Tracer tracer = new Tracer(targetDescriptors, builder.build(), command.getReporter());
tracer.run(command.getConsumer());
}
public static void run(String... args) throws CompilationFailedException {
TraceReferencesCommand command =
TraceReferencesCommand.parse(args, CommandLineOrigin.INSTANCE).build();
if (command.isPrintHelp()) {
System.out.println(TraceReferencesCommandParser.USAGE_MESSAGE);
return;
}
if (command.isPrintVersion()) {
System.out.println("tracereferences " + Version.getVersionString());
return;
}
run(command);
}
/**
* Command-line entry to tracereferences.
*
* <p>See {@link TraceReferencesCommandParser#USAGE_MESSAGE} or run {@code tracereferences --help}
* for usage information.
*/
public static void main(String[] args) {
if (args.length == 0) {
throw new RuntimeException(
StringUtils.joinLines("Invalid invocation.", TraceReferencesCommandParser.USAGE_MESSAGE));
}
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
}