blob: c4affd36e07c76a93c203274f78db3b2f76d42ef [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 com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
import com.android.tools.r8.origin.Origin;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class DexLibraryClass extends DexClass implements LibraryClass, Supplier<DexLibraryClass> {
public DexLibraryClass(
DexType type,
ProgramResource.Kind kind,
Origin origin,
ClassAccessFlags accessFlags,
DexType superType,
DexTypeList interfaces,
DexString sourceFile,
NestHostClassAttribute nestHost,
List<NestMemberClassAttribute> nestMembers,
EnclosingMethodAttribute enclosingMember,
List<InnerClassAttribute> innerClasses,
ClassSignature classSignature,
DexAnnotationSet annotations,
DexEncodedField[] staticFields,
DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods,
boolean skipNameValidationForTesting) {
super(
sourceFile,
interfaces,
accessFlags,
superType,
type,
staticFields,
instanceFields,
directMethods,
virtualMethods,
nestHost,
nestMembers,
enclosingMember,
innerClasses,
classSignature,
annotations,
origin,
skipNameValidationForTesting);
assert Arrays.stream(directMethods).allMatch(DexLibraryClass::verifyLibraryMethod);
assert Arrays.stream(virtualMethods).allMatch(DexLibraryClass::verifyLibraryMethod);
assert Arrays.stream(staticFields).allMatch(DexLibraryClass::verifyLibraryField);
assert Arrays.stream(instanceFields).allMatch(DexLibraryClass::verifyLibraryField);
// Set all static field values to unknown. We don't want to use the value from the library
// at compile time, as it can be different at runtime.
for (DexEncodedField staticField : staticFields) {
staticField.clearStaticValue();
}
assert kind == Kind.CF : "Invalid kind " + kind + " for library-path class " + type;
}
public static Builder builder(DexItemFactory dexItemFactory) {
return new Builder(dexItemFactory);
}
public static DexLibraryClass asLibraryClassOrNull(DexClass clazz) {
return clazz != null ? clazz.asLibraryClass() : null;
}
private static boolean verifyLibraryMethod(DexEncodedMethod method) {
assert !method.isClassInitializer();
assert !method.isPrivateMethod();
assert !method.hasCode();
return true;
}
private static boolean verifyLibraryField(DexEncodedField field) {
assert !field.isPrivate();
assert !field.isStatic() || !field.hasExplicitStaticValue();
return true;
}
@Override
public void accept(
Consumer<DexProgramClass> programClassConsumer,
Consumer<DexClasspathClass> classpathClassConsumer,
Consumer<DexLibraryClass> libraryClassConsumer) {
libraryClassConsumer.accept(this);
}
@Override
public String toString() {
return type.toString() + "(library class)";
}
@Override
public String toSourceString() {
return type.toSourceString() + "(library class)";
}
@Override
public void addDependencies(MixedSectionCollection collector) {
// Should never happen but does not harm.
assert false;
}
@Override
public boolean isNotProgramClass() {
return true;
}
@Override
public boolean isLibraryClass() {
return true;
}
@Override
public DexLibraryClass asLibraryClass() {
return this;
}
@Override
public DexLibraryClass asClasspathOrLibraryClass() {
return this;
}
@Override
public KotlinClassLevelInfo getKotlinInfo() {
throw new Unreachable("We should never consider metadata for library classes");
}
@Override
public DexLibraryClass get() {
return this;
}
@Override
boolean internalClassOrInterfaceMayHaveInitializationSideEffects(
AppView<?> appView,
DexClass initialAccessHolder,
Predicate<DexType> ignore,
Set<DexType> seen) {
if (!seen.add(getType()) || ignore.test(getType())) {
return false;
}
return isInterface()
? appView.options().libraryInterfacesMayHaveStaticInitialization
: !appView.dexItemFactory().libraryClassesWithoutStaticInitialization.contains(type);
}
public static class Builder {
// Required.
private DexType type;
private ClassAccessFlags accessFlags;
// Optional.
private Origin origin = Origin.unknown();
private DexType superType;
private DexTypeList interfaces = DexTypeList.empty();
private DexString sourceFile = null;
private NestHostClassAttribute nestHost = null;
private List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
private EnclosingMethodAttribute enclosingMember = null;
private List<InnerClassAttribute> innerClasses = Collections.emptyList();
private ClassSignature classSignature = ClassSignature.noSignature();
private DexAnnotationSet annotations = DexAnnotationSet.empty();
private DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;
private DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;
private DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;
private DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
private boolean skipNameValidationForTesting;
private Builder(DexItemFactory dexItemFactory) {
this.superType = dexItemFactory.objectType;
this.skipNameValidationForTesting = dexItemFactory.getSkipNameValidationForTesting();
}
public Builder setAccessFlags(ClassAccessFlags accessFlags) {
this.accessFlags = accessFlags;
return this;
}
public Builder setDirectMethods(Collection<DexEncodedMethod> directMethods) {
this.directMethods = directMethods.toArray(DexEncodedMethod.EMPTY_ARRAY);
return this;
}
public Builder setType(DexType type) {
this.type = type;
return this;
}
public DexLibraryClass build() {
assert validate();
return new DexLibraryClass(
type,
ProgramResource.Kind.CF,
origin,
accessFlags,
superType,
interfaces,
sourceFile,
nestHost,
nestMembers,
enclosingMember,
innerClasses,
classSignature,
annotations,
staticFields,
instanceFields,
directMethods,
virtualMethods,
skipNameValidationForTesting);
}
private boolean validate() {
assert type != null;
assert accessFlags != null;
return true;
}
}
}