| // Copyright (c) 2018, 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.shaking; |
| |
| import com.android.tools.r8.graph.AppInfo; |
| import com.android.tools.r8.graph.DexClass; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Sets; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Set; |
| import java.util.function.Consumer; |
| import java.util.function.Predicate; |
| |
| public class MainDexClasses { |
| |
| public static MainDexClasses NONE = new MainDexClasses(ImmutableSet.of(), ImmutableSet.of()); |
| |
| public static class Builder { |
| public final AppInfo appInfo; |
| public final Set<DexType> roots = Sets.newIdentityHashSet(); |
| public final Set<DexType> dependencies = Sets.newIdentityHashSet(); |
| |
| private Builder(AppInfo appInfo) { |
| this.appInfo = appInfo; |
| } |
| |
| public Builder addRoot(DexType type) { |
| assert isProgramClass(type) : type.toSourceString(); |
| roots.add(type); |
| return this; |
| } |
| |
| public Builder addRoots(Collection<DexType> rootSet) { |
| assert rootSet.stream().allMatch(this::isProgramClass); |
| this.roots.addAll(rootSet); |
| return this; |
| } |
| |
| public Builder addDependency(DexType type) { |
| assert isProgramClass(type); |
| dependencies.add(type); |
| return this; |
| } |
| |
| public boolean contains(DexType type) { |
| return roots.contains(type) || dependencies.contains(type); |
| } |
| |
| public MainDexClasses build() { |
| return new MainDexClasses(roots, dependencies); |
| } |
| |
| private boolean isProgramClass(DexType dexType) { |
| DexClass clazz = appInfo.definitionFor(dexType); |
| return clazz != null && clazz.isProgramClass(); |
| } |
| } |
| |
| // The classes in the root set. |
| private final Set<DexType> roots; |
| // Additional dependencies (direct dependencies and runtime annotations with enums). |
| private final Set<DexType> dependencies; |
| // All main dex classes. |
| private final Set<DexType> classes; |
| |
| private MainDexClasses(Set<DexType> roots, Set<DexType> dependencies) { |
| assert Sets.intersection(roots, dependencies).isEmpty(); |
| this.roots = Collections.unmodifiableSet(roots); |
| this.dependencies = Collections.unmodifiableSet(dependencies); |
| this.classes = Sets.union(roots, dependencies); |
| } |
| |
| public boolean isEmpty() { |
| assert !roots.isEmpty() || dependencies.isEmpty(); |
| return roots.isEmpty(); |
| } |
| |
| public Set<DexType> getRoots() { |
| return roots; |
| } |
| |
| public Set<DexType> getDependencies() { |
| return dependencies; |
| } |
| |
| public Set<DexType> getClasses() { |
| return classes; |
| } |
| |
| private void collectTypesMatching( |
| Set<DexType> types, Predicate<DexType> predicate, Consumer<DexType> consumer) { |
| types.forEach( |
| type -> { |
| if (predicate.test(type)) { |
| consumer.accept(type); |
| } |
| }); |
| } |
| |
| public MainDexClasses prunedCopy(AppInfoWithLiveness appInfo) { |
| Builder builder = builder(appInfo); |
| Predicate<DexType> wasPruned = appInfo::wasPruned; |
| collectTypesMatching(roots, wasPruned.negate(), builder::addRoot); |
| collectTypesMatching(dependencies, wasPruned.negate(), builder::addDependency); |
| return builder.build(); |
| } |
| |
| public static Builder builder(AppInfo appInfo) { |
| return new Builder(appInfo); |
| } |
| } |