blob: fbedd8ea62a1fcf07e5eeabbfff5884c0513f792 [file] [log] [blame]
// Copyright (c) 2017, 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.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.StreamSupport;
public abstract class ProguardConfigurationRule extends ProguardClassSpecification {
private boolean used = false;
// TODO(b/164019179): Since we are using the rule language for tracing main dex we can end up in
// a situation where the references to types are dead.
private boolean canReferenceDeadTypes = false;
ProguardConfigurationRule(
Origin origin,
Position position,
String source,
List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
super(
origin,
position,
source,
classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
}
public boolean isUsed() {
return used;
}
public void markAsUsed() {
used = true;
}
public boolean isProguardKeepRule() {
return false;
}
public ProguardKeepRule asProguardKeepRule() {
return null;
}
public boolean isProguardIfRule() {
return false;
}
public ProguardIfRule asProguardIfRule() {
return null;
}
public boolean isClassInlineRule() {
return false;
}
public ClassInlineRule asClassInlineRule() {
return null;
}
public boolean isReprocessClassInitializerRule() {
return false;
}
public ReprocessClassInitializerRule asReprocessClassInitializerRule() {
return null;
}
public boolean isReprocessMethodRule() {
return false;
}
public ReprocessMethodRule asReprocessMethodRule() {
return null;
}
public void canReferenceDeadTypes() {
this.canReferenceDeadTypes = true;
}
Iterable<DexProgramClass> relevantCandidatesForRule(
AppView<? extends AppInfoWithClassHierarchy> appView,
SubtypingInfo subtypingInfo,
Iterable<DexProgramClass> defaultValue) {
List<DexType> specificTypes = getClassNames().asSpecificDexTypes();
if (specificTypes != null) {
return DexProgramClass.asProgramClasses(
specificTypes,
new DexDefinitionSupplier() {
@Override
public DexClass definitionFor(DexType type) {
if (canReferenceDeadTypes) {
return appView.appInfo().definitionForWithoutExistenceAssert(type);
}
return appView.definitionFor(type);
}
@Override
public DexItemFactory dexItemFactory() {
return appView.dexItemFactory();
}
});
}
if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
DexType type = getInheritanceClassName().getSpecificType();
if (appView.verticallyMergedClasses() != null
&& appView.verticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
DexType target = appView.verticallyMergedClasses().getTargetFor(type);
DexClass clazz = appView.definitionFor(target);
assert clazz != null && clazz.isProgramClass();
return Iterables.concat(
ImmutableList.of(clazz.asProgramClass()),
DexProgramClass.asProgramClasses(subtypingInfo.subtypes(type), appView));
} else {
return DexProgramClass.asProgramClasses(subtypingInfo.subtypes(type), appView);
}
}
return defaultValue;
}
abstract String typeString();
String modifierString() {
return null;
}
public boolean applyToNonProgramClasses() {
return false;
}
protected Iterable<ProguardWildcard> getWildcards() {
List<ProguardMemberRule> memberRules = getMemberRules();
return Iterables.concat(
ProguardTypeMatcher.getWildcardsOrEmpty(getClassAnnotations()),
ProguardClassNameList.getWildcardsOrEmpty(getClassNames()),
ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceAnnotations()),
ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceClassName()),
memberRules != null
? memberRules.stream()
.map(ProguardMemberRule::getWildcards)
.flatMap(it -> StreamSupport.stream(it.spliterator(), false))
::iterator
: Collections::emptyIterator);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ProguardConfigurationRule)) {
return false;
}
ProguardConfigurationRule that = (ProguardConfigurationRule) o;
if (used != that.used) {
return false;
}
if (!Objects.equals(typeString(), that.typeString())) {
return false;
}
if (!Objects.equals(modifierString(), that.modifierString())) {
return false;
}
return super.equals(that);
}
@Override
public int hashCode() {
int result = 3 * typeString().hashCode();
result = 3 * result + (used ? 1 : 0);
String modifier = modifierString();
result = 3 * result + (modifier != null ? modifier.hashCode() : 0);
return result + super.hashCode();
}
@Override
protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
builder.append("-");
builder.append(typeString());
StringUtils.appendNonEmpty(builder, ",", modifierString(), null);
builder.append(' ');
super.append(builder, includeMemberRules);
return builder;
}
}