blob: 1091d0938ca02940ea1d374d270eb2db43ef3ead [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.DexAnnotationSet;
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.DexProgramClass;
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.InnerClassAttribute;
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.origin.Origin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
public class SyntheticClassBuilder {
private final DexItemFactory factory;
private final DexType type;
private final Origin origin;
private DexType superType;
private DexTypeList interfaces = DexTypeList.empty();
private int nextMethodId = 0;
private List<SyntheticMethodBuilder> methods = new ArrayList<>();
SyntheticClassBuilder(DexType type, SynthesizingContext context, DexItemFactory factory) {
this.factory = factory;
this.type = type;
this.origin = context.getInputContextOrigin();
this.superType = factory.objectType;
}
public DexItemFactory getFactory() {
return factory;
}
public DexType getType() {
return type;
}
private String getNextMethodName() {
return SyntheticItems.INTERNAL_SYNTHETIC_METHOD_PREFIX + nextMethodId++;
}
public SyntheticClassBuilder addMethod(Consumer<SyntheticMethodBuilder> fn) {
SyntheticMethodBuilder method = new SyntheticMethodBuilder(this, getNextMethodName());
fn.accept(method);
methods.add(method);
return this;
}
DexProgramClass build() {
ClassAccessFlags accessFlags =
ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
Kind originKind = null;
DexString sourceFile = null;
NestHostClassAttribute nestHost = null;
List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
EnclosingMethodAttribute enclosingMembers = null;
List<InnerClassAttribute> innerClasses = Collections.emptyList();
DexAnnotationSet classAnnotations = DexAnnotationSet.empty();
DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;
DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;
DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;
DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
assert !methods.isEmpty();
List<DexEncodedMethod> directs = new ArrayList<>(methods.size());
List<DexEncodedMethod> virtuals = new ArrayList<>(methods.size());
for (SyntheticMethodBuilder builder : methods) {
DexEncodedMethod method = builder.build();
if (method.isNonPrivateVirtualMethod()) {
virtuals.add(method);
} else {
directs.add(method);
}
}
if (!directs.isEmpty()) {
directMethods = directs.toArray(new DexEncodedMethod[directs.size()]);
}
if (!virtuals.isEmpty()) {
virtualMethods = virtuals.toArray(new DexEncodedMethod[virtuals.size()]);
}
long checksum = 7 * (long) directs.hashCode() + 11 * (long) virtuals.hashCode();
return new DexProgramClass(
type,
originKind,
origin,
accessFlags,
superType,
interfaces,
sourceFile,
nestHost,
nestMembers,
enclosingMembers,
innerClasses,
classAnnotations,
staticFields,
instanceFields,
directMethods,
virtualMethods,
factory.getSkipNameValidationForTesting(),
c -> checksum);
}
}