blob: fd2c110859ef09524e6e4eba4452ffe80895321e [file] [log] [blame]
// Copyright (c) 2016, 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.graph;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Collections;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class DexField extends DexMember<DexEncodedField, DexField> {
public final DexType type;
DexField(DexType holder, DexType type, DexString name, boolean skipNameValidationForTesting) {
super(holder, name);
this.type = type;
if (!skipNameValidationForTesting && !name.isValidFieldName()) {
throw new CompilationError(
"Field name '" + name.toString() + "' cannot be represented in dex format.");
}
}
private static void specify(StructuralSpecification<DexField, ?> spec) {
spec.withItem(DexField::getHolderType).withItem(DexField::getName).withItem(DexField::getType);
}
@Override
public int compareTo(DexReference other) {
if (other.isDexField()) {
return compareTo(other.asDexField());
}
if (other.isDexMethod()) {
int comparisonResult = getHolderType().compareTo(other.getContextType());
return comparisonResult != 0 ? comparisonResult : -1;
}
int comparisonResult = getHolderType().compareTo(other.asDexType());
return comparisonResult != 0 ? comparisonResult : 1;
}
@Override
public DexField self() {
return this;
}
@Override
public StructuralMapping<DexField> getStructuralMapping() {
return DexField::specify;
}
public DexType getType() {
return type;
}
public TypeElement getTypeElement(AppView<?> appView) {
return TypeElement.fromDexType(getType(), maybeNull(), appView);
}
@Override
public DexEncodedField lookupOnClass(DexClass clazz) {
return clazz != null ? clazz.lookupField(this) : null;
}
@Override
public DexClassAndField lookupMemberOnClass(DexClass clazz) {
return clazz != null ? clazz.lookupClassField(this) : null;
}
@Override
public ProgramField lookupOnProgramClass(DexProgramClass clazz) {
return clazz != null ? clazz.lookupProgramField(this) : null;
}
@Override
public <T> T apply(Function<DexField, T> fieldConsumer, Function<DexMethod, T> methodConsumer) {
return fieldConsumer.apply(this);
}
@Override
public <T> T apply(
Function<DexType, T> classConsumer,
Function<DexField, T> fieldConsumer,
Function<DexMethod, T> methodConsumer) {
return fieldConsumer.apply(this);
}
@Override
public void accept(
Consumer<DexType> classConsumer,
Consumer<DexField> fieldConsumer,
Consumer<DexMethod> methodConsumer) {
fieldConsumer.accept(this);
}
@Override
public <T> void accept(
BiConsumer<DexType, T> classConsumer,
BiConsumer<DexField, T> fieldConsumer,
BiConsumer<DexMethod, T> methodConsumer,
T arg) {
fieldConsumer.accept(this, arg);
}
@Override
public int computeHashCode() {
return holder.hashCode()
+ type.hashCode() * 7
+ name.hashCode() * 31;
}
@Override
public boolean computeEquals(Object other) {
if (other instanceof DexField) {
DexField o = (DexField) other;
return holder.equals(o.holder)
&& type.equals(o.type)
&& name.equals(o.name);
}
return false;
}
@Override
public String toString() {
return "Field " + type + " " + holder + "." + name;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems) {
if (indexedItems.addField(this)) {
holder.collectIndexedItems(indexedItems);
type.collectIndexedItems(indexedItems);
indexedItems.getRenamedName(this).collectIndexedItems(indexedItems);
}
}
@Override
public int getOffset(ObjectToOffsetMapping mapping) {
return mapping.getOffsetFor(this);
}
@Override
public boolean isDexField() {
return true;
}
@Override
public DexField asDexField() {
return this;
}
@Override
public Iterable<DexType> getReferencedTypes() {
return Collections.singleton(type);
}
@Override
public int acceptCompareTo(DexField other, CompareToVisitor visitor) {
return visitor.visitDexField(this, other);
}
@Override
public boolean match(DexField field) {
return field.name == name && field.type == type;
}
@Override
public boolean match(DexEncodedField encodedField) {
return match(encodedField.getReference());
}
public String qualifiedName() {
return holder + "." + name;
}
@Override
public String toSmaliString() {
return holder.toSmaliString() + "->" + name + ":" + type.toSmaliString();
}
@Override
public String toSourceString() {
return type.toSourceString() + " " + holder.toSourceString() + "." + name.toSourceString();
}
public DexField withHolder(DexType holder, DexItemFactory dexItemFactory) {
return dexItemFactory.createField(holder, type, name);
}
public DexField withName(DexString name, DexItemFactory dexItemFactory) {
return dexItemFactory.createField(holder, type, name);
}
public DexField withType(DexType type, DexItemFactory dexItemFactory) {
return dexItemFactory.createField(holder, type, name);
}
public FieldReference asFieldReference() {
return Reference.field(
Reference.classFromDescriptor(holder.toDescriptorString()),
name.toString(),
Reference.typeFromDescriptor(type.toDescriptorString()));
}
}