|  | // 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; | 
|  | } | 
|  | } | 
|  | } |