D8 Nest based access constructor
- add NestConstructor synthetized class
- rewrite init to new init methods with NestConstructor param
Bug: 130529390
Change-Id: Ic0f7c5986ede324adcac9b20c396dbbec600089e
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 01fc41d..97fd72c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -731,6 +731,39 @@
return builder.build();
}
+ public DexEncodedMethod toInitializerForwardingBridge(
+ DexClass holder, DexDefinitionSupplier definitions, DexProgramClass nestConstructor) {
+ assert accessFlags.isPrivate()
+ : "Expected to create bridge for private constructor as part of nest-based access"
+ + " desugaring";
+ DexProto newProto =
+ definitions.dexItemFactory().appendTypeToProto(method.proto, nestConstructor.type);
+ DexMethod newMethod =
+ definitions.dexItemFactory().createMethod(method.holder, newProto, method.name);
+ Builder builder = builder(this);
+ builder.setMethod(newMethod);
+ builder.setCode(
+ new SynthesizedCode(
+ callerPosition ->
+ new ForwardMethodSourceCode(
+ holder.type,
+ newMethod,
+ newMethod,
+ holder.type,
+ method,
+ Invoke.Type.DIRECT,
+ callerPosition,
+ holder.isInterface(),
+ false,
+ true),
+ registry -> registry.registerInvokeDirect(method)));
+ assert !builder.accessFlags.isStatic();
+ builder.accessFlags.unsetPrivate();
+ builder.accessFlags.setSynthetic();
+ builder.accessFlags.setConstructor();
+ return builder.build();
+ }
+
public static DexEncodedMethod createFieldAccessorBridge(
DexFieldWithAccess fieldWithAccess,
DexClass holder,
@@ -783,7 +816,7 @@
DexProto proto =
accessFlags.isStatic()
? method.proto
- : definitions.dexItemFactory().createExtendedProto(holder.type, method.proto);
+ : definitions.dexItemFactory().prependTypeToProto(holder.type, method.proto);
DexMethod newMethod = definitions.dexItemFactory().createMethod(holder.type, proto, newName);
Builder builder = builder(this);
builder.setMethod(newMethod);
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 11f90fb..c1c8cc6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1054,7 +1054,7 @@
parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters));
}
- public DexProto createExtendedProto(DexType extraFirstType, DexProto initialProto) {
+ public DexProto prependTypeToProto(DexType extraFirstType, DexProto initialProto) {
DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
parameterTypes[0] = extraFirstType;
System.arraycopy(
@@ -1062,6 +1062,14 @@
return createProto(initialProto.returnType, parameterTypes);
}
+ public DexProto appendTypeToProto(DexProto initialProto, DexType extraLastType) {
+ DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
+ System.arraycopy(
+ initialProto.parameters.values, 0, parameterTypes, 0, initialProto.parameters.size());
+ parameterTypes[parameterTypes.length - 1] = extraLastType;
+ return createProto(initialProto.returnType, parameterTypes);
+ }
+
public DexProto applyClassMappingToProto(
DexProto proto, Function<DexType, DexType> mapping, Map<DexProto, DexProto> cache) {
assert cache != null;
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 41af11a..801d6f8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
+import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -248,6 +249,7 @@
|| name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX)
|| name.contains(OutlineOptions.CLASS_NAME)
|| name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME)
+ || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME)
|| name.contains(Java8MethodRewriter.UTILITY_CLASS_NAME_PREFIX);
}
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 0aed270..d104823 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
@@ -296,6 +296,12 @@
}
}
+ private void synthetizeNestConstructor(Builder<?> builder) {
+ if (nestBasedAccessDesugaringRewriter != null) {
+ nestBasedAccessDesugaringRewriter.synthetizeNestConstructor(builder);
+ }
+ }
+
private void synthesizeLambdaClasses(Builder<?> builder, ExecutorService executorService)
throws ExecutionException {
if (lambdaRewriter != null) {
@@ -361,6 +367,7 @@
Builder<?> builder = application.builder();
builder.setHighestSortingString(highestSortingString);
+ synthetizeNestConstructor(builder);
synthesizeLambdaClasses(builder, executor);
desugarInterfaceMethods(builder, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder, executor);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 4b64470..a309b6d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -1,7 +1,11 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -10,9 +14,12 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.origin.SynthesizedOrigin;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -33,20 +40,19 @@
private static final String NEST_ACCESS_FIELD_PUT_NAME_PREFIX = NEST_ACCESS_NAME_PREFIX + "fput";
private static final String NEST_ACCESS_STATIC_PUT_FIELD_NAME_PREFIX =
NEST_ACCESS_NAME_PREFIX + "sfput";
+ public static final String NEST_CONSTRUCTOR_NAME = NEST_ACCESS_NAME_PREFIX + "Constructor";
+ private static final String FULL_NEST_CONTRUCTOR_NAME = "L" + NEST_CONSTRUCTOR_NAME + ";";
- private final AppView<?> appView;
+ protected final AppView<?> appView;
private final HashMap<DexEncodedMethod, DexEncodedMethod> bridges = new HashMap<>();
private final HashMap<DexFieldWithAccess, DexEncodedMethod> fieldBridges = new HashMap<>();
private final HashMap<DexEncodedMethod, DexProgramClass> deferredBridgesToAdd = new HashMap<>();
+ private DexProgramClass nestConstructor;
public NestBasedAccessDesugaring(AppView<?> appView) {
this.appView = appView;
}
- public AppView<?> getAppView() {
- return appView;
- }
-
public void analyzeNests() {
// TODO(b/130529338) we don't need to compute a list with all live nests.
// we just need to iterate all live nests.
@@ -55,6 +61,13 @@
addDeferredBridges();
}
+ public void synthetizeNestConstructor(DexApplication.Builder<?> builder) {
+ if (nestConstructor != null) {
+ appView.appInfo().addSynthesizedClass(nestConstructor);
+ builder.addSynthesizedClass(nestConstructor, true);
+ }
+ }
+
private void addDeferredBridges() {
for (Map.Entry<DexEncodedMethod, DexProgramClass> entry : deferredBridgesToAdd.entrySet()) {
entry.getValue().addMethod(entry.getKey());
@@ -152,6 +165,8 @@
protected abstract void shouldRewriteCalls(DexMethod method, DexMethod bridge);
+ protected abstract void shouldRewriteInitializers(DexMethod method, DexMethod bridge);
+
protected abstract void shouldRewriteStaticGetFields(DexField field, DexMethod bridge);
protected abstract void shouldRewriteStaticPutFields(DexField field, DexMethod bridge);
@@ -197,6 +212,34 @@
return appView.dexItemFactory().createString(fullName);
}
+ private DexProgramClass ensureNestConstructorClass() {
+ if (nestConstructor != null) {
+ return nestConstructor;
+ }
+ nestConstructor =
+ new DexProgramClass(
+ appView.dexItemFactory().createType(FULL_NEST_CONTRUCTOR_NAME),
+ null,
+ new SynthesizedOrigin("Nest based access desugaring", getClass()),
+ // Make the synthesized class public since shared in the whole program.
+ ClassAccessFlags.fromDexAccessFlags(
+ Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
+ appView.dexItemFactory().objectType,
+ DexTypeList.empty(),
+ appView.dexItemFactory().createString("nest"),
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ appView.dexItemFactory().getSkipNameValidationForTesting());
+ return nestConstructor;
+ }
+
private class NestBasedAccessDesugaringUseRegistry extends UseRegistry {
private final List<DexType> nest;
@@ -216,17 +259,17 @@
if (target == null || !target.accessFlags.isPrivate()) {
return false;
}
- if (target.isInstanceInitializer()) {
- // TODO(b/130529338): support initializer
- return false;
- }
DexEncodedMethod bridge =
bridges.computeIfAbsent(
target,
k -> {
DexClass holder = appView.definitionFor(method.holder);
DexEncodedMethod localBridge =
- target.toStaticForwardingBridge(holder, appView, methodBridgeName(target));
+ target.isInstanceInitializer()
+ ? target.toInitializerForwardingBridge(
+ holder, appView, ensureNestConstructorClass())
+ : target.toStaticForwardingBridge(
+ holder, appView, methodBridgeName(target));
// Accesses to program classes private members require bridge insertion.
if (holder.isProgramClass()) {
deferredBridgesToAdd.put(localBridge, holder.asProgramClass());
@@ -237,7 +280,11 @@
});
// In program classes, any access to nest mate private member needs to be rewritten.
if (currentClass.isProgramClass()) {
- shouldRewriteCalls(method, bridge.method);
+ if (target.isInstanceInitializer()) {
+ shouldRewriteInitializers(method, bridge.method);
+ } else {
+ shouldRewriteCalls(method, bridge.method);
+ }
}
return true;
}
@@ -269,14 +316,14 @@
});
// In program classes, any access to nest mate private member needs to be rewritten.
if (currentClass.isProgramClass()) {
- if (isGet){
- if (target.isStatic()){
+ if (isGet) {
+ if (target.isStatic()) {
shouldRewriteStaticGetFields(field, bridge.method);
} else {
shouldRewriteInstanceGetFields(field, bridge.method);
}
} else {
- if (target.isStatic()){
+ if (target.isStatic()) {
shouldRewriteStaticPutFields(field, bridge.method);
} else {
shouldRewriteInstancePutFields(field, bridge.method);
@@ -328,7 +375,9 @@
@Override
public boolean registerNewInstance(DexType type) {
- // TODO(b/130529338): support initializer
+ // Unrelated to access based control.
+ // The <init> method has to be rewritten instead
+ // and <init> is called through registerInvoke.
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
index 6f44d56..b009861 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
@@ -15,7 +15,6 @@
}
public GraphLense run() {
- AppView<?> appView = this.getAppView();
if (appView.options().canUseNestBasedAccess()) {
return appView.graphLense();
}
@@ -24,27 +23,33 @@
}
@Override
+ protected void shouldRewriteInitializers(DexMethod method, DexMethod bridge) {
+ // TODO(b/130529338): support initializer in r8
+ // initializerMap.put(method, bridge);
+ }
+
+ @Override
protected void shouldRewriteCalls(DexMethod method, DexMethod bridge) {
builder.map(method, bridge);
}
@Override
protected void shouldRewriteStaticGetFields(DexField field, DexMethod bridge) {
- builder.mapStaticGet(field,bridge);
+ builder.mapStaticGet(field, bridge);
}
@Override
protected void shouldRewriteStaticPutFields(DexField field, DexMethod bridge) {
- builder.mapStaticPut(field,bridge);
+ builder.mapStaticPut(field, bridge);
}
@Override
protected void shouldRewriteInstanceGetFields(DexField field, DexMethod bridge) {
- builder.mapInstanceGet(field,bridge);
+ builder.mapInstanceGet(field, bridge);
}
@Override
protected void shouldRewriteInstancePutFields(DexField field, DexMethod bridge) {
- builder.mapInstancePut(field,bridge);
+ builder.mapInstancePut(field, bridge);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
index 7cec930..ed4cfbe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
@@ -8,16 +8,20 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
-import java.util.HashMap;
+import com.android.tools.r8.ir.code.Value;
+import java.util.ArrayList;
import java.util.IdentityHashMap;
+import java.util.List;
import java.util.ListIterator;
import java.util.Map;
public class NestBasedAccessDesugaringRewriter extends NestBasedAccessDesugaring {
- private HashMap<DexMethod, DexMethod> methodToRewrite = new HashMap<>();
+ private Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
+ private Map<DexMethod, DexMethod> initializerMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> staticGetToMethodMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> staticPutToMethodMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> instanceGetToMethodMap = new IdentityHashMap<>();
@@ -29,7 +33,12 @@
@Override
protected void shouldRewriteCalls(DexMethod method, DexMethod bridge) {
- methodToRewrite.put(method, bridge);
+ methodMap.put(method, bridge);
+ }
+
+ @Override
+ protected void shouldRewriteInitializers(DexMethod method, DexMethod bridge) {
+ initializerMap.put(method, bridge);
}
@Override
@@ -67,9 +76,6 @@
public void rewriteNestBasedAccesses(
DexEncodedMethod encodedMethod, IRCode code, AppView<?> appView) {
- if (methodToRewrite.isEmpty()) {
- return;
- }
ListIterator<BasicBlock> blocks = code.listIterator();
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
@@ -79,10 +85,23 @@
if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
InvokeMethod invokeMethod = instruction.asInvokeMethod();
DexMethod methodCalled = invokeMethod.getInvokedMethod();
- DexMethod newTarget = methodToRewrite.get(methodCalled);
+ DexMethod newTarget = methodMap.get(methodCalled);
if (newTarget != null && encodedMethod.method != newTarget) {
instructions.replaceCurrentInstruction(
new InvokeStatic(newTarget, invokeMethod.outValue(), invokeMethod.arguments()));
+ } else {
+ newTarget = initializerMap.get(methodCalled);
+ if (newTarget != null && encodedMethod.method != newTarget) {
+ // insert extra null value and replace call.
+ instructions.previous();
+ Value extraNullValue =
+ instructions.insertConstNullInstruction(code, appView.options());
+ instructions.next();
+ List<Value> parameters = new ArrayList<>(invokeMethod.arguments());
+ parameters.add(extraNullValue);
+ instructions.replaceCurrentInstruction(
+ new InvokeDirect(newTarget, invokeMethod.outValue(), parameters));
+ }
}
} else if (instruction.isInstanceGet()) {
rewriteFieldAccess(
@@ -95,7 +114,6 @@
} else if (instruction.isStaticPut()) {
rewriteFieldAccess(instruction, instructions, encodedMethod.method, staticPutToMethodMap);
}
- // TODO(b/130529338): support initializers
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index 76dba16..c49c3e1 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
@@ -24,6 +25,7 @@
private final Invoke.Type invokeType;
private final boolean castResult;
private final boolean isInterface;
+ private final boolean extraNullParameter;
public ForwardMethodSourceCode(
DexType receiver,
@@ -56,6 +58,30 @@
Position callerPosition,
boolean isInterface,
boolean castResult) {
+ this(
+ receiver,
+ method,
+ originalMethod,
+ targetReceiver,
+ target,
+ invokeType,
+ callerPosition,
+ isInterface,
+ castResult,
+ false);
+ }
+
+ public ForwardMethodSourceCode(
+ DexType receiver,
+ DexMethod method,
+ DexMethod originalMethod,
+ DexType targetReceiver,
+ DexMethod target,
+ Type invokeType,
+ Position callerPosition,
+ boolean isInterface,
+ boolean castResult,
+ boolean extraNullParameter) {
super(receiver, method, callerPosition, originalMethod);
assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
@@ -64,6 +90,7 @@
this.invokeType = invokeType;
this.isInterface = isInterface;
this.castResult = castResult;
+ this.extraNullParameter = extraNullParameter;
assert checkSignatures();
switch (invokeType) {
@@ -84,6 +111,9 @@
sourceParams.add(receiver);
}
sourceParams.addAll(Lists.newArrayList(proto.parameters.values));
+ if (extraNullParameter) {
+ sourceParams.remove(sourceParams.size() - 1);
+ }
List<DexType> targetParams = new ArrayList<>();
if (targetReceiver != null) {
@@ -118,7 +148,7 @@
}
DexType[] accessorParams = proto.parameters.values;
- for (int i = 0; i < accessorParams.length; i++) {
+ for (int i = 0; i < accessorParams.length - BooleanUtils.intValue(extraNullParameter); i++) {
argValueTypes.add(ValueType.fromDexType(accessorParams[i]));
argRegisters.add(getParamRegister(i));
}
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index b71e9e1..25c61d8 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -951,8 +951,7 @@
Rename.ALWAYS,
appView
.dexItemFactory()
- .createExtendedProto(
- virtualMethod.method.holder, virtualMethod.method.proto));
+ .prependTypeToProto(virtualMethod.method.holder, virtualMethod.method.proto));
makeStatic(resultingDirectMethod);
// Update method pool collection now that we are adding a new public method.
diff --git a/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
index d40cc47..1fa9dd9 100644
--- a/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
@@ -133,7 +132,7 @@
this.parameters = parameters;
}
- public void testJavaAndD8(String id, boolean d8Success) throws Exception {
+ public void testJavaAndD8(String id) throws Exception {
if (parameters.isCfRuntime()) {
testForJvm()
.addProgramFiles(JAR)
@@ -141,32 +140,20 @@
.assertSuccessWithOutput(getExpectedResult(id));
} else {
assert parameters.isDexRuntime();
- D8TestRunResult run =
- d8CompilationResult
- .apply(parameters.getApiLevel())
- .run(parameters.getRuntime(), getMainClass(id));
- if (d8Success) {
- run.assertSuccessWithOutput(getExpectedResult(id));
- } else {
- if (parameters.isDexRuntime()
- && (parameters.getRuntime().asDex().getVm().getVersion() == Version.V6_0_1
- || parameters.getRuntime().asDex().getVm().getVersion() == Version.V5_1_1)) {
- run.assertFailure(); // different message, same error
- } else {
- run.assertFailureWithErrorThatMatches(containsString("IllegalAccessError"));
- }
- }
+ d8CompilationResult
+ .apply(parameters.getApiLevel())
+ .run(parameters.getRuntime(), getMainClass(id))
+ .assertSuccessWithOutput(getExpectedResult(id));
}
}
@Test
public void testJavaAndD8() throws Exception {
- // TODO(b/130529390): As features are implemented, set success to true in each line.
- testJavaAndD8("methods", true);
- testJavaAndD8("fields", true);
- testJavaAndD8("constructors", false);
- testJavaAndD8("anonymous", true);
- testJavaAndD8("all", false);
+ testJavaAndD8("methods");
+ testJavaAndD8("fields");
+ testJavaAndD8("constructors");
+ testJavaAndD8("anonymous");
+ testJavaAndD8("all");
}
public void testR8(String id, boolean r8Success) throws Exception {