|
37 | 37 | import com.google.turbine.binder.ClassPathBinder;
|
38 | 38 | import com.google.turbine.binder.Processing;
|
39 | 39 | import com.google.turbine.binder.Processing.ProcessorInfo;
|
| 40 | +import com.google.turbine.binder.sym.ClassSymbol; |
40 | 41 | import com.google.turbine.diag.SourceFile;
|
41 | 42 | import com.google.turbine.diag.TurbineDiagnostic;
|
42 | 43 | import com.google.turbine.diag.TurbineError;
|
| 44 | +import com.google.turbine.diag.TurbineLog; |
43 | 45 | import com.google.turbine.lower.IntegrationTestSupport;
|
44 | 46 | import com.google.turbine.parse.Parser;
|
45 | 47 | import com.google.turbine.testing.TestClassPaths;
|
46 | 48 | import com.google.turbine.tree.Tree;
|
47 | 49 | import java.io.IOException;
|
| 50 | +import java.io.OutputStream; |
48 | 51 | import java.io.PrintWriter;
|
49 | 52 | import java.io.UncheckedIOException;
|
50 | 53 | import java.io.Writer;
|
51 | 54 | import java.net.URI;
|
| 55 | +import java.nio.file.Files; |
52 | 56 | import java.nio.file.Path;
|
53 | 57 | import java.nio.file.Paths;
|
| 58 | +import java.util.Map; |
54 | 59 | import java.util.Optional;
|
55 | 60 | import java.util.Set;
|
| 61 | +import java.util.jar.JarEntry; |
| 62 | +import java.util.jar.JarOutputStream; |
56 | 63 | import javax.annotation.processing.AbstractProcessor;
|
57 | 64 | import javax.annotation.processing.ProcessingEnvironment;
|
58 | 65 | import javax.annotation.processing.RoundEnvironment;
|
|
62 | 69 | import javax.lang.model.element.Element;
|
63 | 70 | import javax.lang.model.element.ExecutableElement;
|
64 | 71 | import javax.lang.model.element.TypeElement;
|
| 72 | +import javax.lang.model.type.DeclaredType; |
65 | 73 | import javax.lang.model.type.ExecutableType;
|
66 | 74 | import javax.tools.Diagnostic;
|
67 | 75 | import javax.tools.FileObject;
|
68 | 76 | import javax.tools.JavaFileObject;
|
69 | 77 | import javax.tools.StandardLocation;
|
| 78 | +import org.junit.Rule; |
70 | 79 | import org.junit.Test;
|
| 80 | +import org.junit.rules.TemporaryFolder; |
71 | 81 | import org.junit.runner.RunWith;
|
72 | 82 | import org.junit.runners.JUnit4;
|
73 | 83 |
|
74 | 84 | @RunWith(JUnit4.class)
|
75 | 85 | public class ProcessingIntegrationTest {
|
76 | 86 |
|
| 87 | + @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); |
| 88 | + |
77 | 89 | @SupportedAnnotationTypes("*")
|
78 | 90 | public static class CrashingProcessor extends AbstractProcessor {
|
79 | 91 |
|
@@ -864,4 +876,74 @@ public void uriProcessing() throws IOException {
|
864 | 876 | .map(d -> d.message()))
|
865 | 877 | .containsExactly("file:///foo/Bar - " + Paths.get(URI.create("file:///foo/Bar")));
|
866 | 878 | }
|
| 879 | + |
| 880 | + @SupportedAnnotationTypes("*") |
| 881 | + public static class MethodAnnotationTypeKindProcessor extends AbstractProcessor { |
| 882 | + @Override |
| 883 | + public SourceVersion getSupportedSourceVersion() { |
| 884 | + return SourceVersion.latestSupported(); |
| 885 | + } |
| 886 | + |
| 887 | + boolean first = true; |
| 888 | + |
| 889 | + @Override |
| 890 | + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { |
| 891 | + if (!first) { |
| 892 | + return false; |
| 893 | + } |
| 894 | + first = false; |
| 895 | + TypeElement e = processingEnv.getElementUtils().getTypeElement("T"); |
| 896 | + for (AnnotationMirror a : e.getAnnotationMirrors()) { |
| 897 | + DeclaredType t = a.getAnnotationType(); |
| 898 | + processingEnv |
| 899 | + .getMessager() |
| 900 | + .printMessage(Diagnostic.Kind.NOTE, t + "(" + t.getKind() + ")", e); |
| 901 | + // this shouldn't crash |
| 902 | + requireNonNull(a.getAnnotationType().asElement().getEnclosedElements()); |
| 903 | + } |
| 904 | + return false; |
| 905 | + } |
| 906 | + } |
| 907 | + |
| 908 | + @Test |
| 909 | + public void missingAnnotationType() throws IOException { |
| 910 | + Map<String, byte[]> library = |
| 911 | + IntegrationTestSupport.runTurbine( |
| 912 | + ImmutableMap.of( |
| 913 | + "A.java", // |
| 914 | + "@interface A {}", |
| 915 | + "T.java", |
| 916 | + "@A class T {}"), |
| 917 | + ImmutableList.of()); |
| 918 | + Path libJar = temporaryFolder.newFile("lib.jar").toPath(); |
| 919 | + try (OutputStream os = Files.newOutputStream(libJar); |
| 920 | + JarOutputStream jos = new JarOutputStream(os)) { |
| 921 | + // deliberately exclude the definition of the annotation |
| 922 | + jos.putNextEntry(new JarEntry("T.class")); |
| 923 | + jos.write(requireNonNull(library.get("T"))); |
| 924 | + } |
| 925 | + |
| 926 | + ImmutableList<Tree.CompUnit> units = |
| 927 | + parseUnit( |
| 928 | + "=== Y.java ===", // |
| 929 | + "class Y {}"); |
| 930 | + |
| 931 | + TurbineLog log = new TurbineLog(); |
| 932 | + BindingResult bound = |
| 933 | + Binder.bind( |
| 934 | + log, |
| 935 | + units, |
| 936 | + ClassPathBinder.bindClasspath(ImmutableList.of(libJar)), |
| 937 | + ProcessorInfo.create( |
| 938 | + ImmutableList.of(new MethodAnnotationTypeKindProcessor()), |
| 939 | + getClass().getClassLoader(), |
| 940 | + ImmutableMap.of(), |
| 941 | + SourceVersion.latestSupported()), |
| 942 | + TestClassPaths.TURBINE_BOOTCLASSPATH, |
| 943 | + Optional.empty()); |
| 944 | + assertThat(bound.units().keySet()).containsExactly(new ClassSymbol("Y")); |
| 945 | + ImmutableList<String> messages = |
| 946 | + log.diagnostics().stream().map(TurbineDiagnostic::message).collect(toImmutableList()); |
| 947 | + assertThat(messages).containsExactly("A(ERROR)"); |
| 948 | + } |
867 | 949 | }
|
0 commit comments