blob: 58bb93421a9795033772591fad7d76154042bf1a [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.android.jack;
import com.android.jack.analysis.DefinitionMarkerAdder;
import com.android.jack.analysis.DefinitionMarkerRemover;
import com.android.jack.analysis.UsedVariableAdder;
import com.android.jack.analysis.UsedVariableRemover;
import com.android.jack.analysis.defsuses.DefUsesAndUseDefsChainComputation;
import com.android.jack.analysis.defsuses.DefUsesAndUseDefsChainRemover;
import com.android.jack.analysis.defsuses.UseDefsChecker;
import com.android.jack.analysis.dependency.DependencyInLibraryProduct;
import com.android.jack.analysis.dependency.file.FileDependenciesCollector;
import com.android.jack.analysis.dependency.file.FileDependenciesInLibraryWriter;
import com.android.jack.analysis.dependency.library.LibraryDependenciesInLibraryWriter;
import com.android.jack.analysis.dependency.type.TypeDependenciesCollector;
import com.android.jack.analysis.dependency.type.TypeDependenciesInLibraryWriter;
import com.android.jack.analysis.dfa.reachingdefs.ReachingDefinitions;
import com.android.jack.analysis.dfa.reachingdefs.ReachingDefinitionsRemover;
import com.android.jack.analysis.tracer.ExtendingOrImplementingClassFinder;
import com.android.jack.backend.ResourceWriter;
import com.android.jack.backend.dex.ClassAnnotationBuilder;
import com.android.jack.backend.dex.ClassDefItemBuilder;
import com.android.jack.backend.dex.DexFileProduct;
import com.android.jack.backend.dex.DexFileWriter;
import com.android.jack.backend.dex.DexInLibraryProduct;
import com.android.jack.backend.dex.DexInLibraryWriter;
import com.android.jack.backend.dex.EncodedFieldBuilder;
import com.android.jack.backend.dex.EncodedMethodBuilder;
import com.android.jack.backend.dex.FieldAnnotationBuilder;
import com.android.jack.backend.dex.FieldInitializerRemover;
import com.android.jack.backend.dex.MainDexCollector;
import com.android.jack.backend.dex.MainDexTracer;
import com.android.jack.backend.dex.MethodAnnotationBuilder;
import com.android.jack.backend.dex.MethodBodyRemover;
import com.android.jack.backend.dex.MultiDexAnnotationsFinder;
import com.android.jack.backend.dex.MultiDexLegacy;
import com.android.jack.backend.dex.annotations.ClassAnnotationSchedulingSeparator;
import com.android.jack.backend.dex.annotations.DefaultValueAnnotationAdder;
import com.android.jack.backend.dex.annotations.ReflectAnnotationsAdder;
import com.android.jack.backend.dex.multidex.legacy.AnnotatedFinder;
import com.android.jack.backend.dex.multidex.legacy.RuntimeAnnotationFinder;
import com.android.jack.backend.dex.rop.CodeItemBuilder;
import com.android.jack.backend.jayce.JayceFileImporter;
import com.android.jack.backend.jayce.JayceInLibraryProduct;
import com.android.jack.backend.jayce.JayceInLibraryWriter;
import com.android.jack.cfg.CfgBuilder;
import com.android.jack.cfg.CfgMarkerRemover;
import com.android.jack.config.id.JavaVersionPropertyId.JavaVersion;
import com.android.jack.frontend.FrontendCompilationException;
import com.android.jack.frontend.MethodIdDuplicateRemover;
import com.android.jack.frontend.MethodIdMerger;
import com.android.jack.frontend.TypeDuplicateRemoverChecker;
import com.android.jack.frontend.VirtualMethodsMarker;
import com.android.jack.frontend.java.JackBatchCompiler;
import com.android.jack.frontend.java.JackBatchCompiler.TransportExceptionAroundEcjError;
import com.android.jack.frontend.java.JackBatchCompiler.TransportJUEAroundEcjError;
import com.android.jack.incremental.GenerateLibraryFromIncrementalFolder;
import com.android.jack.incremental.Incremental;
import com.android.jack.ir.JackFormatIr;
import com.android.jack.ir.JavaSourceIr;
import com.android.jack.ir.ast.JClass;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPackage;
import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.ir.formatter.InternalFormatter;
import com.android.jack.ir.formatter.TypePackageAndMethodFormatter;
import com.android.jack.ir.formatter.UserFriendlyFormatter;
import com.android.jack.ir.sourceinfo.SourceInfoCreation;
import com.android.jack.jayce.JaycePackageLoader;
import com.android.jack.library.FileType;
import com.android.jack.library.InputJackLibrary;
import com.android.jack.library.InputLibrary;
import com.android.jack.library.LibraryIOException;
import com.android.jack.library.LibraryReadingException;
import com.android.jack.lookup.CommonTypes;
import com.android.jack.lookup.JPhantomLookup;
import com.android.jack.meta.LibraryMetaWriter;
import com.android.jack.meta.MetaImporter;
import com.android.jack.optimizations.ConstantRefinerAndVariableRemover;
import com.android.jack.optimizations.DefUsesChainsSimplifier;
import com.android.jack.optimizations.ExpressionSimplifier;
import com.android.jack.optimizations.IfWithConstantSimplifier;
import com.android.jack.optimizations.NotSimplifier;
import com.android.jack.optimizations.UnusedDefinitionRemover;
import com.android.jack.optimizations.UseDefsChainsSimplifier;
import com.android.jack.preprocessor.PreProcessor;
import com.android.jack.preprocessor.PreProcessorApplier;
import com.android.jack.reporting.Reporter;
import com.android.jack.reporting.Reporter.Severity;
import com.android.jack.resource.LibraryResourceWriter;
import com.android.jack.resource.ResourceImporter;
import com.android.jack.resource.ResourceReadingException;
import com.android.jack.scheduling.adapter.ExcludeTypeFromLibAdapter;
import com.android.jack.scheduling.adapter.ExcludeTypeFromLibWithBinaryAdapter;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter;
import com.android.jack.scheduling.adapter.JFieldAdapter;
import com.android.jack.scheduling.adapter.JMethodAdapter;
import com.android.jack.scheduling.adapter.JPackageAdapter;
import com.android.jack.scheduling.feature.CompiledTypeStats;
import com.android.jack.scheduling.feature.DropMethodBody;
import com.android.jack.scheduling.feature.Resources;
import com.android.jack.scheduling.feature.SourceVersion7;
import com.android.jack.scheduling.feature.VisibilityBridge;
import com.android.jack.shrob.obfuscation.Mapping;
import com.android.jack.shrob.obfuscation.MappingPrinter;
import com.android.jack.shrob.obfuscation.NameFinalizer;
import com.android.jack.shrob.obfuscation.NameKeeper;
import com.android.jack.shrob.obfuscation.Obfuscation;
import com.android.jack.shrob.obfuscation.OriginalNames;
import com.android.jack.shrob.obfuscation.RemoveSourceFile;
import com.android.jack.shrob.obfuscation.Renamer;
import com.android.jack.shrob.obfuscation.SourceFileRemover;
import com.android.jack.shrob.obfuscation.SourceFileRenamer;
import com.android.jack.shrob.obfuscation.SourceFileRenaming;
import com.android.jack.shrob.obfuscation.annotation.AnnotationDefaultValueRemover;
import com.android.jack.shrob.obfuscation.annotation.FieldAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.FieldGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.LineNumberRemover;
import com.android.jack.shrob.obfuscation.annotation.LocalVariableGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.LocalVariableNameRemover;
import com.android.jack.shrob.obfuscation.annotation.MethodAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.MethodGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.ParameterAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.ParameterNameRemover;
import com.android.jack.shrob.obfuscation.annotation.RemoveAnnotationDefaultValue;
import com.android.jack.shrob.obfuscation.annotation.RemoveEnclosingMethod;
import com.android.jack.shrob.obfuscation.annotation.RemoveEnclosingType;
import com.android.jack.shrob.obfuscation.annotation.RemoveGenericSignature;
import com.android.jack.shrob.obfuscation.annotation.RemoveLineNumber;
import com.android.jack.shrob.obfuscation.annotation.RemoveLocalVariableGenericSignature;
import com.android.jack.shrob.obfuscation.annotation.RemoveLocalVariableName;
import com.android.jack.shrob.obfuscation.annotation.RemoveParameterName;
import com.android.jack.shrob.obfuscation.annotation.RemoveThrownException;
import com.android.jack.shrob.obfuscation.annotation.ThrownExceptionRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeEnclosingMethodRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeEnclosingTypeRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.resource.AdaptResourceFileContent;
import com.android.jack.shrob.obfuscation.resource.ResourceContentRefiner;
import com.android.jack.shrob.obfuscation.resource.ResourceRefiner;
import com.android.jack.shrob.proguard.GrammarActions;
import com.android.jack.shrob.seed.SeedFile;
import com.android.jack.shrob.seed.SeedFinder;
import com.android.jack.shrob.seed.SeedPrinter;
import com.android.jack.shrob.shrink.FieldShrinker;
import com.android.jack.shrob.shrink.Keeper;
import com.android.jack.shrob.shrink.MethodShrinker;
import com.android.jack.shrob.shrink.ShrinkAndMainDexTracer;
import com.android.jack.shrob.shrink.ShrinkStructurePrinter;
import com.android.jack.shrob.shrink.Shrinking;
import com.android.jack.shrob.shrink.StructurePrinting;
import com.android.jack.shrob.shrink.TypeShrinker;
import com.android.jack.shrob.spec.Flags;
import com.android.jack.statistics.BinaryOperationWithCst;
import com.android.jack.statistics.CodeStats;
import com.android.jack.statistics.FieldStats;
import com.android.jack.statistics.MethodStats;
import com.android.jack.transformations.AssertionTransformer;
import com.android.jack.transformations.AssertionTransformerSchedulingSeparator;
import com.android.jack.transformations.EmptyClinitRemover;
import com.android.jack.transformations.FieldInitializer;
import com.android.jack.transformations.Jarjar;
import com.android.jack.transformations.SanityChecks;
import com.android.jack.transformations.UnusedLocalRemover;
import com.android.jack.transformations.VisibilityBridgeAdder;
import com.android.jack.transformations.ast.BooleanTestTransformer;
import com.android.jack.transformations.ast.CompoundAssignmentRemover;
import com.android.jack.transformations.ast.ConcatRemover;
import com.android.jack.transformations.ast.ExpressionStatementLegalizer;
import com.android.jack.transformations.ast.ImplicitBlocks;
import com.android.jack.transformations.ast.ImplicitBlocksChecker;
import com.android.jack.transformations.ast.IncDecRemover;
import com.android.jack.transformations.ast.InitInNewArrayRemover;
import com.android.jack.transformations.ast.MultiDimensionNewArrayRemover;
import com.android.jack.transformations.ast.NestedAssignRemover;
import com.android.jack.transformations.ast.NumericConversionChecker;
import com.android.jack.transformations.ast.PrimitiveClassTransformer;
import com.android.jack.transformations.ast.RefAsStatementRemover;
import com.android.jack.transformations.ast.SynchronizeTransformer;
import com.android.jack.transformations.ast.TryWithResourcesTransformer;
import com.android.jack.transformations.ast.TypeLegalizer;
import com.android.jack.transformations.ast.inner.InnerAccessorAdder;
import com.android.jack.transformations.ast.inner.InnerAccessorGenerator;
import com.android.jack.transformations.ast.inner.InnerAccessorSchedulingSeparator;
import com.android.jack.transformations.ast.removeinit.FieldInitMethodCallRemover;
import com.android.jack.transformations.ast.removeinit.FieldInitMethodRemover;
import com.android.jack.transformations.ast.splitnew.SplitNewInstance;
import com.android.jack.transformations.ast.splitnew.SplitNewInstanceChecker;
import com.android.jack.transformations.ast.string.FieldGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.FieldStringLiteralRefiner;
import com.android.jack.transformations.ast.string.MethodGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.MethodStringLiteralRefiner;
import com.android.jack.transformations.ast.string.ReflectionStringLiteralRefiner;
import com.android.jack.transformations.ast.string.SimpleNameRefiner;
import com.android.jack.transformations.ast.string.TypeGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.TypeStringLiteralRefiner;
import com.android.jack.transformations.ast.switches.SwitchStringSupport;
import com.android.jack.transformations.ast.switches.UselessCaseChecker;
import com.android.jack.transformations.ast.switches.UselessCaseRemover;
import com.android.jack.transformations.ast.switches.UselessSwitchesRemover;
import com.android.jack.transformations.booleanoperators.ConditionalAndOrRemover;
import com.android.jack.transformations.booleanoperators.ConditionalAndOrRemoverChecker;
import com.android.jack.transformations.cast.UselessCastRemover;
import com.android.jack.transformations.enums.EnumMappingMarkerRemover;
import com.android.jack.transformations.enums.EnumMappingSchedulingSeparator;
import com.android.jack.transformations.enums.SwitchEnumSupport;
import com.android.jack.transformations.enums.UsedEnumFieldCollector;
import com.android.jack.transformations.enums.UsedEnumFieldMarkerRemover;
import com.android.jack.transformations.exceptions.ExceptionRuntimeValueAdder;
import com.android.jack.transformations.exceptions.TryCatchRemover;
import com.android.jack.transformations.exceptions.TryStatementSchedulingSeparator;
import com.android.jack.transformations.finallyblock.FinallyRemover;
import com.android.jack.transformations.flow.FlowNormalizer;
import com.android.jack.transformations.flow.FlowNormalizerSchedulingSeparator;
import com.android.jack.transformations.parent.AstChecker;
import com.android.jack.transformations.parent.TypeAstChecker;
import com.android.jack.transformations.renamepackage.PackageRenamer;
import com.android.jack.transformations.rop.cast.RopCastLegalizer;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeBuilder;
import com.android.jack.transformations.typedef.TypeDefRemover;
import com.android.jack.transformations.typedef.TypeDefRemover.RemoveTypeDef;
import com.android.jack.transformations.uselessif.UselessIfChecker;
import com.android.jack.transformations.uselessif.UselessIfRemover;
import com.android.jack.util.collect.UnmodifiableCollections;
import com.android.sched.scheduler.FeatureSet;
import com.android.sched.scheduler.IllegalRequestException;
import com.android.sched.scheduler.Plan;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.PlanNotFoundException;
import com.android.sched.scheduler.PlanPrinterFactory;
import com.android.sched.scheduler.ProcessException;
import com.android.sched.scheduler.ProductionSet;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.Scheduler;
import com.android.sched.scheduler.SubPlanBuilder;
import com.android.sched.scheduler.TagOrMarkerOrComponentSet;
import com.android.sched.util.RunnableHooks;
import com.android.sched.util.Version;
import com.android.sched.util.config.Config;
import com.android.sched.util.config.ConfigPrinterFactory;
import com.android.sched.util.config.ConfigurationException;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.ReflectFactory;
import com.android.sched.util.config.ThreadConfig;
import com.android.sched.util.config.id.BooleanPropertyId;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.ReflectFactoryPropertyId;
import com.android.sched.util.log.Event;
import com.android.sched.util.log.LoggerFactory;
import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
import com.android.sched.vfs.Container;
import org.antlr.runtime.RecognitionException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Executable class to run the jack compiler.
*/
@HasKeyId
public abstract class Jack {
@Nonnull
private static final Logger logger = LoggerFactory.getLogger();
@Nonnull
private static final TypePackageAndMethodFormatter lookupFormatter =
InternalFormatter.getFormatter();
@Nonnull
private static final TypePackageAndMethodFormatter userFriendlyFormatter =
UserFriendlyFormatter.getFormatter();
@Nonnull
public static final ObjectId<JSession> SESSION =
new ObjectId<JSession>("jack.session", JSession.class);
// Compilation configuration kept in a static field to avoid ThreadConfig overhead
@CheckForNull
private static UnmodifiableCollections unmodifiableCollections;
@Nonnull
private static final
ReflectFactoryPropertyId<JaycePackageLoader> CLASSPATH_POLICY =
ReflectFactoryPropertyId.create(
"jack.internal.jayce.loader.classpath.policy",
"Hint on default load policy for classpath entries",
JaycePackageLoader.class)
.addArgType(InputJackLibrary.class)
.addArgType(JPhantomLookup.class)
.bypassAccessibility()
.addDefaultValue("structure");
@Nonnull
private static final
ReflectFactoryPropertyId<JaycePackageLoader> IMPORT_POLICY = ReflectFactoryPropertyId.create(
"jack.internal.jayce.loader.import.policy",
"Hint on default load policy for import entries",
JaycePackageLoader.class)
.addArgType(InputJackLibrary.class)
.addArgType(JPhantomLookup.class)
.bypassAccessibility()
.addDefaultValue("type");
@Nonnull
public static final BooleanPropertyId STRICT_CLASSPATH = BooleanPropertyId.create(
"jack.classpath.strict", "Do not ignore missing or malformed class path entries")
.addDefaultValue(Boolean.FALSE);
@Nonnull
public static JSession getSession() {
return ThreadConfig.get(Jack.SESSION);
}
@Nonnull
public static String getEmitterId() {
return "jack";
}
@Nonnull
public static UnmodifiableCollections getUnmodifiableCollections() {
if (unmodifiableCollections == null) {
unmodifiableCollections =
ThreadConfig.get(UnmodifiableCollections.UNMODIFIABLE_COLLECTION).create();
}
assert unmodifiableCollections != null; // FINDBUGS
return unmodifiableCollections;
}
public static void checkAndRun(@Nonnull Options options)
throws IllegalOptionsException,
ConfigurationException,
JackUserException, ProcessException {
RunnableHooks hooks = new RunnableHooks();
try {
check(options, hooks);
run(options, hooks);
} finally {
hooks.runHooks();
}
}
public static void check(@Nonnull Options options, @Nonnull RunnableHooks hooks)
throws IllegalOptionsException, ConfigurationException {
if (options.proguardFlagsFiles != null && !options.proguardFlagsFiles.isEmpty()) {
if (options.flags == null) {
options.flags = new Flags();
}
for (File proguardFlagsFile : options.getProguardFlagsFile()) {
try {
assert options.flags != null;
GrammarActions.parse(proguardFlagsFile.getPath(), ".", options.flags);
} catch (RecognitionException e) {
throw new IllegalOptionsException(
"Error while parsing '" + e.input.getSourceName() + "':" + e.line, e);
}
}
options.applyShrobFlags();
}
options.checkValidity(hooks);
Config config = options.getConfig();
boolean sanityChecks = config.get(Options.SANITY_CHECKS).booleanValue();
logger.log(Level.INFO, "Jack sanity checks {0}",
(sanityChecks ? "enabled" : "disabled"));
}
/**
* Runs the jack compiler.
* @param options options for the compiler.
* @param hooks hooks that allow to attach actions that should be run after calling this method
* @throws JackUserException thrown to report information to the user
* @throws ProcessException thrown during schedulable execution
*/
public static void run(@Nonnull Options options, @Nonnull RunnableHooks hooks)
throws JackUserException, ProcessException {
Event event = null;
try {
Config config = options.getConfig();
ThreadConfig.setConfig(config);
event = TracerFactory.getTracer().start(JackEventType.JACK_RUN);
ConfigPrinterFactory.getConfigPrinter().printConfig(config);
JSession session = getSession();
try {
buildSession(session, options, hooks);
if (config.get(Options.GENERATE_JACK_LIBRARY).booleanValue()) {
session.setJackOutputLibrary(session.getInputFilter().getOutputJackLibrary());
}
Request request = createInitialRequest();
request.addFeature(PreProcessor.class);
request.addFeature(Resources.class);
JavaVersion sourceVersion = config.get(Options.JAVA_SOURCE_VERSION);
if (sourceVersion.compareTo(JavaVersion.JAVA_7) >= 0) {
request.addFeature(SourceVersion7.class);
}
if (config.get(Options.DROP_METHOD_BODY).booleanValue()) {
request.addFeature(DropMethodBody.class);
}
if (config.get(Options.ENABLE_COMPILED_FILES_STATISTICS).booleanValue()) {
request.addFeature(CompiledTypeStats.class);
request.addFeature(CodeStats.class);
}
if (config.get(Options.SANITY_CHECKS).booleanValue()) {
request.addFeature(SanityChecks.class);
}
if (config.get(PackageRenamer.JARJAR_ENABLED).booleanValue()) {
request.addFeature(Jarjar.class);
}
if (config.get(VisibilityBridgeAdder.VISIBILITY_BRIDGE).booleanValue()) {
request.addFeature(VisibilityBridge.class);
}
if (options.flags != null) {
if (options.flags.shrink()) {
request.addFeature(Shrinking.class);
}
if (options.flags.obfuscate()) {
request.addFeature(Obfuscation.class);
}
if (options.flags.printSeeds()) {
request.addProduction(SeedFile.class);
}
if (!options.flags.keepAttribute("EnclosingMethod")) {
request.addFeature(RemoveEnclosingMethod.class);
}
if (!options.flags.keepAttribute("InnerClasses")) {
request.addFeature(RemoveEnclosingType.class);
}
if (!options.flags.keepAttribute("Signature")) {
request.addFeature(RemoveGenericSignature.class);
}
if (!options.flags.keepAttribute("AnnotationDefault")) {
request.addFeature(RemoveAnnotationDefaultValue.class);
}
if (!options.flags.keepAttribute("LocalVariableTypeTable")) {
request.addFeature(RemoveLocalVariableGenericSignature.class);
}
if (!options.flags.keepAttribute("Exceptions")) {
request.addFeature(RemoveThrownException.class);
}
if (!options.flags.keepAttribute("SourceFile")) {
request.addFeature(RemoveSourceFile.class);
}
if (!options.flags.keepAttribute("LineNumberTable")) {
request.addFeature(RemoveLineNumber.class);
}
if (!options.flags.keepAttribute("LocalVariableTable")) {
request.addFeature(RemoveLocalVariableName.class);
if (!options.flags.getKeepParameterNames()) {
request.addFeature(RemoveParameterName.class);
}
}
if (options.flags.getRenameSourceFileAttribute() != null) {
request.addFeature(SourceFileRenaming.class);
}
if (options.flags.getAdaptResourceFileContents() != null) {
request.addFeature(AdaptResourceFileContent.class);
}
}
if (config.get(MappingPrinter.MAPPING_OUTPUT_ENABLED).booleanValue()) {
request.addProduction(Mapping.class);
}
if (config.get(ShrinkStructurePrinter.STRUCTURE_PRINTING).booleanValue()) {
request.addProduction(StructurePrinting.class);
}
if (config.get(MultiDexLegacy.MULTIDEX_LEGACY).booleanValue()) {
request.addFeature(MultiDexLegacy.class);
}
if (config.get(Options.INCREMENTAL_MODE).booleanValue()) {
request.addFeature(Incremental.class);
}
if (config.get(Options.GENERATE_LIBRARY_FROM_INCREMENTAL_FOLDER).booleanValue()) {
request.addFeature(GenerateLibraryFromIncrementalFolder.class);
}
request.addInitialTagsOrMarkers(getJavaSourceInitialTagSet());
request.addInitialTagsOrMarkers(getJackFormatInitialTagSet());
if (config.get(Options.GENERATE_DEX_IN_LIBRARY).booleanValue()) {
request.addProduction(DexInLibraryProduct.class);
}
if (config.get(Options.GENERATE_DEX_FILE).booleanValue()) {
request.addProduction(DexFileProduct.class);
session.addGeneratedFileType(FileType.DEX);
}
if (config.get(Options.GENERATE_JAYCE_IN_LIBRARY).booleanValue()) {
request.addProduction(JayceInLibraryProduct.class);
}
if (config.get(Options.GENERATE_DEPENDENCIES_IN_LIBRARY).booleanValue()) {
request.addProduction(DependencyInLibraryProduct.class);
}
if (config.get(TypeDefRemover.REMOVE_TYPEDEF).booleanValue()) {
request.addFeature(TypeDefRemover.RemoveTypeDef.class);
}
ProductionSet targetProduction = request.getTargetProductions();
FeatureSet features = request.getFeatures();
PlanBuilder<JSession> planBuilder;
try {
planBuilder = request.getPlanBuilder(JSession.class);
} catch (IllegalRequestException e) {
throw new AssertionError(e);
}
planBuilder.append(PreProcessorApplier.class);
fillDexPlan(planBuilder);
if (targetProduction.contains(DexFileProduct.class)) {
planBuilder.append(DexFileWriter.class);
}
if (features.contains(Resources.class)) {
if (targetProduction.contains(DexFileProduct.class)) {
planBuilder.append(ResourceWriter.class);
}
if (targetProduction.contains(JayceInLibraryProduct.class)) {
planBuilder.append(LibraryResourceWriter.class);
}
}
if (targetProduction.contains(JayceInLibraryProduct.class)) {
planBuilder.append(LibraryMetaWriter.class);
}
Plan<JSession> plan;
try {
// Try to build an automatic plan ...
try {
plan = request.buildPlan(JSession.class);
} catch (PlanNotFoundException e) {
throw new AssertionError(e);
} catch (IllegalRequestException e) {
throw new AssertionError(e);
}
} catch (UnsupportedOperationException e) {
// ... but use a manual one if not supported
plan = planBuilder.getPlan();
assert !targetProduction.contains(JayceInLibraryProduct.class)
|| targetProduction.contains(DexFileProduct.class) || (plan.computeFinalTagsOrMarkers(
request.getInitialTags()).contains(JackFormatIr.class)
&& !targetProduction.contains(DexInLibraryProduct.class)) || (
targetProduction.contains(DexInLibraryProduct.class)
&& targetProduction.contains(JayceInLibraryProduct.class));
}
PlanPrinterFactory.getPlanPrinter().printPlan(plan);
plan.getScheduleInstance().process(session);
} finally {
try {
if (session.getInputFilter() != null) {
session.getInputFilter().getOutputJackLibrary().close();
}
// TODO(jack-team): auto-close
if (config.get(Options.GENERATE_DEX_FILE).booleanValue()
&& config.get(Options.DEX_OUTPUT_CONTAINER_TYPE) == Container.ZIP) {
config.get(Options.DEX_OUTPUT_ZIP).close();
}
} catch (LibraryIOException e) {
throw new AssertionError(e);
} catch (IOException e) {
throw new AssertionError(e);
}
}
} finally {
if (event != null) {
event.end();
}
ThreadConfig.unsetConfig();
}
}
@Nonnull
public static Request createInitialRequest() {
Scheduler scheduler = Scheduler.getScheduler();
Request request = scheduler.createScheduleRequest();
request.addSchedulables(scheduler.getAllSchedulable());
return request;
}
@Nonnull
public static TagOrMarkerOrComponentSet getJavaSourceInitialTagSet() {
Scheduler scheduler = Scheduler.getScheduler();
TagOrMarkerOrComponentSet set = scheduler.createTagOrMarkerOrComponentSet();
set.add(JavaSourceIr.class);
set.add(OriginalNames.class);
set.add(SourceInfoCreation.class);
return set;
}
@Nonnull
private static TagOrMarkerOrComponentSet getJackFormatInitialTagSet() {
Scheduler scheduler = Scheduler.getScheduler();
TagOrMarkerOrComponentSet set = scheduler.createTagOrMarkerOrComponentSet();
set.add(JackFormatIr.class);
set.add(OriginalNames.class);
set.add(SourceInfoCreation.class);
return set;
}
@Nonnull
static JSession buildSession(@Nonnull Options options,
@Nonnull RunnableHooks hooks) throws JackUserException {
JSession session = getSession();
buildSession(session, options, hooks);
return session;
}
@Nonnull
private static void buildSession(@Nonnull JSession session, @Nonnull Options options,
@Nonnull RunnableHooks hooks) throws JackUserException {
Tracer tracer = TracerFactory.getTracer();
session.setHooks(hooks);
session.setReporter(ThreadConfig.get(Reporter.REPORTER));
Config config = ThreadConfig.getConfig();
try {
session.setInputFilter(config.get(Options.INPUT_FILTER).create(options));
} catch (RuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof JackAbortException) {
throw (JackAbortException) cause;
} else if (cause instanceof JackUserException) {
throw (JackUserException) cause;
} else {
throw e;
}
}
new MetaImporter(config.get(MetaImporter.IMPORTED_META)).doImport(session);
List<InputJackLibrary> inputJackLibraries = new ArrayList<InputJackLibrary>();
for (InputLibrary library : session.getInputFilter().getImportedLibrary()) {
if (library instanceof InputJackLibrary) {
addPackageLoaderForLibrary(session, config.get(IMPORT_POLICY),
(InputJackLibrary) library);
inputJackLibraries.add((InputJackLibrary) library);
session.addImportedLibrary(library);
}
}
JayceFileImporter jayceImporter = new JayceFileImporter(inputJackLibraries);
for (InputLibrary library : session.getInputFilter().getClasspath()) {
if (library instanceof InputJackLibrary) {
addPackageLoaderForLibrary(session, config.get(CLASSPATH_POLICY),
(InputJackLibrary) library);
session.addLibraryOnClasspath(library);
}
}
Set<String> fileNamesToCompile = session.getInputFilter().getFileNamesToCompile();
if (!fileNamesToCompile.isEmpty()) {
JackBatchCompiler jbc = new JackBatchCompiler(session);
Event event = tracer.start(JackEventType.ECJ_COMPILATION);
List<String> ecjExtraArguments = options.getEcjExtraArguments();
List<String> ecjArguments = new ArrayList<String>(
ecjExtraArguments.size() + fileNamesToCompile.size());
ecjArguments.addAll(ecjExtraArguments);
ecjArguments.addAll(fileNamesToCompile);
try {
if (!jbc.compile(ecjArguments.toArray(new String[ecjArguments.size()]))) {
throw new FrontendCompilationException("Failed to compile");
}
} catch (TransportExceptionAroundEcjError e) {
throw e.getCause();
} catch (TransportJUEAroundEcjError e) {
throw e.getCause();
} finally {
event.end();
}
}
try {
new ResourceImporter(config.get(ResourceImporter.IMPORTED_RESOURCES)).doImport(session);
} catch (ResourceReadingException e) {
session.getReporter().report(Severity.FATAL, e);
throw new JackAbortException(e);
}
try {
jayceImporter.doJayceImport(session);
jayceImporter.doResourceImport(session);
} catch (LibraryReadingException e) {
session.getReporter().report(Severity.FATAL, e);
throw new JackAbortException(e);
}
if (options.flags != null && (options.flags.shrink() || options.flags.obfuscate())) {
Event eventIdMerger = tracer.start(JackEventType.METHOD_ID_MERGER);
try {
JClass javaLangObject = session.getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
MethodIdMerger merger = new MethodIdMerger(javaLangObject);
for (JType type : session.getTypesToEmit()) {
merger.accept(type);
}
JVisitor remover = new VirtualMethodsMarker.Remover(javaLangObject);
for (JType type : session.getTypesToEmit()) {
remover.accept(type);
}
} finally {
eventIdMerger.end();
}
MethodIdDuplicateRemover methodIdDupRemover = new MethodIdDuplicateRemover();
methodIdDupRemover.accept(session.getTypesToEmit());
}
}
private static void addPackageLoaderForLibrary(JSession session,
ReflectFactory<JaycePackageLoader> factory, InputJackLibrary inputJackLibrary) {
if (inputJackLibrary.containsFileType(FileType.JAYCE)) {
JaycePackageLoader rootPLoader =
factory.create(inputJackLibrary, session.getPhantomLookup());
session.getTopLevelPackage().addLoader(rootPLoader);
}
}
private static void appendMultiDexAndShrobStartPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
ProductionSet productions = planBuilder.getRequest().getTargetProductions();
FeatureSet features = planBuilder.getRequest().getFeatures();
boolean isShrinking = features.contains(Shrinking.class);
boolean isMultiDexWithConstraints = features.contains(MultiDexLegacy.class);
if (!(isShrinking || features.contains(Obfuscation.class)
|| isMultiDexWithConstraints || productions.contains(SeedFile.class))) {
// nothing to do
return;
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (isShrinking || features.contains(Obfuscation.class)
|| productions.contains(SeedFile.class)) {
typePlan.append(SeedFinder.class);
if (productions.contains(SeedFile.class)) {
planBuilder.append(SeedPrinter.class);
}
}
if (isMultiDexWithConstraints) {
typePlan.append(MultiDexAnnotationsFinder.class);
typePlan.append(RuntimeAnnotationFinder.class);
typePlan.append(AnnotatedFinder.class);
}
if (isMultiDexWithConstraints || isShrinking) {
typePlan.append(ExtendingOrImplementingClassFinder.class);
}
}
if (isShrinking) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
Request request = planBuilder.getRequest();
if (isMultiDexWithConstraints &&
request.getTargetProductions().contains(DexFileProduct.class)) {
typePlan.append(ShrinkAndMainDexTracer.class);
} else {
typePlan.append(Keeper.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeShrinker.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodShrinker.class);
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldShrinker.class);
}
}
} else if (isMultiDexWithConstraints) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(MainDexTracer.class);
}
if (isMultiDexWithConstraints) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(MainDexCollector.class);
}
}
private static void appendStringRefiners(@Nonnull PlanBuilder<JSession> planBuilder) {
FeatureSet features = planBuilder.getRequest().getFeatures();
boolean isShrinking = features.contains(Shrinking.class);
if (isShrinking || features.contains(Obfuscation.class) || features.contains(Jarjar.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeGenericSignatureSplitter.class);
typePlan.append(TypeStringLiteralRefiner.class);
typePlan.append(SimpleNameRefiner.class);
{
SubPlanBuilder<JMethod> methodPlan =
typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodGenericSignatureSplitter.class);
methodPlan.append(ReflectionStringLiteralRefiner.class);
methodPlan.append(MethodStringLiteralRefiner.class);
}
{
SubPlanBuilder<JField> fieldPlan =
typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldGenericSignatureSplitter.class);
fieldPlan.append(FieldStringLiteralRefiner.class);
}
}
}
static void fillDexPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
FeatureSet features = planBuilder.getRequest().getFeatures();
ProductionSet productions = planBuilder.getRequest().getTargetProductions();
boolean hasSanityChecks = features.contains(SanityChecks.class);
// TODO(jack-team): Remove this hack
boolean preDexing = !getSession().getImportedLibraries().isEmpty();
for (InputLibrary il : getSession().getImportedLibraries()) {
if (!il.containsFileType(FileType.DEX)) {
preDexing = false;
}
}
if (features.contains(Jarjar.class) || features.contains(Obfuscation.class)
|| features.contains(Shrinking.class)) {
for (InputLibrary il : getSession().getImportedLibraries()) {
((InputJackLibrary) il).fileTypes.remove(FileType.DEX);
}
}
logger.log(Level.INFO, "Jack pre-dexing is " + (preDexing ? "enabled" : "disabled"));
// Build the plan
if (hasSanityChecks) {
planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(RemoveTypeDef.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeDefRemover.class);
}
appendStringRefiners(planBuilder);
if (features.contains(Jarjar.class)) {
planBuilder.append(PackageRenamer.class);
}
if (hasSanityChecks) {
planBuilder.append(AstChecker.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
if (features.contains(CompiledTypeStats.class)) {
methodPlan.append(MethodStats.class);
}
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
if (features.contains(CompiledTypeStats.class)) {
fieldPlan.append(FieldStats.class);
}
fieldPlan.append(FieldInitializerRemover.class);
}
}
appendMultiDexAndShrobStartPlan(planBuilder);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
typePlan.append(UsedEnumFieldCollector.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan2 =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
{
if (features.contains(VisibilityBridge.class)) {
typePlan2.append(VisibilityBridgeAdder.class);
}
SubPlanBuilder<JMethod> methodPlan =
typePlan2.appendSubPlan(JMethodAdapter.class);
methodPlan.append(NotSimplifier.class);
methodPlan.append(AssertionTransformer.class);
if (features.contains(SourceVersion7.class)) {
methodPlan.append(TryWithResourcesTransformer.class);
}
}
}
planBuilder.append(AssertionTransformerSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
{
{
SubPlanBuilder<JField> fieldPlan =
typePlan3.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldInitializer.class);
}
{
SubPlanBuilder<JMethod> methodPlan2 =
typePlan3.appendSubPlan(JMethodAdapter.class);
methodPlan2.append(ImplicitBlocks.class);
if (hasSanityChecks) {
methodPlan2.append(ImplicitBlocksChecker.class);
}
if (hasSanityChecks) {
methodPlan2.append(UselessIfChecker.class);
}
methodPlan2.append(IncDecRemover.class);
methodPlan2.append(CompoundAssignmentRemover.class);
methodPlan2.append(ConcatRemover.class);
}
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
typePlan.append(InnerAccessorGenerator.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(SwitchEnumSupport.class);
}
planBuilder.append(InnerAccessorSchedulingSeparator.class);
planBuilder.append(TryStatementSchedulingSeparator.class);
planBuilder.append(EnumMappingSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
typePlan4.append(InnerAccessorAdder.class);
typePlan4.append(UsedEnumFieldMarkerRemover.class);
{
SubPlanBuilder<JMethod> methodPlan =
typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan.append(FlowNormalizer.class);
if (features.contains(SourceVersion7.class)) {
methodPlan.append(SwitchStringSupport.class);
}
methodPlan.append(EnumMappingMarkerRemover.class);
methodPlan.append(EmptyClinitRemover.class);
}
typePlan4.append(FlowNormalizerSchedulingSeparator.class);
{
SubPlanBuilder<JMethod> methodPlan3 =
typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan3.append(FieldInitMethodCallRemover.class);
}
typePlan4.append(FieldInitMethodRemover.class);
}
if (features.contains(Obfuscation.class)) {
appendObfuscationPlan(planBuilder, features);
} else {
planBuilder.append(NameFinalizer.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan;
// Jayce files must be copied into output library in incremental library mode or in non
// incremental mode
if (features.contains(GenerateLibraryFromIncrementalFolder.class)
|| !features.contains(Incremental.class)) {
typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
} else {
typePlan = planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
}
if (productions.contains(JayceInLibraryProduct.class)) {
typePlan.append(JayceInLibraryWriter.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibAdapter.class);
if (productions.contains(DependencyInLibraryProduct.class)) {
typePlan.append(TypeDependenciesCollector.class);
typePlan.append(FileDependenciesCollector.class);
}
}
if (features.contains(SourceFileRenaming.class)) {
planBuilder.append(SourceFileRenamer.class);
}
{
// After this point {@link JDcoiExcludeJackFileAdapter} must not be used since
// schedulables are not executed into the Java to Jayce plan.
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan.append(ConditionalAndOrRemover.class);
if (hasSanityChecks) {
methodPlan.append(ConditionalAndOrRemoverChecker.class);
}
methodPlan.append(BooleanTestTransformer.class);
methodPlan.append(SplitNewInstance.class);
if (hasSanityChecks) {
methodPlan.append(SplitNewInstanceChecker.class);
}
methodPlan.append(MultiDimensionNewArrayRemover.class);
methodPlan.append(InitInNewArrayRemover.class);
methodPlan.append(PrimitiveClassTransformer.class);
methodPlan.append(SynchronizeTransformer.class);
methodPlan.append(NestedAssignRemover.class);
methodPlan.append(TypeLegalizer.class);
methodPlan.append(RopCastLegalizer.class);
if (features.contains(CodeStats.class)) {
methodPlan.append(BinaryOperationWithCst.class);
}
methodPlan.append(UselessCaseRemover.class);
methodPlan.append(UselessSwitchesRemover.class);
if (hasSanityChecks) {
methodPlan.append(UselessCaseChecker.class);
}
methodPlan.append(FinallyRemover.class);
methodPlan.append(ExceptionRuntimeValueAdder.class);
methodPlan.append(DefinitionMarkerAdder.class);
methodPlan.append(ThreeAddressCodeBuilder.class);
methodPlan.append(UselessCastRemover.class);
methodPlan.append(DefinitionMarkerRemover.class);
methodPlan.append(TryCatchRemover.class);
methodPlan.append(ExpressionStatementLegalizer.class);
if (hasSanityChecks) {
methodPlan.append(NumericConversionChecker.class);
}
}
}
if (productions.contains(DependencyInLibraryProduct.class)) {
planBuilder.append(TypeDependenciesInLibraryWriter.class);
planBuilder.append(FileDependenciesInLibraryWriter.class);
planBuilder.append(LibraryDependenciesInLibraryWriter.class);
}
if (productions.contains(Mapping.class)) {
planBuilder.append(MappingPrinter.class);
}
if (productions.contains(StructurePrinting.class)) {
planBuilder.append(ShrinkStructurePrinter.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
typePlan.append(ReflectAnnotationsAdder.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(DefaultValueAnnotationAdder.class);
}
}
planBuilder.append(ClassAnnotationSchedulingSeparator.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
typePlan.append(ClassDefItemBuilder.class);
typePlan.append(ClassAnnotationBuilder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan5 =
planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
{
SubPlanBuilder<JMethod> methodPlan4 =
typePlan5.appendSubPlan(JMethodAdapter.class);
methodPlan4.append(RefAsStatementRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(DefinitionMarkerAdder.class);
methodPlan4.append(ReachingDefinitions.class);
methodPlan4.append(UsedVariableAdder.class);
methodPlan4.append(DefUsesAndUseDefsChainComputation.class);
if (hasSanityChecks) {
methodPlan4.append(UseDefsChecker.class);
}
methodPlan4.append(ConstantRefinerAndVariableRemover.class);
methodPlan4.append(UseDefsChainsSimplifier.class);
methodPlan4.append(DefUsesChainsSimplifier.class);
// Instructions are removed by DefUsesChainsSimplifier thus rebuild the cfg.
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(UnusedDefinitionRemover.class);
methodPlan4.append(RefAsStatementRemover.class);
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(IfWithConstantSimplifier.class);
methodPlan4.append(UnusedLocalRemover.class);
methodPlan4.append(DefUsesAndUseDefsChainRemover.class);
methodPlan4.append(DefinitionMarkerRemover.class);
methodPlan4.append(UsedVariableRemover.class);
methodPlan4.append(ReachingDefinitionsRemover.class);
methodPlan4.append(ExpressionSimplifier.class);
methodPlan4.append(UselessIfRemover.class);
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(CodeItemBuilder.class);
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(EncodedMethodBuilder.class);
methodPlan4.append(MethodAnnotationBuilder.class);
if (features.contains(DropMethodBody.class)) {
methodPlan4.append(MethodBodyRemover.class);
}
{
SubPlanBuilder<JField> fieldPlan2 =
typePlan5.appendSubPlan(JFieldAdapter.class);
fieldPlan2.append(EncodedFieldBuilder.class);
fieldPlan2.append(FieldAnnotationBuilder.class);
}
}
if (hasSanityChecks) {
typePlan5.append(TypeAstChecker.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan;
// Jayce files must be copied into output library in incremental library mode or in non
// incremental mode
if (features.contains(GenerateLibraryFromIncrementalFolder.class)
|| !features.contains(Incremental.class)) {
typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
} else {
typePlan = planBuilder.appendSubPlan(ExcludeTypeFromLibWithBinaryAdapter.class);
}
if (productions.contains(DexInLibraryProduct.class)) {
typePlan.append(DexInLibraryWriter.class);
}
}
if (hasSanityChecks) {
planBuilder.append(AstChecker.class);
}
}
private static void appendObfuscationPlan(@Nonnull PlanBuilder<JSession> planBuilder,
@Nonnull FeatureSet features) {
{
SubPlanBuilder<JPackage> packagePlan = planBuilder.appendSubPlan(JPackageAdapter.class);
packagePlan.append(NameKeeper.class);
}
planBuilder.append(ResourceRefiner.class);
if (features.contains(AdaptResourceFileContent.class)) {
planBuilder.append(ResourceContentRefiner.class);
}
planBuilder.append(Renamer.class);
if (features.contains(RemoveSourceFile.class)) {
planBuilder.append(SourceFileRemover.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeAnnotationRemover.class);
if (features.contains(RemoveEnclosingMethod.class)) {
typePlan.append(TypeEnclosingMethodRemover.class);
}
if (features.contains(RemoveEnclosingType.class)) {
typePlan.append(TypeEnclosingTypeRemover.class);
}
if (features.contains(RemoveGenericSignature.class)) {
typePlan.append(TypeGenericSignatureRemover.class);
}
if (features.contains(RemoveLineNumber.class)) {
typePlan.append(LineNumberRemover.class);
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldAnnotationRemover.class);
if (features.contains(RemoveGenericSignature.class)) {
fieldPlan.append(FieldGenericSignatureRemover.class);
}
}
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodAnnotationRemover.class);
methodPlan.append(ParameterAnnotationRemover.class);
if (features.contains(RemoveGenericSignature.class)) {
methodPlan.append(MethodGenericSignatureRemover.class);
}
if (features.contains(RemoveLocalVariableGenericSignature.class)) {
methodPlan.append(LocalVariableGenericSignatureRemover.class);
}
if (features.contains(RemoveAnnotationDefaultValue.class)) {
methodPlan.append(AnnotationDefaultValueRemover.class);
}
if (features.contains(RemoveThrownException.class)) {
methodPlan.append(ThrownExceptionRemover.class);
}
if (features.contains(RemoveParameterName.class)) {
methodPlan.append(ParameterNameRemover.class);
}
if (features.contains(RemoveLocalVariableName.class)) {
methodPlan.append(LocalVariableNameRemover.class);
}
}
}
}
@CheckForNull
private static Version version = null;
@Nonnull
public static Version getVersion() {
if (version == null) {
try {
version = new Version("jack", Jack.class.getClassLoader());
} catch (IOException e) {
logger.log(Level.SEVERE, "Failed to open Jack version file", e);
throw new AssertionError();
}
}
assert version != null;
return version;
}
@Nonnull
public static TypePackageAndMethodFormatter getLookupFormatter() {
return lookupFormatter;
}
@Nonnull
public static TypePackageAndMethodFormatter getUserFriendlyFormatter() {
return userFriendlyFormatter;
}
}