• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.auto.value.processor;
17 
18 import static com.google.common.collect.ImmutableList.toImmutableList;
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.testing.compile.JavaFileObjects;
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Locale;
29 import javax.tools.Diagnostic;
30 import javax.tools.JavaCompiler;
31 import javax.tools.JavaFileObject;
32 import javax.tools.ToolProvider;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.rules.TemporaryFolder;
36 import org.junit.runner.RunWith;
37 import org.junit.runners.JUnit4;
38 
39 @RunWith(JUnit4.class)
40 public final class AutoValueModuleCompilationTest {
41   @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
42 
43   /**
44    * This test currently confirms that AutoValue has a bug with module handling. If your AutoValue
45    * class inherits an abstract method from a module, and that abstract method has an annotation
46    * that is not exported from the module, then AutoValue will incorrectly try to copy the
47    * annotation onto the generated implementation of the abstract method.
48    */
49   @Test
nonVisibleMethodAnnotationFromOtherModule()50   public void nonVisibleMethodAnnotationFromOtherModule() throws Exception {
51     JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
52     Path tempDir = temporaryFolder.newFolder().toPath();
53     Path srcDir = tempDir.resolve("src");
54     Path outDir = tempDir.resolve("out");
55     Path fooOut = outDir.resolve("foo");
56     writeFile(srcDir, "foo/module-info.java", "module foo {", "  exports foo.exported;", "}");
57     writeFile(
58         srcDir,
59         "foo/exported/Foo.java",
60         "package foo.exported;",
61         "",
62         "import foo.unexported.UnexportedAnnotation;",
63         "",
64         "public interface Foo {",
65         "  @ExportedAnnotation",
66         "  @UnexportedAnnotation",
67         "  String name();",
68         "}");
69     writeFile(
70         srcDir,
71         "foo/exported/ExportedAnnotation.java",
72         "package foo.exported;",
73         "",
74         "import java.lang.annotation.*;",
75         "",
76         "@Retention(RetentionPolicy.RUNTIME)",
77         "public @interface ExportedAnnotation {}");
78     writeFile(
79         srcDir,
80         "foo/unexported/UnexportedAnnotation.java",
81         "package foo.unexported;",
82         "",
83         "import java.lang.annotation.*;",
84         "",
85         "@Retention(RetentionPolicy.RUNTIME)",
86         "public @interface UnexportedAnnotation {}");
87     JavaCompiler.CompilationTask fooCompilationTask =
88         javaCompiler.getTask(
89             /* out= */ null,
90             /* fileManager= */ null,
91             /* diagnosticListener= */ null,
92             /* options= */ ImmutableList.of(
93                 "--module",
94                 "foo",
95                 "-d",
96                 outDir.toString(),
97                 "--module-source-path",
98                 srcDir.toString()),
99             /* classes= */ null,
100             /* compilationUnits= */ null);
101     fooCompilationTask.setProcessors(ImmutableList.of(new AutoValueProcessor()));
102     boolean fooSuccess = fooCompilationTask.call();
103     assertThat(fooSuccess).isTrue();
104 
105     JavaFileObject barFile =
106         JavaFileObjects.forSourceLines(
107             "bar.Value",
108             "package bar;",
109             "",
110             "import com.google.auto.value.AutoValue;",
111             "import foo.exported.Foo;",
112             "",
113             "@AutoValue",
114             "public abstract class Value implements Foo {",
115             "  public static Value of(String name) {",
116             "    return new AutoValue_Value(name);",
117             "  }",
118             "}");
119     List<Diagnostic<?>> diagnostics = new ArrayList<>();
120     JavaCompiler.CompilationTask barCompilationTask =
121         javaCompiler.getTask(
122             /* out= */ null,
123             /* fileManager= */ null,
124             /* diagnosticListener= */ diagnostics::add,
125             /* options= */ ImmutableList.of(
126                 "-d",
127                 outDir.toString(),
128                 "--module-path",
129                 fooOut.toString(),
130                 "--add-modules",
131                 "foo"),
132             /* classes= */ null,
133             /* compilationUnits= */ ImmutableList.of(barFile));
134     boolean barSuccess = barCompilationTask.call();
135     assertThat(barSuccess).isFalse();
136     assertThat(
137             diagnostics.stream()
138                 .map(d -> d.getMessage(Locale.ROOT))
139                 .collect(toImmutableList())
140                 .toString())
141         .contains("package foo.unexported is declared in module foo, which does not export it");
142   }
143 
writeFile(Path srcDir, String relativeName, String... lines)144   private static void writeFile(Path srcDir, String relativeName, String... lines)
145       throws IOException {
146     Path path = srcDir.resolve(relativeName);
147     Files.createDirectories(path.getParent());
148     Files.writeString(path, String.join("\n", lines));
149   }
150 }
151