blob: e33792c9418cefcedf15e1054e0809c7e0783f8a [file] [log] [blame]
// 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 static kotlinx.metadata.FlagsKt.flagsOf;
import com.android.tools.r8.dex.Constants;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
import kotlinx.metadata.Flag;
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;
@Override
protected List<String> getNames() {
return new ImmutableList.Builder<String>()
.addAll(super.getNames())
.add("interface")
.add("abstract")
.add("annotation")
.add("enum")
.add("super")
.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)
.build();
}
private ClassAccessFlags(int flags) {
this(flags, flags);
}
private ClassAccessFlags(int originalFlags, int modifiedFlags) {
super(originalFlags, modifiedFlags);
}
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) {
// Assume that the SUPER flag should be set (behaviour for Java versions > 1.1).
return new ClassAccessFlags((access & DEX_FLAGS) | Constants.ACC_SUPER);
}
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() {
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;
if (isInterface()) {
return flags | Constants.ACC_ABSTRACT;
}
return flags;
}
@Override
public int getAsKotlinFlags() {
int flag = super.getAsKotlinFlags();
List<Flag> flags = new ArrayList<>();
if (isAbstract()) {
flags.add(Flag.IS_ABSTRACT);
}
if (isClass()) {
flags.add(Flag.Class.IS_CLASS);
}
if (isInterface()) {
flags.add(Flag.Class.IS_INTERFACE);
}
if (isAnnotation()) {
flags.add(Flag.Class.IS_ANNOTATION_CLASS);
}
if (isEnum()) {
flags.add(Flag.Class.IS_ENUM_CLASS);
}
return flag | flagsOf(flags.toArray(EMPTY_FLAG));
}
/**
* 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(int majorVersion, boolean isPackageInfo) {
if (isInterface()) {
// We ignore the super flags prior to JDK 9, as so did the VM.
if ((majorVersion >= 53) && 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 (((majorVersion > 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 isSuper() {
return isSet(Constants.ACC_SUPER);
}
public void setSuper() {
set(Constants.ACC_SUPER);
}
public void unsetSuper() {
unset(Constants.ACC_SUPER);
}
}