|  | // Copyright (c) 2017, 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.cf.CfVersion; | 
|  | import com.android.tools.r8.dex.Constants; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.List; | 
|  | import java.util.function.BooleanSupplier; | 
|  |  | 
|  | public class ClassAccessFlags extends AccessFlags<ClassAccessFlags> { | 
|  |  | 
|  | // List of valid flags for both DEX and Java. | 
|  | private static final int SHARED_FLAGS | 
|  | = AccessFlags.BASE_FLAGS | 
|  | | Constants.ACC_INTERFACE | 
|  | | Constants.ACC_ABSTRACT | 
|  | | Constants.ACC_ANNOTATION | 
|  | | Constants.ACC_ENUM; | 
|  |  | 
|  | private static final int DEX_FLAGS | 
|  | = SHARED_FLAGS; | 
|  |  | 
|  | private static final int CF_FLAGS = SHARED_FLAGS | Constants.ACC_SUPER | Constants.ACC_RECORD; | 
|  |  | 
|  | @Override | 
|  | protected List<String> getNames() { | 
|  | return new ImmutableList.Builder<String>() | 
|  | .addAll(super.getNames()) | 
|  | .add("interface") | 
|  | .add("abstract") | 
|  | .add("annotation") | 
|  | .add("enum") | 
|  | .add("super") | 
|  | .add("record") | 
|  | .build(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | protected List<BooleanSupplier> getPredicates() { | 
|  | return new ImmutableList.Builder<BooleanSupplier>() | 
|  | .addAll(super.getPredicates()) | 
|  | .add(this::isInterface) | 
|  | .add(this::isAbstract) | 
|  | .add(this::isAnnotation) | 
|  | .add(this::isEnum) | 
|  | .add(this::isSuper) | 
|  | .add(this::isRecord) | 
|  | .build(); | 
|  | } | 
|  |  | 
|  | private ClassAccessFlags(int flags) { | 
|  | this(flags, flags); | 
|  | } | 
|  |  | 
|  | private ClassAccessFlags(int originalFlags, int modifiedFlags) { | 
|  | super(originalFlags, modifiedFlags); | 
|  | } | 
|  |  | 
|  | public static ClassAccessFlags createPublicFinalSynthetic() { | 
|  | return new ClassAccessFlags( | 
|  | Constants.ACC_PUBLIC | Constants.ACC_FINAL | Constants.ACC_SYNTHETIC); | 
|  | } | 
|  |  | 
|  | public static ClassAccessFlags fromSharedAccessFlags(int access) { | 
|  | assert (access & SHARED_FLAGS) == access; | 
|  | assert SHARED_FLAGS == DEX_FLAGS; | 
|  | return fromDexAccessFlags(access); | 
|  | } | 
|  |  | 
|  | public static ClassAccessFlags fromDexAccessFlags(int access) { | 
|  | return new ClassAccessFlags(access & DEX_FLAGS); | 
|  | } | 
|  |  | 
|  | public static ClassAccessFlags fromCfAccessFlags(int access) { | 
|  | return new ClassAccessFlags(access & CF_FLAGS); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public ClassAccessFlags copy() { | 
|  | return new ClassAccessFlags(originalFlags, modifiedFlags); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public ClassAccessFlags self() { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int getAsCfAccessFlags() { | 
|  | assert !isInterface() || isAbstract(); | 
|  | assert !isInterface() || !isSuper(); | 
|  | assert !isInterface() || !isFinal(); | 
|  | assert !isInterface() || !isEnum(); | 
|  | return materialize(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int getAsDexAccessFlags() { | 
|  | // We unset the super flag here, as it is meaningless in DEX. Furthermore, we add missing | 
|  | // abstract to interfaces to work around a javac bug when generating package-info classes. | 
|  | int flags = materialize() & ~Constants.ACC_SUPER & ~Constants.ACC_RECORD; | 
|  | if (isInterface()) { | 
|  | return flags | Constants.ACC_ABSTRACT; | 
|  | } | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks whether the constraints from | 
|  | * https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 are met. | 
|  | */ | 
|  | public boolean areValid(CfVersion version, boolean isPackageInfo) { | 
|  | if (isInterface()) { | 
|  | // We ignore the super flags prior to JDK 9, as so did the VM. | 
|  | if (version.isGreaterThanOrEqualTo(CfVersion.V9) && isSuper()) { | 
|  | return false; | 
|  | } | 
|  | // When not coming from DEX input we require interfaces to be abstract - except for | 
|  | // package-info classes - as both old versions of javac and other tools can produce | 
|  | // package-info classes that are interfaces but not abstract. | 
|  | if (version.isGreaterThan(Constants.CORRESPONDING_CLASS_FILE_VERSION) | 
|  | && !isAbstract() | 
|  | && !isPackageInfo) { | 
|  | return false; | 
|  | } | 
|  | return !isFinal() && !isEnum(); | 
|  | } else { | 
|  | return !isAnnotation() && (!isFinal() || !isAbstract()); | 
|  | } | 
|  | } | 
|  |  | 
|  | private boolean isClass() { | 
|  | return !isInterface() && !isAnnotation() && !isEnum(); | 
|  | } | 
|  |  | 
|  | public boolean isInterface() { | 
|  | return isSet(Constants.ACC_INTERFACE); | 
|  | } | 
|  |  | 
|  | public void setInterface() { | 
|  | set(Constants.ACC_INTERFACE); | 
|  | } | 
|  |  | 
|  | public void unsetInterface() { | 
|  | unset(Constants.ACC_INTERFACE); | 
|  | } | 
|  |  | 
|  | public boolean isAbstract() { | 
|  | return isSet(Constants.ACC_ABSTRACT); | 
|  | } | 
|  |  | 
|  | public void demoteFromAbstract() { | 
|  | demote(Constants.ACC_ABSTRACT); | 
|  | } | 
|  |  | 
|  | public void setAbstract() { | 
|  | set(Constants.ACC_ABSTRACT); | 
|  | } | 
|  |  | 
|  | public void unsetAbstract() { | 
|  | unset(Constants.ACC_ABSTRACT); | 
|  | } | 
|  |  | 
|  | public boolean isAnnotation() { | 
|  | return isSet(Constants.ACC_ANNOTATION); | 
|  | } | 
|  |  | 
|  | public void setAnnotation() { | 
|  | set(Constants.ACC_ANNOTATION); | 
|  | } | 
|  |  | 
|  | public void unsetAnnotation() { | 
|  | unset(Constants.ACC_ANNOTATION); | 
|  | } | 
|  |  | 
|  | public boolean isEnum() { | 
|  | return isSet(Constants.ACC_ENUM); | 
|  | } | 
|  |  | 
|  | public void setEnum() { | 
|  | set(Constants.ACC_ENUM); | 
|  | } | 
|  |  | 
|  | public boolean isRecord() { | 
|  | return isSet(Constants.ACC_RECORD); | 
|  | } | 
|  |  | 
|  | public void setRecord() { | 
|  | set(Constants.ACC_RECORD); | 
|  | } | 
|  |  | 
|  | public void unsetRecord() { | 
|  | unset(Constants.ACC_RECORD); | 
|  | } | 
|  |  | 
|  | public boolean isSuper() { | 
|  | return isSet(Constants.ACC_SUPER); | 
|  | } | 
|  |  | 
|  | public void setSuper() { | 
|  | set(Constants.ACC_SUPER); | 
|  | } | 
|  |  | 
|  | public void unsetSuper() { | 
|  | unset(Constants.ACC_SUPER); | 
|  | } | 
|  | } |