Open interfaces analysis on cf code
Bug: b/214496607
Bug: b/236581210
Change-Id: I4f0ffb82a2df1d98c80e3a7f74c19bdb34847fe9
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 223fc66..72508bb 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -442,6 +442,7 @@
assert appView.appInfo().hasLiveness();
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ // TODO(b/214496607): Evaluate build speed. Avoid fixpoint when frames are present.
assert new CfOpenClosedInterfacesAnalysis(appViewWithLiveness).run(executorService);
new StartupInstrumentation(appView).instrumentAllClasses(executorService);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 918203f..41f6774 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -36,6 +36,16 @@
return getStoreType();
}
+ @Override
+ public boolean isArrayStore() {
+ return true;
+ }
+
+ @Override
+ public CfArrayStore asArrayStore() {
+ return this;
+ }
+
private int getStoreType() {
switch (getType()) {
case OBJECT:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 80813e1..9ff6d09 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -77,18 +77,6 @@
return visitor.visit(this, other.asFieldInstruction(), CfFieldInstruction::specify);
}
- public boolean isFieldGet() {
- return false;
- }
-
- public boolean isStaticFieldGet() {
- return false;
- }
-
- public boolean isStaticFieldPut() {
- return false;
- }
-
public abstract CfFieldInstruction createWithField(DexField field);
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
index 1a62143..b145f37 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
@@ -103,6 +103,11 @@
return true;
}
+ @Override
+ public boolean isStrengthenFramesEnabled() {
+ return false;
+ }
+
public void seenLabel(CfLabel label) {
if (tryCatchRangeLabels.contains(label)) {
for (CfTryCatch tryCatchRange : tryCatchRanges) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 089f5ee..5384772 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -43,6 +43,11 @@
}
@Override
+ public boolean isInstanceFieldGet() {
+ return true;
+ }
+
+ @Override
public CfFieldInstruction createWithField(DexField otherField) {
return new CfInstanceFieldRead(otherField);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index c492db1..7fffb3d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -46,6 +46,21 @@
}
@Override
+ public boolean isFieldPut() {
+ return true;
+ }
+
+ @Override
+ public boolean isInstanceFieldPut() {
+ return true;
+ }
+
+ @Override
+ public CfInstanceFieldWrite asInstanceFieldPut() {
+ return this;
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldWrite(getField());
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 66e3d69..bc8e8fb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -135,6 +135,14 @@
return TraversalContinuation.doContinue(initialValue);
}
+ public boolean isArrayStore() {
+ return false;
+ }
+
+ public CfArrayStore asArrayStore() {
+ return null;
+ }
+
@Override
public CfInstruction asCfInstruction() {
return this;
@@ -182,6 +190,38 @@
return false;
}
+ public boolean isFieldGet() {
+ return false;
+ }
+
+ public boolean isInstanceFieldGet() {
+ return false;
+ }
+
+ public boolean isStaticFieldGet() {
+ return false;
+ }
+
+ public boolean isFieldPut() {
+ return false;
+ }
+
+ public boolean isInstanceFieldPut() {
+ return false;
+ }
+
+ public CfInstanceFieldWrite asInstanceFieldPut() {
+ return null;
+ }
+
+ public boolean isStaticFieldPut() {
+ return false;
+ }
+
+ public CfStaticFieldWrite asStaticFieldPut() {
+ return null;
+ }
+
public CfGoto asGoto() {
return null;
}
@@ -311,6 +351,10 @@
return false;
}
+ public CfReturn asReturn() {
+ return null;
+ }
+
public boolean isReturnVoid() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index fe5af15..8fb0024 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -106,6 +106,11 @@
}
@Override
+ public CfReturn asReturn() {
+ return this;
+ }
+
+ @Override
public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
Slot pop = state.pop();
builder.addReturn(pop.register);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index bdad2a3..c904d10 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -42,11 +42,21 @@
}
@Override
+ public boolean isFieldPut() {
+ return true;
+ }
+
+ @Override
public boolean isStaticFieldPut() {
return true;
}
@Override
+ public CfStaticFieldWrite asStaticFieldPut() {
+ return this;
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldWrite(getField());
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 1efc762..36c45bc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -157,8 +157,7 @@
if (clazz == null) {
return false;
}
- // TODO(b/214496607): Allow uninstantiated reasoning for closed interfaces.
- if (clazz.isInterface()) {
+ if (clazz.isInterface() && appView.getOpenClosedInterfacesCollection().isMaybeOpen(clazz)) {
return false;
}
return !appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz);
diff --git a/src/main/java/com/android/tools/r8/ir/code/MemberType.java b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
index c85a687..a23e5b1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MemberType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
@@ -20,6 +20,10 @@
INT_OR_FLOAT,
LONG_OR_DOUBLE;
+ public boolean isObject() {
+ return this == OBJECT;
+ }
+
public boolean isPrecise() {
return this != INT_OR_FLOAT && this != LONG_OR_DOUBLE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index e504e3d..226cb11 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -86,7 +86,6 @@
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorIROptimizer;
-import com.android.tools.r8.optimize.interfaces.analysis.OpenClosedInterfacesAnalysis;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepMethodInfo;
@@ -142,7 +141,6 @@
private final ServiceLoaderRewriter serviceLoaderRewriter;
private final EnumValueOptimizer enumValueOptimizer;
private final EnumUnboxer enumUnboxer;
- private final OpenClosedInterfacesAnalysis openClosedInterfacesAnalysis;
public final AssumeInserter assumeInserter;
private final DynamicTypeOptimization dynamicTypeOptimization;
@@ -228,7 +226,6 @@
this.methodOptimizationInfoCollector = null;
this.enumValueOptimizer = null;
this.enumUnboxer = EnumUnboxer.empty();
- this.openClosedInterfacesAnalysis = OpenClosedInterfacesAnalysis.empty();
this.assumeInserter = null;
return;
}
@@ -262,8 +259,6 @@
this.memberValuePropagation = new R8MemberValuePropagation(appViewWithLiveness);
this.methodOptimizationInfoCollector =
new MethodOptimizationInfoCollector(appViewWithLiveness, this);
- // TODO(b/214496607): Enable open/closed interfaces analysis.
- this.openClosedInterfacesAnalysis = OpenClosedInterfacesAnalysis.empty();
if (options.isMinifying()) {
this.identifierNameStringMarker = new IdentifierNameStringMarker(appViewWithLiveness);
} else {
@@ -299,7 +294,6 @@
this.methodOptimizationInfoCollector = null;
this.enumValueOptimizer = null;
this.enumUnboxer = EnumUnboxer.empty();
- this.openClosedInterfacesAnalysis = OpenClosedInterfacesAnalysis.empty();
}
this.stringSwitchRemover =
options.isStringSwitchConversionEnabled()
@@ -669,7 +663,6 @@
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.initializeCodeScanner(executorService, timing));
enumUnboxer.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
- openClosedInterfacesAnalysis.prepareForPrimaryOptimizationPass();
outliner.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
if (fieldAccessAnalysis != null) {
@@ -857,7 +850,6 @@
if (inliner != null) {
inliner.onLastWaveDone(postMethodProcessorBuilder, executorService, timing);
}
- openClosedInterfacesAnalysis.onPrimaryOptimizationPassComplete();
// Ensure determinism of method-to-reprocess set.
appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
@@ -1164,8 +1156,6 @@
assert code.verifyTypes(appView);
assert code.isConsistentSSA(appView);
- openClosedInterfacesAnalysis.analyze(context, code);
-
if (shouldPassThrough(context)) {
// If the code is pass trough, do not finalize by overwriting the existing code.
assert appView.enableWholeProgramOptimizations();
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java
index 0a2bec0..bd636c3 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java
@@ -19,4 +19,6 @@
int getMaxStack();
boolean isImmediateSuperClassOfCurrentContext(DexType type);
+
+ boolean isStrengthenFramesEnabled();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
index ae2e594..f37e786 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
@@ -4,15 +4,22 @@
package com.android.tools.r8.optimize.interfaces.analysis;
+import com.android.tools.r8.cf.code.CfArrayStore;
import com.android.tools.r8.cf.code.CfAssignability;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfSubtypingAssignability;
import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
@@ -23,36 +30,52 @@
import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfBlock;
import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfControlFlowGraph;
import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfIntraproceduralDataflowAnalysis;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
+import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.optimize.interfaces.collection.NonEmptyOpenClosedInterfacesCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.InternalOptions.OpenClosedInterfacesOptions;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.UnverifiableCfCodeDiagnostic;
+import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramMethodMap;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
public class CfOpenClosedInterfacesAnalysis {
private final AppView<AppInfoWithLiveness> appView;
private final CfAssignability assignability;
+ private final DexItemFactory dexItemFactory;
private final InternalOptions options;
+ private final Set<DexClass> openInterfaces = Sets.newConcurrentHashSet();
+
private final ProgramMethodMap<UnverifiableCfCodeDiagnostic> unverifiableCodeDiagnostics =
ProgramMethodMap.createConcurrent();
public CfOpenClosedInterfacesAnalysis(AppView<AppInfoWithLiveness> appView) {
- InternalOptions options = appView.options();
this.appView = appView;
this.assignability = new CfSubtypingAssignability(appView);
- this.options = options;
+ this.dexItemFactory = appView.dexItemFactory();
+ this.options = appView.options();
}
public boolean run(ExecutorService executorService) throws ExecutionException {
processClasses(executorService);
+ setClosedInterfaces();
reportUnverifiableCodeDiagnostics();
return true;
}
@@ -62,14 +85,15 @@
}
private void processClass(DexProgramClass clazz) {
- clazz.forEachProgramMethodMatching(DexEncodedMethod::hasCode, this::processMethod);
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode, method -> openInterfaces.addAll(processMethod(method)));
}
- private void processMethod(ProgramMethod method) {
+ private Set<DexClass> processMethod(ProgramMethod method) {
Code code = method.getDefinition().getCode();
if (!code.isCfCode()) {
assert code.isDefaultInstanceInitializerCode() || code.isDexCode() || code.isThrowNullCode();
- return;
+ return Collections.emptySet();
}
CfCode cfCode = code.asCfCode();
@@ -79,29 +103,25 @@
new CfIntraproceduralDataflowAnalysis<>(appView, CfFrameState.bottom(), cfg, transfer);
DataflowAnalysisResult result = analysis.run(cfg.getEntryBlock());
assert result.isSuccessfulAnalysisResult();
+
+ Set<DexClass> openInterfacesForMethod = Sets.newIdentityHashSet();
for (CfBlock block : cfg.getBlocks()) {
if (analysis.isIntermediateBlock(block)) {
continue;
}
CfFrameState state = analysis.computeBlockEntryState(block);
+ if (state.isError()) {
+ return registerUnverifiableCode(method, 0, state.asError());
+ }
do {
for (int instructionIndex = block.getFirstInstructionIndex();
instructionIndex <= block.getLastInstructionIndex();
instructionIndex++) {
- // TODO(b/214496607): Determine open interfaces.
CfInstruction instruction = cfCode.getInstruction(instructionIndex);
+ processInstruction(method, instruction, state, openInterfacesForMethod::add);
state = transfer.apply(instruction, state).asAbstractState();
if (state.isError()) {
- if (options.getCfCodeAnalysisOptions().isUnverifiableCodeReportingEnabled()) {
- unverifiableCodeDiagnostics.put(
- method,
- new UnverifiableCfCodeDiagnostic(
- method.getMethodReference(),
- instructionIndex,
- state.asError().getMessage(),
- method.getOrigin()));
- }
- return;
+ return registerUnverifiableCode(method, instructionIndex, state.asError());
}
}
if (analysis.isBlockWithIntermediateSuccessorBlock(block)) {
@@ -111,6 +131,198 @@
}
} while (block != null);
}
+ return openInterfacesForMethod;
+ }
+
+ private void processInstruction(
+ ProgramMethod method,
+ CfInstruction instruction,
+ CfFrameState state,
+ Consumer<DexClass> openInterfaceConsumer) {
+ assert !state.isError();
+ if (state.isBottom()) {
+ // Represents that this instruction is unreachable from the method entry point.
+ return;
+ }
+ assert state.isConcrete();
+ ConcreteCfFrameState concreteState = state.asConcrete();
+ if (instruction.isArrayStore()) {
+ processArrayStore(instruction.asArrayStore(), concreteState, openInterfaceConsumer);
+ } else if (instruction.isInstanceFieldPut()) {
+ processInstanceFieldPut(
+ instruction.asInstanceFieldPut(), concreteState, openInterfaceConsumer);
+ } else if (instruction.isInvoke()) {
+ processInvoke(instruction.asInvoke(), concreteState, openInterfaceConsumer);
+ } else if (instruction.isReturn() && !instruction.isReturnVoid()) {
+ processReturn(instruction.asReturn(), method, concreteState, openInterfaceConsumer);
+ } else if (instruction.isStaticFieldPut()) {
+ processStaticFieldPut(instruction.asStaticFieldPut(), concreteState, openInterfaceConsumer);
+ }
+ }
+
+ private void processArrayStore(
+ CfArrayStore arrayStore,
+ ConcreteCfFrameState state,
+ Consumer<DexClass> openInterfaceConsumer) {
+ if (!arrayStore.getType().isObject()) {
+ return;
+ }
+ state.peekStackElements(
+ 3,
+ stack -> {
+ FrameType array = stack.peekFirst();
+ FrameType value = stack.peekLast();
+ if (array.isInitializedReferenceType()) {
+ DexType arrayType = array.asInitializedReferenceType().getInitializedType();
+ if (arrayType.isArrayType()) {
+ processAssignment(
+ value, arrayType.toArrayElementType(dexItemFactory), openInterfaceConsumer);
+ } else {
+ assert arrayType.isNullValueType();
+ }
+ } else {
+ assert false;
+ }
+ });
+ }
+
+ private void processInstanceFieldPut(
+ CfInstanceFieldWrite instanceFieldPut,
+ ConcreteCfFrameState state,
+ Consumer<DexClass> openInterfaceConsumer) {
+ state.peekStackElement(
+ head ->
+ processAssignment(head, instanceFieldPut.getField().getType(), openInterfaceConsumer),
+ options);
+ }
+
+ private void processInvoke(
+ CfInvoke invoke, ConcreteCfFrameState state, Consumer<DexClass> openInterfaceConsumer) {
+ DexMethod invokedMethod = invoke.getMethod();
+ state.peekStackElements(
+ invokedMethod.getNumberOfArguments(invoke.isInvokeStatic()),
+ arguments -> {
+ int argumentIndex = 0;
+ for (FrameType argument : arguments) {
+ DexType parameter =
+ invokedMethod.getArgumentType(argumentIndex, invoke.isInvokeStatic());
+ processAssignment(argument, parameter, openInterfaceConsumer);
+ argumentIndex++;
+ }
+ },
+ options);
+ }
+
+ private void processReturn(
+ CfReturn returnInstruction,
+ ProgramMethod context,
+ ConcreteCfFrameState state,
+ Consumer<DexClass> openInterfaceConsumer) {
+ state.peekStackElement(
+ head -> processAssignment(head, context.getReturnType(), openInterfaceConsumer), options);
+ }
+
+ private void processStaticFieldPut(
+ CfStaticFieldWrite staticFieldPut,
+ ConcreteCfFrameState state,
+ Consumer<DexClass> openInterfaceConsumer) {
+ state.peekStackElement(
+ head -> processAssignment(head, staticFieldPut.getField().getType(), openInterfaceConsumer),
+ options);
+ }
+
+ private void processAssignment(
+ FrameType fromType, DexType toType, Consumer<DexClass> openInterfaceConsumer) {
+ if (fromType.isInitializedReferenceType() && !fromType.isNullType()) {
+ processAssignment(
+ fromType.asInitializedReferenceType().getInitializedType(),
+ toType,
+ openInterfaceConsumer);
+ }
+ }
+
+ private void processAssignment(
+ DexType fromType, DexType toType, Consumer<DexClass> openInterfaceConsumer) {
+ processAssignment(
+ fromType.toTypeElement(appView), toType.toTypeElement(appView), openInterfaceConsumer);
+ }
+
+ private void processAssignment(
+ TypeElement fromType, TypeElement toType, Consumer<DexClass> openInterfaceConsumer) {
+ // If the type is an interface type, then check that the assigned value is a subtype of the
+ // interface type, or mark the interface as open.
+ if (!toType.isClassType()) {
+ return;
+ }
+ ClassTypeElement toClassType = toType.asClassType();
+ if (toClassType.getClassType() != dexItemFactory.objectType) {
+ return;
+ }
+ InterfaceCollection interfaceCollection = toClassType.getInterfaces();
+ interfaceCollection.forEachKnownInterface(
+ knownInterfaceType -> {
+ DexClass knownInterface = appView.definitionFor(knownInterfaceType);
+ if (knownInterface == null) {
+ return;
+ }
+ assert knownInterface.isInterface();
+ if (fromType.lessThanOrEqualUpToNullability(toType, appView)) {
+ return;
+ }
+ assert verifyOpenInterfaceWitnessIsSuppressed(fromType, knownInterface);
+ openInterfaceConsumer.accept(knownInterface);
+ });
+ }
+
+ private void setClosedInterfaces() {
+ // If open interfaces are not allowed and there are one or more suppressions, we should find at
+ // least one open interface.
+ OpenClosedInterfacesOptions openClosedInterfacesOptions =
+ options.getOpenClosedInterfacesOptions();
+ assert openClosedInterfacesOptions.isOpenInterfacesAllowed()
+ || !openClosedInterfacesOptions.hasSuppressions()
+ || !openInterfaces.isEmpty()
+ : "Expected to find at least one open interface";
+
+ includeParentOpenInterfaces();
+
+ appView.setOpenClosedInterfacesCollection(
+ new NonEmptyOpenClosedInterfacesCollection(
+ openInterfaces.stream()
+ .map(DexClass::getType)
+ .collect(
+ Collectors.toCollection(
+ () -> SetUtils.newIdentityHashSet(openInterfaces.size())))));
+ }
+
+ private void includeParentOpenInterfaces() {
+ // This includes all parent interfaces of each open interface in the set of open interfaces,
+ // by using the open interfaces as the seen set.
+ WorkList<DexClass> worklist = WorkList.newWorkList(openInterfaces);
+ worklist.addAllIgnoringSeenSet(openInterfaces);
+ while (worklist.hasNext()) {
+ DexClass openInterface = worklist.next();
+ for (DexType indirectOpenInterfaceType : openInterface.getInterfaces()) {
+ DexClass indirectOpenInterfaceDefinition = appView.definitionFor(indirectOpenInterfaceType);
+ if (indirectOpenInterfaceDefinition != null) {
+ worklist.addIfNotSeen(indirectOpenInterfaceDefinition);
+ }
+ }
+ }
+ }
+
+ private Set<DexClass> registerUnverifiableCode(
+ ProgramMethod method, int instructionIndex, ErroneousCfFrameState state) {
+ if (options.getCfCodeAnalysisOptions().isUnverifiableCodeReportingEnabled()) {
+ unverifiableCodeDiagnostics.put(
+ method,
+ new UnverifiableCfCodeDiagnostic(
+ method.getMethodReference(),
+ instructionIndex,
+ state.getMessage(),
+ method.getOrigin()));
+ }
+ return Collections.emptySet();
}
private void reportUnverifiableCodeDiagnostics() {
@@ -121,6 +333,17 @@
methods.forEach(method -> reporter.warning(unverifiableCodeDiagnostics.get(method)));
}
+ private boolean verifyOpenInterfaceWitnessIsSuppressed(
+ TypeElement valueType, DexClass openInterface) {
+ assert options.getOpenClosedInterfacesOptions().isSuppressed(appView, valueType, openInterface)
+ : "Unexpected open interface "
+ + openInterface.getTypeName()
+ + " (assignment: "
+ + valueType
+ + ")";
+ return true;
+ }
+
private class TransferFunction
implements AbstractTransferFunction<CfBlock, CfInstruction, CfFrameState> {
@@ -160,6 +383,11 @@
public boolean isImmediateSuperClassOfCurrentContext(DexType type) {
return type == context.getHolder().getSuperType();
}
+
+ @Override
+ public boolean isStrengthenFramesEnabled() {
+ return true;
+ }
};
this.context = context;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
index 531db8b..1c2e7ee 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.FunctionUtils;
+import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Iterables;
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -35,6 +36,7 @@
import java.util.Iterator;
import java.util.Objects;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.function.UnaryOperator;
public class ConcreteCfFrameState extends CfFrameState {
@@ -78,6 +80,9 @@
if (assignabilityResult.isFailed()) {
return error(assignabilityResult.asFailed().getMessage());
}
+ if (config.isStrengthenFramesEnabled()) {
+ return this;
+ }
CfFrame frameCopy = frame.mutableCopy();
return new ConcreteCfFrameState(
frameCopy.getMutableLocals(), frameCopy.getMutableStack(), stackHeight);
@@ -135,6 +140,29 @@
return new ConcreteCfFrameState(locals, newStack, stackHeight);
}
+ public void peekStackElement(Consumer<PreciseFrameType> consumer, InternalOptions options) {
+ if (!stack.isEmpty()) {
+ consumer.accept(stack.peekLast());
+ } else {
+ assert options.getTestingOptions().allowTypeErrors;
+ }
+ }
+
+ public void peekStackElements(
+ int number, Consumer<Deque<PreciseFrameType>> consumer, InternalOptions options) {
+ if (stack.size() >= number) {
+ Deque<PreciseFrameType> result = new ArrayDeque<>(number);
+ Iterator<PreciseFrameType> iterator = stack.descendingIterator();
+ while (iterator.hasNext() && number > 0) {
+ result.addFirst(iterator.next());
+ number--;
+ }
+ consumer.accept(result);
+ } else {
+ assert options.getTestingOptions().allowTypeErrors;
+ }
+ }
+
@Override
public CfFrameState pop() {
return pop(FunctionUtils::getFirst);
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/EmptyOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/EmptyOpenClosedInterfacesAnalysis.java
deleted file mode 100644
index 6e09082..0000000
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/EmptyOpenClosedInterfacesAnalysis.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2022, 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.optimize.interfaces.analysis;
-
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.IRCode;
-
-public class EmptyOpenClosedInterfacesAnalysis extends OpenClosedInterfacesAnalysis {
-
- private static final EmptyOpenClosedInterfacesAnalysis INSTANCE =
- new EmptyOpenClosedInterfacesAnalysis();
-
- private EmptyOpenClosedInterfacesAnalysis() {}
-
- static EmptyOpenClosedInterfacesAnalysis getInstance() {
- return INSTANCE;
- }
-
- @Override
- public void analyze(ProgramMethod method, IRCode code) {
- // Intentionally empty.
- }
-
- @Override
- public void prepareForPrimaryOptimizationPass() {
- // Intentionally empty.
- }
-
- @Override
- public void onPrimaryOptimizationPassComplete() {
- // Intentionally empty.
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysis.java
deleted file mode 100644
index dc13d50..0000000
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysis.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2022, 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.optimize.interfaces.analysis;
-
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.IRCode;
-
-public abstract class OpenClosedInterfacesAnalysis {
-
- public static EmptyOpenClosedInterfacesAnalysis empty() {
- return EmptyOpenClosedInterfacesAnalysis.getInstance();
- }
-
- public abstract void analyze(ProgramMethod method, IRCode code);
-
- public abstract void prepareForPrimaryOptimizationPass();
-
- public abstract void onPrimaryOptimizationPassComplete();
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysisImpl.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysisImpl.java
deleted file mode 100644
index 4e474f4..0000000
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/OpenClosedInterfacesAnalysisImpl.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (c) 2022, 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.optimize.interfaces.analysis;
-
-import static com.android.tools.r8.ir.code.Opcodes.ARRAY_PUT;
-import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_PUT;
-import static com.android.tools.r8.ir.code.Opcodes.INVOKE_DIRECT;
-import static com.android.tools.r8.ir.code.Opcodes.INVOKE_INTERFACE;
-import static com.android.tools.r8.ir.code.Opcodes.INVOKE_STATIC;
-import static com.android.tools.r8.ir.code.Opcodes.INVOKE_SUPER;
-import static com.android.tools.r8.ir.code.Opcodes.INVOKE_VIRTUAL;
-import static com.android.tools.r8.ir.code.Opcodes.RETURN;
-import static com.android.tools.r8.ir.code.Opcodes.STATIC_PUT;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
-import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.ArrayPut;
-import com.android.tools.r8.ir.code.FieldPut;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.Return;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.optimize.interfaces.collection.NonEmptyOpenClosedInterfacesCollection;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions.OpenClosedInterfacesOptions;
-import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.Sets;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-public class OpenClosedInterfacesAnalysisImpl extends OpenClosedInterfacesAnalysis {
-
- private final AppView<AppInfoWithLiveness> appView;
- private final DexItemFactory dexItemFactory;
-
- private Set<DexClass> openInterfaces;
-
- public OpenClosedInterfacesAnalysisImpl(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- this.dexItemFactory = appView.dexItemFactory();
- }
-
- @Override
- public void analyze(ProgramMethod method, IRCode code) {
- if (openInterfaces == null) {
- return;
- }
- // Analyze each instruction that may assign to an interface type.
- for (Instruction instruction : code.instructions()) {
- switch (instruction.opcode()) {
- case ARRAY_PUT:
- analyzeArrayPut(instruction.asArrayPut());
- break;
- case INSTANCE_PUT:
- case STATIC_PUT:
- analyzeFieldPut(instruction.asFieldPut());
- break;
- case INVOKE_DIRECT:
- case INVOKE_INTERFACE:
- case INVOKE_STATIC:
- case INVOKE_SUPER:
- case INVOKE_VIRTUAL:
- analyzeInvokeMethod(instruction.asInvokeMethod());
- break;
- case RETURN:
- analyzeReturn(instruction.asReturn(), method);
- break;
- default:
- break;
- }
- }
- }
-
- private void analyzeArrayPut(ArrayPut arrayPut) {
- Value array = arrayPut.array();
- TypeElement arrayType = array.getType();
- if (!arrayType.isArrayType()) {
- return;
- }
- TypeElement valueType = arrayPut.value().getType();
- TypeElement arrayMemberType = arrayType.asArrayType().getMemberType();
- checkAssignment(valueType, arrayMemberType);
- }
-
- private void analyzeFieldPut(FieldPut fieldPut) {
- TypeElement valueType = fieldPut.value().getType();
- TypeElement fieldType = fieldPut.getField().getTypeElement(appView);
- checkAssignment(valueType, fieldType);
- }
-
- private void analyzeInvokeMethod(InvokeMethod invoke) {
- DexTypeList parameters = invoke.getInvokedMethod().getParameters();
- for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) {
- Value argument = invoke.getArgumentForParameter(parameterIndex);
- TypeElement argumentType = argument.getType();
- TypeElement parameterType = parameters.get(parameterIndex).toTypeElement(appView);
- checkAssignment(argumentType, parameterType);
- }
- }
-
- private void analyzeReturn(Return returnInstruction, ProgramMethod context) {
- if (returnInstruction.isReturnVoid()) {
- return;
- }
- TypeElement valueType = returnInstruction.returnValue().getType();
- TypeElement returnType = context.getReturnType().toTypeElement(appView);
- checkAssignment(valueType, returnType);
- }
-
- private void checkAssignment(TypeElement fromType, TypeElement toType) {
- // If the type is an interface type, then check that the assigned value is a subtype of the
- // interface type, or mark the interface as open.
- if (!toType.isClassType()) {
- return;
- }
- ClassTypeElement toClassType = toType.asClassType();
- if (toClassType.getClassType() != dexItemFactory.objectType) {
- return;
- }
- InterfaceCollection interfaceCollection = toClassType.getInterfaces();
- interfaceCollection.forEachKnownInterface(
- knownInterfaceType -> {
- DexClass knownInterface = appView.definitionFor(knownInterfaceType);
- if (knownInterface == null) {
- return;
- }
- assert knownInterface.isInterface();
- if (fromType.lessThanOrEqualUpToNullability(toType, appView)) {
- return;
- }
- assert verifyOpenInterfaceWitnessIsSuppressed(fromType, knownInterface);
- openInterfaces.add(knownInterface);
- });
- }
-
- @Override
- public void prepareForPrimaryOptimizationPass() {
- openInterfaces = Sets.newConcurrentHashSet();
- }
-
- @Override
- public void onPrimaryOptimizationPassComplete() {
- // If open interfaces are not allowed and there are one or more suppressions, we should find at
- // least one open interface.
- OpenClosedInterfacesOptions options = appView.options().getOpenClosedInterfacesOptions();
- assert options.isOpenInterfacesAllowed()
- || !options.hasSuppressions()
- || !openInterfaces.isEmpty()
- : "Expected to find at least one open interface";
-
- includeParentOpenInterfaces();
- appView.setOpenClosedInterfacesCollection(
- new NonEmptyOpenClosedInterfacesCollection(
- openInterfaces.stream()
- .map(DexClass::getType)
- .collect(
- Collectors.toCollection(
- () -> SetUtils.newIdentityHashSet(openInterfaces.size())))));
- openInterfaces = null;
- }
-
- private void includeParentOpenInterfaces() {
- // This includes all parent interfaces of each open interface in the set of open interfaces,
- // by using the open interfaces as the seen set.
- WorkList<DexClass> worklist = WorkList.newWorkList(openInterfaces);
- worklist.addAllIgnoringSeenSet(openInterfaces);
- while (worklist.hasNext()) {
- DexClass openInterface = worklist.next();
- for (DexType indirectOpenInterfaceType : openInterface.getInterfaces()) {
- DexClass indirectOpenInterfaceDefinition = appView.definitionFor(indirectOpenInterfaceType);
- if (indirectOpenInterfaceDefinition != null) {
- worklist.addIfNotSeen(indirectOpenInterfaceDefinition);
- }
- }
- }
- }
-
- private boolean verifyOpenInterfaceWitnessIsSuppressed(
- TypeElement valueType, DexClass openInterface) {
- OpenClosedInterfacesOptions options = appView.options().getOpenClosedInterfacesOptions();
- assert options.isSuppressed(appView, valueType, openInterface)
- : "Unexpected open interface "
- + openInterface.getTypeName()
- + " (assignment: "
- + valueType
- + ")";
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
index f8aeb81..df264e4 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
@@ -22,8 +22,7 @@
@Override
public boolean isDefinitelyClosed(DexClass clazz) {
- // TODO(b/214496607): Should return false.
- return true;
+ return false;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 1fecada..d338a11 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1621,6 +1621,14 @@
allowOpenInterfaces = false;
}
+ public OpenClosedInterfacesOptions suppressSingleOpenInterface(ClassReference classReference) {
+ assert !allowOpenInterfaces;
+ suppressions.add(
+ (appView, valueType, openInterface) ->
+ openInterface.getTypeName().equals(classReference.getTypeName()));
+ return this;
+ }
+
public void suppressAllOpenInterfaces() {
assert !allowOpenInterfaces;
suppressions.add((appView, valueType, openInterface) -> true);
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
index f7ce233..8d6ee1d 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
@@ -102,9 +102,9 @@
.addKeepRuleFiles(MAIN_KEEP)
.addOptionsModification(
options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
+ // TODO(b/236581210): Should only suppress AutoCloseable due to assignments from
+ // ZipFile.
+ options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.compile()
.apply(c -> FileUtils.writeTextFile(map, c.getProguardMap()))
.writeToZip(jar);
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
index 04e2842..c491fac 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
@@ -68,6 +68,9 @@
.addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_11_JAR)
.addLibraryFiles(Jdk11TestUtils.getJdk11LibraryFiles(getStaticTemp()))
.addKeepRuleFiles(MAIN_KEEP)
+ .addOptionsModification(
+ // TODO(b/236581210): There should be no open interfaces.
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.applyIf(
desugar,
builder ->
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
index cb549f5..f27071b 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
@@ -50,6 +50,9 @@
.setMinApi(parameters.getApiLevel())
.addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_11_JAR)
.addKeepRuleFiles(MAIN_KEEP)
+ .addOptionsModification(
+ // TODO(b/236581210): There should be no open interfaces.
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.compile()
.inspect(this::assertNotEmpty)
.inspect(Java11R8CompilationTest::assertNoNests);
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
index 60f6fa7..de90bf9 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
@@ -110,6 +110,8 @@
"com.android.internal.location.ProviderRequest",
"com.google.protobuf.java_com_google_android_libraries_performance_primes_release"
+ "_gmscore__primes_bcdd2915GeneratedExtensionRegistryLite$Loader")
+ .addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.allowDiagnosticMessages()
.allowUnusedProguardConfigurationRules()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
index b09cb00..afc1811 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
@@ -196,6 +196,8 @@
"android.media.RemoteDisplayState$RemoteDisplayInfo",
"com.android.internal.location.ProviderProperties",
"com.android.internal.location.ProviderRequest")
+ .addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.allowDiagnosticMessages()
.allowUnusedProguardConfigurationRules()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
index 56aed18..c8732a9 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
@@ -91,6 +91,9 @@
keepAllProtosRule(),
keepDynamicMethodSignatureRule(),
keepNewMessageInfoSignatureRule())
+ .addOptionsModification(
+ options ->
+ options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.allowCheckDiscardedErrors(true));
assertRewrittenProtoSchemasMatch(
new CodeInspector(getProgramFiles()), r8CompileResult.inspector());
diff --git a/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java b/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
index 128f780..eef3dcf 100644
--- a/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
+++ b/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
@@ -93,6 +93,8 @@
.addClasspathFiles(outDirectory.resolve("classpath.jar"))
.addLibraryFiles(outDirectory.resolve("library.jar"))
.addKeepRuleFiles(outDirectory.resolve("proguard.config"))
+ .addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.setMinApi(AndroidApiLevel.M)
.allowDiagnosticMessages()
.allowUnnecessaryDontWarnWildcards()
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
index e654b89..ce06fd4 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
@@ -5,6 +5,9 @@
package com.android.tools.r8.ir.analysis.type;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticException;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertFalse;
@@ -16,8 +19,11 @@
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.UnverifiableCfCodeDiagnostic;
import com.google.common.base.Throwables;
import java.util.List;
import org.junit.Test;
@@ -75,16 +81,27 @@
.setMinApi(parameters.getApiLevel())
.compileWithExpectedDiagnostics(
diagnostics -> {
- if (!allowTypeErrors) {
+ if (allowTypeErrors) {
+ MethodReference mainMethodReference =
+ MethodReferenceUtils.mainMethod(TestClass.class);
+ diagnostics.assertWarningsMatch(
+ allOf(
+ diagnosticType(UnverifiableCfCodeDiagnostic.class),
+ diagnosticMessage(
+ containsString(
+ "Unverifiable code in `"
+ + MethodReferenceUtils.toSourceString(mainMethodReference)
+ + "`"))),
+ diagnosticMessage(
+ equalTo(
+ "The method `"
+ + MethodReferenceUtils.toSourceString(mainMethodReference)
+ + "` does not type check and will be assumed to "
+ + "be unreachable.")));
+ } else {
diagnostics.assertErrorThatMatches(diagnosticException(AssertionError.class));
}
- })
- .assertAllWarningMessagesMatch(
- equalTo(
- "The method `void "
- + TestClass.class.getTypeName()
- + ".main(java.lang.String[])` does not type check and will be assumed to"
- + " be unreachable."));
+ });
// Compilation fails unless type errors are allowed.
assertTrue(allowTypeErrors);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
index 1107d60..1e43777 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
@@ -8,8 +8,10 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
@@ -53,15 +55,15 @@
.addKeepMainRule(Main.class)
// Keep get() to prevent that we optimize it into having static return type A.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
- .addNoVerticalClassMergingAnnotations()
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.applyIf(
- !enableVerticalClassMerging,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options ->
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
- .enableNoVerticalClassMergingAnnotations())
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.addVerticallyMergedClassesInspector(
inspector -> {
if (enableVerticalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java
index d294a77..aeca839 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java
@@ -8,8 +8,10 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
@@ -53,15 +55,15 @@
.addKeepMainRule(Main.class)
// Keep get() to prevent that we optimize it into having static return type A.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
- .addNoVerticalClassMergingAnnotations()
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.applyIf(
- !enableVerticalClassMerging,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options ->
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
- .enableNoVerticalClassMergingAnnotations())
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.addVerticallyMergedClassesInspector(
inspector -> {
if (enableVerticalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java
index 87d60b4..f541549 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java
@@ -8,8 +8,11 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ir.optimize.classmerger.vertical.StaticPutToInterfaceWithObjectMergingTest.I;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
@@ -53,15 +56,15 @@
.addKeepMainRule(Main.class)
// Keep get() to prevent that we optimize it into having static return type A.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
- .addNoVerticalClassMergingAnnotations()
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.applyIf(
- !enableVerticalClassMerging,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options ->
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
- .enableNoVerticalClassMergingAnnotations())
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.addVerticallyMergedClassesInspector(
inspector -> {
if (enableVerticalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java
index 072b819..bfc7276 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java
@@ -8,8 +8,10 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
@@ -53,15 +55,15 @@
.addKeepMainRule(Main.class)
// Keep get() to prevent that we optimize it into having static return type A.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
- .addNoVerticalClassMergingAnnotations()
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.applyIf(
- !enableVerticalClassMerging,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options ->
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
- .enableNoVerticalClassMergingAnnotations())
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.addVerticallyMergedClassesInspector(
inspector -> {
if (enableVerticalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
index d74eb4b..3aaa789 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -62,11 +63,19 @@
.addKeepMainRule(Main.class)
// Keep get() to prevent that we optimize it into having static return type A.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
- .addInliningAnnotations()
- .addNoVerticalClassMergingAnnotations()
- .applyIf(!enableInlining, R8TestBuilder::enableInliningAnnotations)
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.applyIf(
- !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ enableInlining,
+ R8TestBuilder::addInliningAnnotations,
+ R8TestBuilder::enableInliningAnnotations)
+ .applyIf(
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.addVerticallyMergedClassesInspector(
inspector -> {
if (enableVerticalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java
index 4dc19d3..7bc991e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
@@ -62,16 +63,20 @@
// Keep getA() and getB() to prevent that we optimize it into having static return type A/B.
.addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get?(...); }")
.addInliningAnnotations()
- .addNoVerticalClassMergingAnnotations()
- .applyIf(!enableInlining, R8TestBuilder::enableInliningAnnotations)
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class))
+ .suppressSingleOpenInterface(Reference.classFromClass(J.class)))
.applyIf(
- !enableVerticalClassMerging,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options ->
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
- .enableNoVerticalClassMergingAnnotations())
+ enableInlining,
+ R8TestBuilder::addInliningAnnotations,
+ R8TestBuilder::enableInliningAnnotations)
+ .applyIf(
+ enableVerticalClassMerging,
+ R8TestBuilder::addNoVerticalClassMergingAnnotations,
+ R8TestBuilder::enableNoVerticalClassMergingAnnotations)
.enableNoHorizontalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
index e8d4e5f..c756f8c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
@@ -41,7 +41,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -52,7 +52,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -68,7 +68,7 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(true));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
private List<Class<?>> getProgramClasses() {
@@ -102,11 +102,7 @@
.transform();
}
- private List<String> getExpectedOutputLines(boolean isR8) {
- if (isR8) {
- // TODO(b/214496607): R8 should not optimize the check-cast instruction since I is open.
- return ImmutableList.of("OK", "OK");
- }
+ private List<String> getExpectedOutputLines() {
if (parameters.isDexRuntime()
&& parameters
.getDexRuntimeVersion()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
index e2b4a29..4eaa6a4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
@@ -71,8 +71,7 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- // TODO(b/214496607): Should succeed with the expected output.
- .assertFailureWithErrorThatThrows(ClassCastException.class);
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
private List<Class<?>> getProgramClasses() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
index 5a57dc4..dac3848 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
@@ -41,7 +41,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -52,7 +52,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -68,7 +68,7 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(true));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
private List<Class<?>> getProgramClasses() {
@@ -95,11 +95,7 @@
.transform();
}
- private List<String> getExpectedOutputLines(boolean isR8) {
- if (isR8) {
- // TODO(b/214496607): R8 should not optimize the instanceof instruction since I is open.
- return ImmutableList.of("true", "true");
- }
+ private List<String> getExpectedOutputLines() {
if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V7_0_0)) {
return ImmutableList.of("true", "true");
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
index 68c055d..07b765f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
@@ -40,7 +40,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -51,7 +51,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(false));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
@Test
@@ -65,7 +65,7 @@
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines(true));
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
}
private List<Class<?>> getProgramClasses() {
@@ -92,11 +92,7 @@
.transform();
}
- private List<String> getExpectedOutputLines(boolean isR8) {
- if (isR8) {
- // TODO(b/214496607): R8 should not optimize the instanceof instruction since I is open.
- return ImmutableList.of("true");
- }
+ private List<String> getExpectedOutputLines() {
if (parameters.isDexRuntime()) {
if (parameters.getDexRuntimeVersion().isEqualTo(Version.V7_0_0)
|| parameters.getDexRuntimeVersion().isEqualTo(Version.V13_0_0)) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
index 12bc414..521d164 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Test;
@@ -40,6 +41,13 @@
testForR8(parameters.getBackend())
.addInnerClasses(UnusedInterfaceRemovalTest.class)
.addKeepMainRule(TestClass.class)
+ .addOptionsModification(
+ options ->
+ // TODO(b/236581210): I is spuriously reported as being "open" due to lossy joins in
+ // the analysis of cf code.
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.enableNoVerticalClassMergingAnnotations()
.enableNoHorizontalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java
index 836c703..307032a 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,6 +32,13 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options ->
+ // TODO(b/236581210): I is spuriously reported as being "open" due to lossy joins in
+ // the analysis of cf code.
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(I.class)))
.enableNoHorizontalClassMergingAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
index 077e3c2..7028257 100644
--- a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
+++ b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
@@ -4,7 +4,9 @@
package com.android.tools.r8.regress.b78493232;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.AsmTestBase;
@@ -96,12 +98,14 @@
diagnostics ->
diagnostics.assertWarningsMatch(
diagnosticMessage(
- equalTo(
- "Unverifiable code in `java.lang.String regress78493232.Test."
- + "methodCausingIssue(byte, short, int)` at instruction 53: "
- + "Cannot join stacks, expected frame types at stack index 1 "
- + "to join to a precise (non-top) type, but types null and "
- + "uninitialized java.lang.String do not."))))
+ allOf(
+ startsWith(
+ "Unverifiable code in `java.lang.String regress78493232.Test."
+ + "methodCausingIssue(byte, short, int)`"),
+ containsString(
+ "Cannot join stacks, expected frame types at stack index 1 "
+ + "to join to a precise (non-top) type, but types null "
+ + "and uninitialized java.lang.String do not.")))))
.run(parameters.getRuntime(), MAIN);
checkResult(result);
}
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
index 369d584..6740f60 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
@@ -10,18 +10,15 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -84,6 +81,7 @@
.addDontWarnGoogle()
.addDontWarnJavax()
.addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
+ .apply(this::suppressAllOpenInterfaces)
.compile();
}
@@ -97,6 +95,7 @@
.addDontWarnGoogle()
.addDontWarnJavax()
.addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
+ .apply(this::suppressAllOpenInterfaces)
.compile();
}
@@ -122,6 +121,7 @@
.addDontWarnGoogle()
.addDontWarnJavax()
.addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
+ .apply(this::suppressAllOpenInterfaces)
.compile()
.inspect(
inspector -> {
@@ -211,13 +211,9 @@
.addKeepMainRule(R8.class)
.addKeepClassRules(CLASS_WITH_ANNOTATED_METHOD)
.addKeepRules("-keepclassmembers class * { @" + PRESENT_ANNOTATION + " *** *(...); }")
- .addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
.addDontWarnGoogle()
.addDontWarnJavaxNullableAnnotation()
+ .apply(this::suppressAllOpenInterfaces)
.apply(this::configureHorizontalClassMerging)
.compile()
.graphInspector();
@@ -235,12 +231,8 @@
+ " *** *(...); }")
.addDontWarnGoogle()
.addDontWarnJavaxNullableAnnotation()
- .addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
.apply(this::configureHorizontalClassMerging)
+ .apply(this::suppressAllOpenInterfaces)
.compile()
.graphInspector();
assertRetainedClassesEqual(referenceInspector, ifThenKeepClassMembersInspector);
@@ -258,12 +250,8 @@
+ " *** *(...); }")
.addDontWarnGoogle()
.addDontWarnJavaxNullableAnnotation()
- .addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
.apply(this::configureHorizontalClassMerging)
+ .apply(this::suppressAllOpenInterfaces)
.compile()
.graphInspector();
assertRetainedClassesEqual(referenceInspector, ifThenKeepClassesWithMembersInspector);
@@ -283,12 +271,8 @@
+ " <2> <3>(...); }")
.addDontWarnGoogle()
.addDontWarnJavaxNullableAnnotation()
- .addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
.apply(this::configureHorizontalClassMerging)
+ .apply(this::suppressAllOpenInterfaces)
.compile()
.graphInspector();
assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector);
@@ -334,10 +318,9 @@
notInConditional);
}
- private void assertAllClassesAreSynthetics(Set<String> classNames) {
- for (String className : classNames) {
- ClassReference classReference = Reference.classFromTypeName(className);
- assertTrue(className, SyntheticItemsTestUtils.isExternalSynthetic(classReference));
- }
+ private void suppressAllOpenInterfaces(R8TestBuilder<?> testBuilder) {
+ // TODO(b/236581210): There should be no open interfaces.
+ testBuilder.addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces());
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
index 82d8fff..453028a 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
@@ -48,10 +48,9 @@
.addKeepRuleFiles(MAIN_KEEP)
.addKeepRules(WHY_ARE_YOU_KEEPING_ALL)
.addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressZipFileAssignmentsToJavaLangAutoCloseable())
+ // TODO(b/236581210): Should only suppress AutoCloseable due to assignments from
+ // ZipFile.
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.collectStdout()
.compile()
.assertStdoutThatMatches(containsString("referenced in keep rule"))