blob: 2cceb1a398d41afc392a4de720c699901b18488d [file] [log] [blame]
// Copyright (c) 2019, 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.features.FeatureSplitBoundaryOptimizationUtils;
import com.android.tools.r8.utils.OptionalBool;
/**
* Definitions of access control routines.
*
* <p>Follows SE 11, jvm spec, section 5.4.4 on "Access Control", except for aspects related to
* "run-time module", for which all items are assumed to be in the same single such module.
*/
public class AccessControl {
public static OptionalBool isClassAccessible(
DexClass clazz, Definition context, AppView<? extends AppInfoWithClassHierarchy> appView) {
return isClassAccessible(clazz, context, appView, appView.appInfo());
}
public static OptionalBool isClassAccessible(
DexClass clazz, Definition context, AppView<?> appView, AppInfoWithClassHierarchy appInfo) {
assert appInfo != null;
if (!clazz.isPublic() && !clazz.getType().isSamePackage(context.getContextType())) {
return OptionalBool.FALSE;
}
if (appView.hasClassHierarchy()
&& context.isProgramDefinition()
&& !FeatureSplitBoundaryOptimizationUtils.isSafeForAccess(
clazz, context.asProgramDefinition(), appView.withClassHierarchy())) {
return OptionalBool.UNKNOWN;
}
return OptionalBool.TRUE;
}
/** Intentionally package-private, use {@link MemberResolutionResult#isAccessibleFrom}. */
static OptionalBool isMemberAccessible(
SuccessfulMemberResolutionResult<?, ?> resolutionResult,
Definition context,
AppView<?> appView,
AppInfoWithClassHierarchy appInfo) {
return isMemberAccessible(
resolutionResult.getResolutionPair(),
resolutionResult.getInitialResolutionHolder(),
context,
appView,
appInfo);
}
public static OptionalBool isMemberAccessible(
DexClassAndMember<?, ?> member,
Definition initialResolutionContext,
Definition context,
AppView<? extends AppInfoWithClassHierarchy> appView) {
return isMemberAccessible(
member, initialResolutionContext, context, appView, appView.appInfo());
}
static OptionalBool isMemberAccessible(
DexClassAndMember<?, ?> member,
Definition initialResolutionContext,
Definition context,
AppView<?> appView,
AppInfoWithClassHierarchy appInfo) {
AccessFlags<?> memberFlags = member.getDefinition().getAccessFlags();
OptionalBool classAccessibility =
isClassAccessible(initialResolutionContext.getContextClass(), context, appView, appInfo);
if (classAccessibility.isFalse()) {
return OptionalBool.FALSE;
}
if (memberFlags.isPublic()) {
return classAccessibility;
}
if (memberFlags.isPrivate()) {
if (!isNestMate(member.getHolder(), context.getContextClass())) {
return OptionalBool.FALSE;
}
return classAccessibility;
}
if (!member.getHolderType().isSamePackage(context.getContextType())) {
if (memberFlags.isPackagePrivate()
|| !appInfo.isSubtype(context.getContextType(), member.getHolderType())) {
return OptionalBool.FALSE;
}
}
if (appView.hasClassHierarchy()
&& context.isProgramDefinition()
&& !FeatureSplitBoundaryOptimizationUtils.isSafeForAccess(
member, context.asProgramDefinition(), appView.withClassHierarchy())) {
return OptionalBool.UNKNOWN;
}
return classAccessibility;
}
private static boolean isNestMate(DexClass clazz, DexClass context) {
if (clazz == context) {
return true;
}
if (context == null) {
assert false : "context should not be null";
return false;
}
if (!clazz.isInANest() || !context.isInANest()) {
return false;
}
return clazz.getNestHost().isIdenticalTo(context.getNestHost());
}
}