Fix failures from missing classes update
Change-Id: I727ce93f4965fc63bb00e986b2332353b99fe2c2
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
index de211e8..9fcf485 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
@@ -37,6 +37,9 @@
public void reportDesugarDependencies() {
forEachNest(
nest -> {
+ if (nest.hasMissingMembers()) {
+ throw appView.options().errorMissingNestMember(nest);
+ }
DexClass hostClass = nest.getHostClass();
for (DexClass memberClass : nest.getMembers()) {
if (hostClass.isProgramClass() || memberClass.isProgramClass()) {
@@ -44,6 +47,9 @@
reportDependencyEdge(memberClass, hostClass, appView.options());
}
}
+ },
+ classWithoutHost -> {
+ throw appView.options().errorMissingNestHost(classWithoutHost);
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/Nest.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/Nest.java
index 1e66edc..979eb9c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/Nest.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/Nest.java
@@ -11,6 +11,7 @@
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class Nest {
@@ -25,13 +26,19 @@
}
public static Nest create(AppView<?> appView, DexClass clazz) {
+ return create(appView, clazz, null);
+ }
+
+ public static Nest create(
+ AppView<?> appView, DexClass clazz, Consumer<DexClass> missingHostConsumer) {
assert clazz.isInANest();
DexClass hostClass = clazz.isNestHost() ? clazz : appView.definitionFor(clazz.getNestHost());
if (hostClass == null) {
// Missing nest host means the class is considered as not being part of a nest.
- clazz.clearNestHost();
- appView.options().nestDesugaringWarningMissingNestHost(clazz);
+ if (missingHostConsumer != null) {
+ missingHostConsumer.accept(clazz);
+ }
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index bab308e..cbaa05a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.desugar.nest;
+import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -76,13 +78,17 @@
}
void forEachNest(Consumer<Nest> consumer) {
+ forEachNest(consumer, emptyConsumer());
+ }
+
+ void forEachNest(Consumer<Nest> consumer, Consumer<DexClass> missingHostConsumer) {
Set<DexType> seenNestHosts = Sets.newIdentityHashSet();
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (!clazz.isInANest() || !seenNestHosts.add(clazz.getNestHost())) {
continue;
}
- Nest nest = Nest.create(appView, clazz);
+ Nest nest = Nest.create(appView, clazz, missingHostConsumer);
if (nest != null) {
consumer.accept(nest);
}
@@ -225,7 +231,7 @@
private RuntimeException reportIncompleteNest(LibraryMember<?, ?> member) {
Nest nest = Nest.create(appView, member.getHolder());
assert nest != null : "Should be a compilation error if missing nest host on library class.";
- throw appView.options().errorMissingClassIncompleteNest(nest);
+ throw appView.options().errorMissingNestMember(nest);
}
private DexProgramClass createNestAccessConstructor() {
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 9230427..a8bec4a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.ExperimentalClassFileVersionDiagnostic;
+import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.errors.InvalidLibrarySuperclassDiagnostic;
@@ -602,6 +603,7 @@
public boolean printCfg = false;
public String printCfgFile;
public boolean ignoreMissingClasses = false;
+
// EXPERIMENTAL flag to get behaviour as close to Proguard as possible.
public boolean forceProguardCompatibility = false;
public AssertionConfigurationWithDefault assertionsConfiguration = null;
@@ -789,42 +791,28 @@
private final Set<DexItem> invalidLibraryClasses = Sets.newConcurrentHashSet();
- public RuntimeException errorMissingClassMissingNestHost(DexClass compiledClass) {
- throw reporter.fatalError(messageErrorMissingNestHost(compiledClass));
- }
-
- public void nestDesugaringWarningMissingNestHost(DexClass compiledClass) {
- if (compiledClass.isLibraryClass()) {
- throw errorMissingClassMissingNestHost(compiledClass);
- }
- reporter.warning(
+ public RuntimeException errorMissingNestHost(DexClass clazz) {
+ throw reporter.fatalError(
new MissingNestHostNestDesugarDiagnostic(
- compiledClass.getOrigin(),
- Position.UNKNOWN,
- messageWarningMissingNestHost(compiledClass)));
+ clazz.getOrigin(), Position.UNKNOWN, messageErrorMissingNestHost(clazz)));
}
- public RuntimeException errorMissingClassIncompleteNest(Nest nest) {
- throw reporter.fatalError(messageErrorIncompleteNest(nest));
- }
-
- private String messageErrorMissingNestHost(DexClass compiledClass) {
+ private static String messageErrorMissingNestHost(DexClass compiledClass) {
String nestHostName = compiledClass.getNestHost().getName();
return "Class "
+ compiledClass.type.getName()
+ " requires its nest host "
+ nestHostName
- + " to be on program or class path. ";
+ + " to be on program or class path.";
}
- private String messageWarningMissingNestHost(DexClass compiledClass) {
- return messageErrorMissingNestHost(compiledClass)
- + "Class "
- + compiledClass.type.getName()
- + " is considered as not being part of any nest.";
+ public RuntimeException errorMissingNestMember(Nest nest) {
+ throw reporter.fatalError(
+ new IncompleteNestNestDesugarDiagnosic(
+ nest.getHostClass().getOrigin(), Position.UNKNOWN, messageErrorIncompleteNest(nest)));
}
- private String messageErrorIncompleteNest(Nest nest) {
+ private static String messageErrorIncompleteNest(Nest nest) {
List<DexProgramClass> programClassesFromNest = new ArrayList<>();
List<DexClasspathClass> classpathClassesFromNest = new ArrayList<>();
List<DexLibraryClass> libraryClassesFromNest = new ArrayList<>();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index 7dde5dc..07f4415 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -120,7 +121,9 @@
testForR8(parameters.getBackend())
.minification(minifying)
.addKeepMainRule(TEST_CLASS)
- .addDontWarnEmulatedLibraryClasses()
+ .applyIf(
+ parameters.getApiLevel().isLessThan(AndroidApiLevel.N),
+ TestShrinkerBuilder::addDontWarnEmulatedLibraryClasses)
.addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
index 62aa4a3..66e2ec7 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
@@ -58,12 +58,14 @@
}
@Test
- public void testWarningD8() throws Exception {
+ public void testD8() throws Exception {
Assume.assumeTrue(parameters.isDexRuntime());
- testIncompleteNestWarning(true, true);
- testMissingNestHostWarning(true, true);
+ testMissingNestHostError(true);
+ testIncompleteNestError(true);
}
-
+ // TODO R8:
+ // appView.options().reportMissingNestHost(clazz);
+ // clazz.clearNestHost();
@Test
public void testWarningR8() throws Exception {
testIncompleteNestWarning(false, parameters.isDexRuntime());
@@ -72,8 +74,8 @@
@Test
public void testErrorR8() {
- testMissingNestHostError();
- testIncompleteNestError();
+ testMissingNestHostError(false);
+ testIncompleteNestError(false);
}
private TestCompilerBuilder<?, ?, ?, ?, ?> compileOnlyClassesMatching(
@@ -106,23 +108,38 @@
}
}
- private void testMissingNestHostError() {
+ private void testMissingNestHostError(boolean d8) {
try {
Matcher<String> innerClassMatcher =
containsString("BasicNestHostWithInnerClassMethods$BasicNestedClass");
- compileOnlyClassesMatching(innerClassMatcher, false, false, false)
+ compileOnlyClassesMatching(innerClassMatcher, d8, false, false)
.compileWithExpectedDiagnostics(
diagnostics -> {
- diagnostics
- .assertOnlyErrors()
- .assertErrorsMatch(diagnosticType(MissingClassesDiagnostic.class));
+ if (d8) {
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(
+ diagnosticType(MissingNestHostNestDesugarDiagnostic.class));
- MissingClassesDiagnostic diagnostic =
- (MissingClassesDiagnostic) diagnostics.getErrors().get(0);
- assertEquals(1, diagnostic.getMissingClasses().size());
- assertEquals(
- "nesthostexample.BasicNestHostWithInnerClassMethods",
- diagnostic.getMissingClasses().iterator().next().getTypeName());
+ MissingNestHostNestDesugarDiagnostic diagnostic =
+ (MissingNestHostNestDesugarDiagnostic) diagnostics.getErrors().get(0);
+ assertEquals(
+ "Class BasicNestHostWithInnerClassMethods$BasicNestedClass requires its nest "
+ + "host BasicNestHostWithInnerClassMethods to be on program or class "
+ + "path.",
+ diagnostic.getDiagnosticMessage());
+ } else {
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(diagnosticType(MissingClassesDiagnostic.class));
+
+ MissingClassesDiagnostic diagnostic =
+ (MissingClassesDiagnostic) diagnostics.getErrors().get(0);
+ assertEquals(1, diagnostic.getMissingClasses().size());
+ assertEquals(
+ "nesthostexample.BasicNestHostWithInnerClassMethods",
+ diagnostic.getMissingClasses().iterator().next().getTypeName());
+ }
});
} catch (CompilationFailedException e) {
// Expected failure.
@@ -131,22 +148,37 @@
fail("Should have raised an exception for missing nest host");
}
- private void testIncompleteNestError() {
+ private void testIncompleteNestError(boolean d8) {
try {
Matcher<String> innerClassMatcher = endsWith("BasicNestHostWithInnerClassMethods");
- compileOnlyClassesMatching(innerClassMatcher, false, false, false)
+ compileOnlyClassesMatching(innerClassMatcher, d8, false, false)
.compileWithExpectedDiagnostics(
diagnostics -> {
- diagnostics
- .assertOnlyErrors()
- .assertErrorsMatch(diagnosticType(MissingClassesDiagnostic.class));
+ if (d8) {
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(diagnosticType(IncompleteNestNestDesugarDiagnosic.class));
- MissingClassesDiagnostic diagnostic =
- (MissingClassesDiagnostic) diagnostics.getErrors().get(0);
- assertEquals(1, diagnostic.getMissingClasses().size());
- assertEquals(
- "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass",
- diagnostic.getMissingClasses().iterator().next().getTypeName());
+ IncompleteNestNestDesugarDiagnosic diagnostic =
+ (IncompleteNestNestDesugarDiagnosic) diagnostics.getErrors().get(0);
+ assertEquals(
+ "Compilation of classes nesthostexample.BasicNestHostWithInnerClassMethods "
+ + "requires its nest mates "
+ + "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass "
+ + "(unavailable) to be on program or class path.",
+ diagnostic.getDiagnosticMessage());
+ } else {
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(diagnosticType(MissingClassesDiagnostic.class));
+
+ MissingClassesDiagnostic diagnostic =
+ (MissingClassesDiagnostic) diagnostics.getErrors().get(0);
+ assertEquals(1, diagnostic.getMissingClasses().size());
+ assertEquals(
+ "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass",
+ diagnostic.getMissingClasses().iterator().next().getTypeName());
+ }
});
} catch (Exception e) {
// Expected failure.