[ApiModel] Throw NoClassDefFoundError for mocked classes in clinit

Bug: 209803983
Bug: 138781768
Change-Id: I055ab49d8960e05e8daa1adcf3358b2035c209ed
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 6329ea5..5071174 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.ThrowExceptionCode;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -134,7 +135,12 @@
     if (libraryClassesToMock.isEmpty()) {
       return;
     }
-    libraryClassesToMock.forEach(this::mockMissingLibraryClass);
+    libraryClassesToMock.forEach(
+        (clazz, methods) ->
+            mockMissingLibraryClass(
+                clazz,
+                methods,
+                ThrowExceptionCode.create(appView.dexItemFactory().noClassDefFoundErrorType)));
     // Commit the synthetic items.
     CommittedItems committedItems = appView.getSyntheticItems().commit(appView.appInfo().app());
     if (appView.hasLiveness()) {
@@ -207,7 +213,10 @@
     }
   }
 
-  private void mockMissingLibraryClass(DexLibraryClass libraryClass, Set<DexMethod> methodsToStub) {
+  private void mockMissingLibraryClass(
+      DexLibraryClass libraryClass,
+      Set<DexMethod> methodsToStub,
+      ThrowExceptionCode throwExceptionCode) {
     if (libraryClass.getType() == appView.dexItemFactory().objectType
         || libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
       return;
@@ -237,12 +246,21 @@
               if (!libraryClass.isFinal()) {
                 classBuilder.unsetFinal();
               }
-              if (!libraryClass.isInterface()
-                  || appView.options().canUseDefaultAndStaticInterfaceMethods()) {
-                classBuilder.setDirectMethods(
-                    buildLibraryMethodsForProgram(
-                        libraryClass, libraryClass.directMethods(), methodsToStub));
-              }
+              List<DexEncodedMethod> directMethods =
+                  (!libraryClass.isInterface()
+                          || appView.options().canUseDefaultAndStaticInterfaceMethods())
+                      ? buildLibraryMethodsForProgram(
+                          libraryClass, libraryClass.directMethods(), methodsToStub)
+                      : new ArrayList<>();
+              // Add throwing static initializer
+              directMethods.add(
+                  DexEncodedMethod.syntheticBuilder()
+                      .setMethod(
+                          appView.dexItemFactory().createClassInitializer(libraryClass.getType()))
+                      .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+                      .setCode(throwExceptionCode)
+                      .build());
+              classBuilder.setDirectMethods(directMethods);
             });
   }
 
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
index 4db820e..ad0961d 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
@@ -51,11 +51,6 @@
         .compile()
         .applyIf(isLibraryOnBootClassPath, b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), NoClassDefFoundError.class)
-        // TODO(b/209803983): Should fail with a NoClassDefFoundError unless the api level of the
-        //  runtime >= 23.
-        .assertFailureWithErrorThatThrowsIf(
-            parameters.isDexRuntime() && !isLibraryOnBootClassPath, UnsatisfiedLinkError.class)
         .assertSuccessWithOutputLinesIf(isLibraryOnBootClassPath, "Hello World");
   }