blob: 5bb0780197b90232e797c4883be90d2226689bb3 [file] [log] [blame]
package com.android.tools.r8.verticalclassmerging;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndField;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistryWithResult;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
import com.android.tools.r8.utils.OptionalBool;
// Searches for a reference to a non-private, non-public class, field or method declared in the
// same package as [source].
public class IllegalAccessDetector extends UseRegistryWithResult<Boolean, ProgramMethod> {
private final AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy;
private final GraphLens codeLens;
public IllegalAccessDetector(
AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy,
ProgramMethod context) {
super(appViewWithClassHierarchy, context, false);
this.appViewWithClassHierarchy = appViewWithClassHierarchy;
this.codeLens = context.getDefinition().getCode().getCodeLens(appViewWithClassHierarchy);
}
protected boolean checkFoundPackagePrivateAccess() {
assert getResult();
return true;
}
protected boolean setFoundPackagePrivateAccess() {
setResult(true);
return true;
}
protected static boolean continueSearchForPackagePrivateAccess() {
return false;
}
private boolean checkFieldReference(DexField field) {
return checkRewrittenFieldReference(
appViewWithClassHierarchy.graphLens().lookupField(field, codeLens));
}
private boolean checkRewrittenFieldReference(DexField field) {
assert field.getHolderType().isClassType();
DexType fieldHolder = field.getHolderType();
if (fieldHolder.isSamePackage(getContext().getHolderType())) {
if (checkRewrittenTypeReference(fieldHolder)) {
return checkFoundPackagePrivateAccess();
}
DexClassAndField resolvedField =
appViewWithClassHierarchy.appInfo().resolveField(field).getResolutionPair();
if (resolvedField == null) {
return setFoundPackagePrivateAccess();
}
if (resolvedField.getHolder() != getContext().getHolder()
&& !resolvedField.getAccessFlags().isPublic()) {
return setFoundPackagePrivateAccess();
}
if (checkRewrittenFieldType(resolvedField)) {
return checkFoundPackagePrivateAccess();
}
}
return continueSearchForPackagePrivateAccess();
}
protected boolean checkRewrittenFieldType(DexClassAndField field) {
return continueSearchForPackagePrivateAccess();
}
private boolean checkRewrittenMethodReference(
DexMethod rewrittenMethod, OptionalBool isInterface) {
DexType baseType =
rewrittenMethod.getHolderType().toBaseType(appViewWithClassHierarchy.dexItemFactory());
if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
if (checkRewrittenTypeReference(rewrittenMethod.getHolderType())) {
return checkFoundPackagePrivateAccess();
}
MethodResolutionResult resolutionResult =
isInterface.isUnknown()
? appViewWithClassHierarchy
.appInfo()
.unsafeResolveMethodDueToDexFormat(rewrittenMethod)
: appViewWithClassHierarchy
.appInfo()
.resolveMethod(rewrittenMethod, isInterface.isTrue());
if (!resolutionResult.isSingleResolution()) {
return setFoundPackagePrivateAccess();
}
DexClassAndMethod resolvedMethod = resolutionResult.asSingleResolution().getResolutionPair();
if (resolvedMethod.getHolder() != getContext().getHolder()
&& !resolvedMethod.getAccessFlags().isPublic()) {
return setFoundPackagePrivateAccess();
}
}
return continueSearchForPackagePrivateAccess();
}
private boolean checkTypeReference(DexType type) {
return internalCheckTypeReference(type, appViewWithClassHierarchy.graphLens(), codeLens);
}
private boolean checkRewrittenTypeReference(DexType type) {
return internalCheckTypeReference(
type, GraphLens.getIdentityLens(), GraphLens.getIdentityLens());
}
private boolean internalCheckTypeReference(
DexType type, GraphLens graphLens, GraphLens codeLens) {
DexType baseType =
graphLens.lookupType(type.toBaseType(appViewWithClassHierarchy.dexItemFactory()), codeLens);
if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
DexClass clazz = appViewWithClassHierarchy.definitionFor(baseType);
if (clazz == null || !clazz.isPublic()) {
return setFoundPackagePrivateAccess();
}
}
return continueSearchForPackagePrivateAccess();
}
@Override
public void registerInitClass(DexType clazz) {
if (appViewWithClassHierarchy.initClassLens().isFinal()) {
// The InitClass lens is always rewritten up until the most recent graph lens, so first map
// the class type to the most recent graph lens.
DexType rewrittenType = appViewWithClassHierarchy.graphLens().lookupType(clazz, codeLens);
DexField initClassField =
appViewWithClassHierarchy.initClassLens().getInitClassField(rewrittenType);
checkRewrittenFieldReference(initClassField);
} else {
checkTypeReference(clazz);
}
}
@Override
public void registerInvokeVirtual(DexMethod method) {
MethodLookupResult lookup =
appViewWithClassHierarchy.graphLens().lookupInvokeVirtual(method, getContext(), codeLens);
checkRewrittenMethodReference(lookup.getReference(), OptionalBool.FALSE);
}
@Override
public void registerInvokeDirect(DexMethod method) {
MethodLookupResult lookup =
appViewWithClassHierarchy.graphLens().lookupInvokeDirect(method, getContext(), codeLens);
checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
}
@Override
public void registerInvokeStatic(DexMethod method) {
MethodLookupResult lookup =
appViewWithClassHierarchy.graphLens().lookupInvokeStatic(method, getContext(), codeLens);
checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
}
@Override
public void registerInvokeInterface(DexMethod method) {
MethodLookupResult lookup =
appViewWithClassHierarchy.graphLens().lookupInvokeInterface(method, getContext(), codeLens);
checkRewrittenMethodReference(lookup.getReference(), OptionalBool.TRUE);
}
@Override
public void registerInvokeSuper(DexMethod method) {
MethodLookupResult lookup =
appViewWithClassHierarchy.graphLens().lookupInvokeSuper(method, getContext(), codeLens);
checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
}
@Override
public void registerInstanceFieldWrite(DexField field) {
checkFieldReference(field);
}
@Override
public void registerInstanceFieldRead(DexField field) {
checkFieldReference(field);
}
@Override
public void registerNewInstance(DexType type) {
checkTypeReference(type);
}
@Override
public void registerStaticFieldRead(DexField field) {
checkFieldReference(field);
}
@Override
public void registerStaticFieldWrite(DexField field) {
checkFieldReference(field);
}
@Override
public void registerTypeReference(DexType type) {
checkTypeReference(type);
}
@Override
public void registerInstanceOf(DexType type) {
checkTypeReference(type);
}
}