Add Local Type Annotation Use Desugaring

- Strips out type annotation reference from the method code session
- Type annotation use isn't supported in Java 7, and the Java7-undefined RuntimeVisibleTypeAnnotation attribute confuses D8 (b/149232699).

PiperOrigin-RevId: 302912545
diff --git a/src/test/java/com/google/devtools/build/android/desugar/BUILD b/src/test/java/com/google/devtools/build/android/desugar/BUILD
index dede1e9..590f41e 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/BUILD
+++ b/src/test/java/com/google/devtools/build/android/desugar/BUILD
@@ -19,6 +19,7 @@
         "//src/test/java/com/google/devtools/build/android/desugar/langmodel:srcs",
         "//src/test/java/com/google/devtools/build/android/desugar/nest:srcs",
         "//src/test/java/com/google/devtools/build/android/desugar/covariantreturn:srcs",
+        "//src/test/java/com/google/devtools/build/android/desugar/typeannotation:srcs",
         "//src/test/java/com/google/devtools/build/android/desugar/runtime:srcs",
         "//src/test/java/com/google/devtools/build/android/desugar/scan:srcs",
         "//src/test/java/com/google/devtools/build/android/desugar/stringconcat:srcs",
diff --git a/src/test/java/com/google/devtools/build/android/desugar/typeannotation/AnnotationUser.java b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/AnnotationUser.java
new file mode 100644
index 0000000..3adc41a
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/AnnotationUser.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 The Bazel Authors. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.build.android.desugar.typeannotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/** The test source class for testing annotation desugaring. */
+public class AnnotationUser {
+
+  @SuppressWarnings("unused") // Test source
+  public void localVarWithTypeUseAnnotation(List<String> inTextList) {
+    List<@EnhancedType String> localTextList = inTextList;
+  }
+
+  public void instructionTypeUseAnnotation() {
+    new ArrayList<@EnhancedType String>();
+  }
+
+  public void tryCatchTypeAnnotation(RuntimeException inException) {
+    try {
+      throw inException;
+    } catch (@EnhancedType IllegalArgumentException e) {
+      throw new UnsupportedOperationException(e);
+    }
+  }
+
+  // @EnhancedVar is expected to be absent in Javac-compiled bytecode, even through @EnhancedVar is
+  // declared with a runtime retention policy. This test case ensures any retained annotation use
+  // within a method body is a type annotation.
+  @SuppressWarnings("unused") // Test source
+  public Function<Integer, Integer> localNonTypeAnnotations(String inputText) {
+    @EnhancedVar String localText = inputText;
+    try {
+      return (@EnhancedVar Integer x) -> 2 * x;
+    } catch (@EnhancedVar IllegalStateException e) {
+      throw new UnsupportedOperationException(e);
+    }
+  }
+
+  @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface EnhancedType {}
+
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface EnhancedVar {}
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/typeannotation/BUILD b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/BUILD
new file mode 100644
index 0000000..c513585
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/BUILD
@@ -0,0 +1,48 @@
+load("@rules_java//java:defs.bzl", "java_test")
+
+package(
+    default_testonly = 1,
+    default_visibility = ["//src/test/java/com/google/devtools/build/android/desugar:__subpackages__"],
+)
+
+licenses(["notice"])  # Apache 2.0
+
+java_test(
+    name = "LocalTypeAnnotationUseTest",
+    size = "medium",
+    srcs = ["LocalTypeAnnotationUseTest.java"],
+    data = [
+        ":annotation_test_src",
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit:android_jar_for_testing",
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit:jacoco_agent_jar",
+    ],
+    jvm_flags = [
+        "-Dinput_srcs=$(locations :annotation_test_src)",
+        # Required by Desugar#verifyLambdaDumpDirectoryRegistered
+        "-Djdk.internal.lambda.dumpProxyClasses=$$(mktemp -d)",
+        "-Dandroid_runtime_jar=$(location //src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit:android_jar_for_testing)",
+        "-Djacoco_agent_jar=$(location //src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit:jacoco_agent_jar)",
+    ],
+    test_class = "com.google.devtools.build.android.desugar.typeannotation.LocalTypeAnnotationUseTest",
+    deps = [
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit:desugar_rule",
+        "//third_party:asm",
+        "//third_party:asm-tree",
+        "//third_party:guava",
+        "//third_party:jsr305",
+        "//third_party:jsr330_inject",
+        "//third_party:junit4",
+        "//third_party:truth",
+    ],
+)
+
+filegroup(
+    name = "annotation_test_src",
+    srcs = ["AnnotationUser.java"],
+)
+
+filegroup(
+    name = "srcs",
+    testonly = 0,
+    srcs = glob(["*"]),
+)
diff --git a/src/test/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUseTest.java b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUseTest.java
new file mode 100644
index 0000000..0d3f8bb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUseTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 The Bazel Authors. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.build.android.desugar.typeannotation;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.testing.junit.DesugarTestHelpers.filterInstructions;
+import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN;
+
+import com.google.devtools.build.android.desugar.testing.junit.AsmNode;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRunner;
+import com.google.devtools.build.android.desugar.testing.junit.JdkSuppress;
+import com.google.devtools.build.android.desugar.testing.junit.JdkVersion;
+import java.lang.invoke.MethodHandles;
+import java.util.Arrays;
+import java.util.Objects;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.objectweb.asm.tree.MethodNode;
+
+/** Tests for desugaring annotations. */
+@RunWith(DesugarRunner.class)
+@JdkSuppress(minJdkVersion = JdkVersion.V11)
+public class LocalTypeAnnotationUseTest {
+
+  @Rule
+  public final DesugarRule desugarRule =
+      DesugarRule.builder(this, MethodHandles.lookup())
+          .addSourceInputsFromJvmFlag("input_srcs")
+          .addJavacOptions("-source 11", "-target 11")
+          .setWorkingJavaPackage("com.google.devtools.build.android.desugar.typeannotation")
+          .addCommandOptions("desugar_try_with_resources_if_needed", "true")
+          .build();
+
+  @Test
+  public void localNonTypeAnnotationsWithRuntimeRetention_discardedByJavac(
+      @AsmNode(className = "AnnotationUser", memberName = "localNonTypeAnnotations", round = 0)
+          MethodNode before) {
+    assertThat(before.visibleLocalVariableAnnotations).isNull();
+    assertThat(
+            Arrays.stream(before.instructions.toArray())
+                .map(insn -> insn.visibleTypeAnnotations)
+                .allMatch(Objects::isNull))
+        .isTrue();
+  }
+
+  @Test
+  public void localVarWithTypeUseAnnotation(
+      @AsmNode(
+              className = "AnnotationUser",
+              memberName = "localVarWithTypeUseAnnotation",
+              round = 0)
+          MethodNode before,
+      @AsmNode(
+              className = "AnnotationUser",
+              memberName = "localVarWithTypeUseAnnotation",
+              round = 1)
+          MethodNode after) {
+    assertThat(before.visibleLocalVariableAnnotations).isNotEmpty();
+    assertThat(after.visibleLocalVariableAnnotations).isNull();
+  }
+
+  @Test
+  public void instructionTypeUseAnnotation(
+      @AsmNode(className = "AnnotationUser", memberName = "instructionTypeUseAnnotation", round = 0)
+          MethodNode before,
+      @AsmNode(className = "AnnotationUser", memberName = "instructionTypeUseAnnotation", round = 1)
+          MethodNode after) {
+    assertThat(getOnlyElement(filterInstructions(before, TYPE_INSN)).visibleTypeAnnotations)
+        .isNotEmpty();
+    assertThat(getOnlyElement(filterInstructions(after, TYPE_INSN)).visibleTypeAnnotations)
+        .isNull();
+  }
+
+  @Test
+  public void tryCatchTypeAnnotation(
+      @AsmNode(className = "AnnotationUser", memberName = "tryCatchTypeAnnotation", round = 0)
+          MethodNode before,
+      @AsmNode(className = "AnnotationUser", memberName = "tryCatchTypeAnnotation", round = 1)
+          MethodNode after) {
+    assertThat(getOnlyElement(before.tryCatchBlocks).visibleTypeAnnotations).isNotEmpty();
+    assertThat(getOnlyElement(after.tryCatchBlocks).visibleTypeAnnotations).isNull();
+  }
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD b/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
index 959a814..a078e03 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
@@ -46,6 +46,7 @@
         "//src/tools/android/java/com/google/devtools/build/android/desugar/langmodel",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/nest",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/strconcat",
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation",
         "//third_party:asm",
         "//third_party:asm-commons",
         "//third_party:asm-tree",
@@ -72,6 +73,7 @@
         "//src/tools/android/java/com/google/devtools/build/android/desugar/langmodel:srcs",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/nest:srcs",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/covariantreturn:srcs",
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation:srcs",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:srcs",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/strconcat:srcs",
         "//src/tools/android/java/com/google/devtools/build/android/desugar/scan:srcs",
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
index 9eff3bc..0353151 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
@@ -45,6 +45,7 @@
 import com.google.devtools.build.android.desugar.nest.NestDesugaring;
 import com.google.devtools.build.android.desugar.nest.NestDigest;
 import com.google.devtools.build.android.desugar.strconcat.IndyStringConcatDesugaring;
+import com.google.devtools.build.android.desugar.typeannotation.LocalTypeAnnotationUse;
 import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest;
 import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse;
 import com.google.devtools.common.options.Option;
@@ -1067,6 +1068,8 @@
 
     visitor = NioBufferRefConverter.create(visitor, rewriter.getPrefixer());
 
+    visitor = new LocalTypeAnnotationUse(visitor);
+
     return visitor;
   }
 
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarTestHelpers.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarTestHelpers.java
index 2292776..7acfd6f 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarTestHelpers.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarTestHelpers.java
@@ -37,6 +37,8 @@
 /** Static utilities that facilities desugar testing. */
 public class DesugarTestHelpers {
 
+  private DesugarTestHelpers() {}
+
   /**
    * A helper method that reads file paths into an array from the JVM flag value associated with
    * {@param jvmFlagKey}.
@@ -61,9 +63,7 @@
     Predicate<String> methodOwnerPredicate = Pattern.compile(methodOwnerRegex).asPredicate();
     Predicate<String> methodNamePredicate = Pattern.compile(methodNameRegex).asPredicate();
     Predicate<String> methodDescPredicate = Pattern.compile(methodDescRegex).asPredicate();
-    AbstractInsnNode[] instructions = enclosingMethod.instructions.toArray();
-    return Arrays.stream(instructions)
-        .filter(node -> node.getType() == AbstractInsnNode.METHOD_INSN)
+    return filterInstructions(enclosingMethod, AbstractInsnNode.METHOD_INSN).stream()
         .map(node -> (MethodInsnNode) node)
         .filter(node -> methodOwnerPredicate.test(node.owner))
         .filter(node -> methodNamePredicate.test(node.name))
@@ -78,5 +78,10 @@
         .collect(toImmutableList());
   }
 
-  private DesugarTestHelpers() {}
+  public static ImmutableList<AbstractInsnNode> filterInstructions(
+      MethodNode enclosingMethod, int instructionType) {
+    return Arrays.stream(enclosingMethod.instructions.toArray())
+        .filter(node -> node.getType() == instructionType)
+        .collect(toImmutableList());
+  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/BUILD b/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/BUILD
new file mode 100644
index 0000000..01b7825
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/BUILD
@@ -0,0 +1,28 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(
+    default_visibility = [
+        "//src/test/java/com/google/devtools/build/android/desugar:__subpackages__",
+        "//src/tools/android/java/com/google/devtools/build/android/desugar:__subpackages__",
+    ],
+)
+
+java_library(
+    name = "typeannotation",
+    srcs = glob(["*.java"]),
+    deps = [
+        "//src/tools/android/java/com/google/devtools/build/android/desugar/langmodel",
+        "//third_party:asm",
+        "//third_party:asm-commons",
+        "//third_party:asm-tree",
+        "//third_party:auto_value",
+        "//third_party:guava",
+        "//third_party:jsr305",
+    ],
+)
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+    visibility = ["//src/tools/android/java/com/google/devtools/build/android/desugar:__pkg__"],
+)
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUse.java b/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUse.java
new file mode 100644
index 0000000..9aafc77
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/typeannotation/LocalTypeAnnotationUse.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2020 The Bazel Authors. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.build.android.desugar.typeannotation;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.TypePath;
+
+/** Desugars bytecode instructions with references to type annotations. */
+public class LocalTypeAnnotationUse extends ClassVisitor {
+
+  public LocalTypeAnnotationUse(ClassVisitor classVisitor) {
+    super(Opcodes.ASM7, classVisitor);
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      int access, String name, String descriptor, String signature, String[] exceptions) {
+    MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
+    return mv == null ? null : new LocalTypeAnnotationUseMethodVisitor(api, mv);
+  }
+
+  private static class LocalTypeAnnotationUseMethodVisitor extends MethodVisitor {
+
+    LocalTypeAnnotationUseMethodVisitor(int api, MethodVisitor methodVisitor) {
+      super(api, methodVisitor);
+    }
+
+    @Override
+    public AnnotationVisitor visitLocalVariableAnnotation(
+        int typeRef,
+        TypePath typePath,
+        Label[] start,
+        Label[] end,
+        int[] index,
+        String descriptor,
+        boolean visible) {
+      // The visited annotation has to be a type annotation. A LOCAL_VARIABLE-targeted annotation
+      // isn't retained in bytecode, regardless of retention policy. See details at,
+      // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.6.4.2
+      return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitInsnAnnotation(
+        int typeRef, TypePath typePath, String descriptor, boolean visible) {
+      // An instruction annotation has to be a type annotation.
+      return null;
+    }
+
+    @Override
+    public AnnotationVisitor visitTryCatchAnnotation(
+        int typeRef, TypePath typePath, String descriptor, boolean visible) {
+      // An exception parameter annotation present in Javac-compiled bytecode has to be a type
+      // annotation. See the JLS link in visitLocalVariableAnnotation of this class.
+      return null;
+    }
+  }
+}