blob: 19f0fdf0a56cb0fcc4215443af10e6c835243545 [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 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);
}
}