Add a check in ImplementsValidator to catch shadow methods in Robolectric missing a @Implementation tag when it should be present.

PiperOrigin-RevId: 440949783
diff --git a/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java b/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java
index 9f46769..b834a2a 100644
--- a/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java
+++ b/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java
@@ -3,6 +3,7 @@
 import static org.robolectric.annotation.processing.validator.ImplementationValidator.METHODS_ALLOWED_TO_BE_PUBLIC;
 
 import com.google.auto.common.AnnotationValues;
+import com.google.auto.common.MoreElements;
 import com.sun.source.tree.ImportTree;
 import com.sun.source.util.Trees;
 import java.util.ArrayList;
@@ -210,7 +211,7 @@
   private void validateShadowMethods(TypeElement sdkClassElem, TypeElement shadowClassElem,
       int classMinSdk, int classMaxSdk, boolean looseSignatures) {
     for (Element memberElement : ElementFilter.methodsIn(shadowClassElem.getEnclosedElements())) {
-      ExecutableElement methodElement = (ExecutableElement) memberElement;
+      ExecutableElement methodElement = MoreElements.asExecutable(memberElement);
 
       // equals, hashCode, and toString are exempt, because of Robolectric's weird special behavior
       if (METHODS_ALLOWED_TO_BE_PUBLIC.contains(methodElement.getSimpleName().toString())) {
@@ -218,6 +219,11 @@
       }
 
       verifySdkMethod(sdkClassElem, methodElement, classMinSdk, classMaxSdk, looseSignatures);
+      if (shadowClassElem.getQualifiedName().toString().startsWith("org.robolectric")
+          && !methodElement.getModifiers().contains(Modifier.ABSTRACT)) {
+        checkForMissingImplementationAnnotation(
+            sdkClassElem, methodElement, classMinSdk, classMaxSdk, looseSignatures);
+      }
 
       String methodName = methodElement.getSimpleName().toString();
       if (methodName.equals(CONSTRUCTOR_METHOD_NAME)
@@ -257,6 +263,40 @@
     }
   }
 
+  /**
+   * For the given {@link ExecutableElement}, check to see if it should have a {@link
+   * Implementation} tag but is missing one
+   */
+  private void checkForMissingImplementationAnnotation(
+      TypeElement sdkClassElem,
+      ExecutableElement methodElement,
+      int classMinSdk,
+      int classMaxSdk,
+      boolean looseSignatures) {
+
+    if (sdkCheckMode == SdkCheckMode.OFF) {
+      return;
+    }
+
+    Implementation implementation = methodElement.getAnnotation(Implementation.class);
+    if (implementation == null) {
+      Kind kind = sdkCheckMode == SdkCheckMode.WARN ? Kind.WARNING : Kind.ERROR;
+      Problems problems = new Problems(kind);
+
+      for (SdkStore.Sdk sdk : sdkStore.sdksMatching(implementation, classMinSdk, classMaxSdk)) {
+        String problem = sdk.verifyMethod(sdkClassElem, methodElement, looseSignatures);
+        if (problem == null) {
+          problems.add(
+              "Missing @Implementation on method " + methodElement.getSimpleName(), sdk.sdkInt);
+        }
+      }
+
+      if (problems.any()) {
+        problems.recount(messager, methodElement);
+      }
+    }
+  }
+
   private void captureJavadoc(TypeElement elem) {
     List<String> imports = new ArrayList<>();
     try {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java
index 889d639..aadbf80 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java
@@ -70,6 +70,7 @@
     return result;
   }
 
+  @Implementation
   protected long addCompletedDownload(
       String title,
       String description,