blob: 65c510c836fb2acdc0922a2b98a1151ff4055a5c [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.synthesis;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
public abstract class SyntheticClassBuilder<
B extends SyntheticClassBuilder<B, C>, C extends DexClass> {
private final DexItemFactory factory;
private final DexType type;
private final SyntheticKind syntheticKind;
private final Origin origin;
private boolean isAbstract = false;
private boolean isInterface = false;
private Kind originKind;
private DexType superType;
private DexTypeList interfaces = DexTypeList.empty();
private DexString sourceFile = null;
private List<DexEncodedField> staticFields = new ArrayList<>();
private List<DexEncodedField> instanceFields = new ArrayList<>();
private List<DexEncodedMethod> directMethods = new ArrayList<>();
private List<DexEncodedMethod> virtualMethods = new ArrayList<>();
private List<SyntheticMethodBuilder> methods = new ArrayList<>();
private ClassSignature signature = ClassSignature.noSignature();
SyntheticClassBuilder(
DexType type,
SyntheticKind syntheticKind,
SynthesizingContext context,
DexItemFactory factory) {
this.factory = factory;
this.type = type;
this.syntheticKind = syntheticKind;
this.origin = context.getInputContextOrigin();
this.superType = factory.objectType;
}
public abstract B self();
public abstract ClassKind<C> getClassKind();
public DexItemFactory getFactory() {
return factory;
}
public DexType getType() {
return type;
}
public SyntheticKind getSyntheticKind() {
return syntheticKind;
}
public B setInterfaces(List<DexType> interfaces) {
this.interfaces =
interfaces.isEmpty()
? DexTypeList.empty()
: new DexTypeList(interfaces.toArray(DexType.EMPTY_ARRAY));
return self();
}
public B setAbstract() {
isAbstract = true;
return self();
}
public B setInterface() {
setAbstract();
isInterface = true;
return self();
}
public B setOriginKind(Kind originKind) {
this.originKind = originKind;
return self();
}
public B setSourceFile(DexString sourceFile) {
this.sourceFile = sourceFile;
return self();
}
public B setGenericSignature(ClassSignature signature) {
this.signature = signature;
return self();
}
public B setStaticFields(List<DexEncodedField> fields) {
staticFields.clear();
staticFields.addAll(fields);
return self();
}
public B setInstanceFields(List<DexEncodedField> fields) {
instanceFields.clear();
instanceFields.addAll(fields);
return self();
}
public B setDirectMethods(Iterable<DexEncodedMethod> methods) {
directMethods.clear();
methods.forEach(directMethods::add);
return self();
}
public B setVirtualMethods(Iterable<DexEncodedMethod> methods) {
virtualMethods.clear();
methods.forEach(virtualMethods::add);
return self();
}
public B addMethod(Consumer<SyntheticMethodBuilder> fn) {
SyntheticMethodBuilder method = new SyntheticMethodBuilder(this);
fn.accept(method);
methods.add(method);
return self();
}
public C build() {
int flag = isAbstract ? Constants.ACC_ABSTRACT : Constants.ACC_FINAL;
int itfFlag = isInterface ? Constants.ACC_INTERFACE : 0;
assert !isInterface || isAbstract;
ClassAccessFlags accessFlags =
ClassAccessFlags.fromSharedAccessFlags(
flag | itfFlag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
NestHostClassAttribute nestHost = null;
List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
EnclosingMethodAttribute enclosingMembers = null;
List<InnerClassAttribute> innerClasses = Collections.emptyList();
for (SyntheticMethodBuilder builder : methods) {
DexEncodedMethod method = builder.build();
if (method.isNonPrivateVirtualMethod()) {
virtualMethods.add(method);
} else {
directMethods.add(method);
}
}
long checksum =
7 * (long) directMethods.hashCode()
+ 11 * (long) virtualMethods.hashCode()
+ 13 * (long) staticFields.hashCode()
+ 17 * (long) instanceFields.hashCode();
return getClassKind()
.create(
type,
originKind,
origin,
accessFlags,
superType,
interfaces,
sourceFile,
nestHost,
nestMembers,
enclosingMembers,
innerClasses,
signature,
DexAnnotationSet.empty(),
staticFields.toArray(DexEncodedField.EMPTY_ARRAY),
instanceFields.toArray(DexEncodedField.EMPTY_ARRAY),
directMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
virtualMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
factory.getSkipNameValidationForTesting(),
c -> checksum,
null);
}
}