1 /* 2 * Copyright 2018 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.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION; 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.TruthJUnit.assume; 21 import static com.google.testing.compile.CompilationSubject.assertThat; 22 import static com.google.testing.compile.CompilationSubject.compilations; 23 import static com.google.testing.compile.Compiler.javac; 24 import static java.util.Arrays.stream; 25 import static java.util.stream.Collectors.joining; 26 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableMap; 29 import com.google.common.collect.ImmutableSet; 30 import com.google.common.truth.Expect; 31 import com.google.testing.compile.Compilation; 32 import com.google.testing.compile.JavaFileObjects; 33 import java.io.IOException; 34 import java.io.PrintWriter; 35 import java.io.UncheckedIOException; 36 import java.io.Writer; 37 import java.lang.annotation.Retention; 38 import java.lang.annotation.RetentionPolicy; 39 import java.util.Set; 40 import javax.annotation.processing.AbstractProcessor; 41 import javax.annotation.processing.RoundEnvironment; 42 import javax.annotation.processing.SupportedAnnotationTypes; 43 import javax.lang.model.SourceVersion; 44 import javax.lang.model.element.Element; 45 import javax.lang.model.element.TypeElement; 46 import javax.lang.model.element.TypeParameterElement; 47 import javax.lang.model.util.ElementFilter; 48 import javax.tools.JavaFileObject; 49 import org.junit.Rule; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.junit.runners.JUnit4; 53 54 /** @author [email protected] (Éamonn McManus) */ 55 @RunWith(JUnit4.class) 56 public class AutoValueCompilationTest { 57 @Rule public final Expect expect = Expect.create(); 58 59 // Sadly we can't rely on JDK 8 to handle type annotations correctly. 60 // Some versions do, some don't. So skip the test unless we are on at least JDK 9. 61 private boolean typeAnnotationsWork = 62 Double.parseDouble(JAVA_SPECIFICATION_VERSION.value()) >= 9.0; 63 64 @Test simpleSuccess()65 public void simpleSuccess() { 66 // Positive test case that ensures we generate the expected code for at least one case. 67 // Most AutoValue code-generation tests are functional, meaning that we check that the generated 68 // code does the right thing rather than checking what it looks like, but this test checks that 69 // we are not generating correct but weird code. 70 JavaFileObject javaFileObject = 71 JavaFileObjects.forSourceLines( 72 "foo.bar.Baz", 73 "package foo.bar;", 74 "", 75 "import com.google.auto.value.AutoValue;", 76 "", 77 "@AutoValue", 78 "public abstract class Baz {", 79 " public abstract long buh();", 80 "", 81 " public static Baz create(long buh) {", 82 " return new AutoValue_Baz(buh);", 83 " }", 84 "}"); 85 JavaFileObject expectedOutput = 86 JavaFileObjects.forSourceLines( 87 "foo.bar.AutoValue_Baz", 88 "package foo.bar;", 89 "", 90 GeneratedImport.importGeneratedAnnotationType(), 91 "", 92 "@Generated(\"" + AutoValueProcessor.class.getName() + "\")", 93 "final class AutoValue_Baz extends Baz {", 94 " private final long buh;", 95 "", 96 " AutoValue_Baz(long buh) {", 97 " this.buh = buh;", 98 " }", 99 "", 100 " @Override public long buh() {", 101 " return buh;", 102 " }", 103 "", 104 " @Override public String toString() {", 105 " return \"Baz{\"", 106 " + \"buh=\" + buh", 107 " + \"}\";", 108 " }", 109 "", 110 " @Override public boolean equals(Object o) {", 111 " if (o == this) {", 112 " return true;", 113 " }", 114 " if (o instanceof Baz) {", 115 " Baz that = (Baz) o;", 116 " return this.buh == that.buh();", 117 " }", 118 " return false;", 119 " }", 120 "", 121 " @Override public int hashCode() {", 122 " int h$ = 1;", 123 " h$ *= 1000003;", 124 " h$ ^= (int) ((buh >>> 32) ^ buh);", 125 " return h$;", 126 " }", 127 "}"); 128 Compilation compilation = 129 javac() 130 .withProcessors(new AutoValueProcessor()) 131 .withOptions("-A" + Nullables.NULLABLE_OPTION + "=") 132 .compile(javaFileObject); 133 assertThat(compilation) 134 .generatedSourceFile("foo.bar.AutoValue_Baz") 135 .hasSourceEquivalentTo(expectedOutput); 136 } 137 138 @Test importTwoWays()139 public void importTwoWays() { 140 // Test that referring to the same class in two different ways does not confuse the import logic 141 // into thinking it is two different classes and that therefore it can't import. The code here 142 // is nonsensical but successfully reproduces a real problem, which is that a TypeMirror that is 143 // extracted using Elements.getTypeElement(name).asType() does not compare equal to one that is 144 // extracted from ExecutableElement.getReturnType(), even though Types.isSameType considers them 145 // equal. So unless we are careful, the java.util.Arrays that we import explicitly to use its 146 // methods will appear different from the java.util.Arrays that is the return type of the 147 // arrays() method here. 148 JavaFileObject javaFileObject = 149 JavaFileObjects.forSourceLines( 150 "foo.bar.Baz", 151 "package foo.bar;", 152 "", 153 "import com.google.auto.value.AutoValue;", 154 "", 155 "import java.util.Arrays;", 156 "", 157 "@AutoValue", 158 "public abstract class Baz {", 159 " @SuppressWarnings(\"mutable\")", 160 " public abstract int[] ints();", 161 " public abstract Arrays arrays();", 162 "", 163 " public static Baz create(int[] ints, Arrays arrays) {", 164 " return new AutoValue_Baz(ints, arrays);", 165 " }", 166 "}"); 167 JavaFileObject expectedOutput = 168 JavaFileObjects.forSourceLines( 169 "foo.bar.AutoValue_Baz", 170 "package foo.bar;", 171 "", 172 "import java.util.Arrays;", 173 GeneratedImport.importGeneratedAnnotationType(), 174 "", 175 "@Generated(\"" + AutoValueProcessor.class.getName() + "\")", 176 "final class AutoValue_Baz extends Baz {", 177 " private final int[] ints;", 178 " private final Arrays arrays;", 179 "", 180 " AutoValue_Baz(int[] ints, Arrays arrays) {", 181 " if (ints == null) {", 182 " throw new NullPointerException(\"Null ints\");", 183 " }", 184 " this.ints = ints;", 185 " if (arrays == null) {", 186 " throw new NullPointerException(\"Null arrays\");", 187 " }", 188 " this.arrays = arrays;", 189 " }", 190 "", 191 " @SuppressWarnings(\"mutable\")", 192 " @Override public int[] ints() {", 193 " return ints;", 194 " }", 195 "", 196 " @Override public Arrays arrays() {", 197 " return arrays;", 198 " }", 199 "", 200 " @Override public String toString() {", 201 " return \"Baz{\"", 202 " + \"ints=\" + Arrays.toString(ints) + \", \"", 203 " + \"arrays=\" + arrays", 204 " + \"}\";", 205 " }", 206 "", 207 " @Override public boolean equals(Object o) {", 208 " if (o == this) {", 209 " return true;", 210 " }", 211 " if (o instanceof Baz) {", 212 " Baz that = (Baz) o;", 213 " return Arrays.equals(this.ints, (that instanceof AutoValue_Baz) " 214 + "? ((AutoValue_Baz) that).ints : that.ints())", 215 " && this.arrays.equals(that.arrays());", 216 " }", 217 " return false;", 218 " }", 219 "", 220 " @Override public int hashCode() {", 221 " int h$ = 1;", 222 " h$ *= 1000003;", 223 " h$ ^= Arrays.hashCode(ints);", 224 " h$ *= 1000003;", 225 " h$ ^= arrays.hashCode();", 226 " return h$;", 227 " }", 228 "}"); 229 Compilation compilation = 230 javac() 231 .withProcessors(new AutoValueProcessor()) 232 .withOptions("-A" + Nullables.NULLABLE_OPTION + "=") 233 .compile(javaFileObject); 234 assertThat(compilation) 235 .generatedSourceFile("foo.bar.AutoValue_Baz") 236 .hasSourceEquivalentTo(expectedOutput); 237 } 238 239 @Test testNoWarningsFromGenerics()240 public void testNoWarningsFromGenerics() { 241 JavaFileObject javaFileObject = 242 JavaFileObjects.forSourceLines( 243 "foo.bar.Baz", 244 "package foo.bar;", 245 "import com.google.auto.value.AutoValue;", 246 "@AutoValue", 247 "public abstract class Baz<T extends Number, U extends T> {", 248 " public abstract T t();", 249 " public abstract U u();", 250 " public static <T extends Number, U extends T> Baz<T, U> create(T t, U u) {", 251 " return new AutoValue_Baz<T, U>(t, u);", 252 " }", 253 "}"); 254 Compilation compilation = 255 javac() 256 .withProcessors(new AutoValueProcessor()) 257 .withOptions("-Xlint:-processing", "-implicit:none") 258 .compile(javaFileObject); 259 assertThat(compilation).succeededWithoutWarnings(); 260 } 261 262 @Test testNestedParameterizedTypesWithTypeAnnotations()263 public void testNestedParameterizedTypesWithTypeAnnotations() { 264 assume().that(typeAnnotationsWork).isTrue(); 265 JavaFileObject annotFileObject = 266 JavaFileObjects.forSourceLines( 267 "foo.bar.Annot", 268 "package foo.bar;", 269 "", 270 "import java.lang.annotation.ElementType;", 271 "import java.lang.annotation.Target;", 272 "", 273 "@Target(ElementType.TYPE_USE)", 274 "public @interface Annot {", 275 " int value();", 276 "}"); 277 JavaFileObject outerFileObject = 278 JavaFileObjects.forSourceLines( 279 "foo.baz.OuterWithTypeParam", 280 "package foo.baz;", 281 "", 282 "public class OuterWithTypeParam<T extends Number> {", 283 " public class InnerWithTypeParam<U> {}", 284 "}"); 285 JavaFileObject nestyFileObject = 286 JavaFileObjects.forSourceLines( 287 "com.example.Nesty", 288 "package com.example;", 289 "", 290 "import com.google.auto.value.AutoValue;", 291 "import foo.bar.Annot;", 292 "import foo.baz.OuterWithTypeParam;", 293 "", 294 "@AutoValue", 295 "abstract class Nesty {", 296 " abstract @Annot(1) OuterWithTypeParam<@Annot(2) Double>", 297 " .@Annot(3) InnerWithTypeParam<@Annot(4) String> inner();", 298 "", 299 " static Nesty of(", 300 " @Annot(1) OuterWithTypeParam<@Annot(2) Double>", 301 " .@Annot(3) InnerWithTypeParam<@Annot(4) String> inner) {", 302 " return new AutoValue_Nesty(inner);", 303 " }", 304 "}"); 305 JavaFileObject expectedOutput = 306 JavaFileObjects.forSourceLines( 307 "com.example.AutoValue_Nesty", 308 "package com.example;", 309 "", 310 "import foo.bar.Annot;", 311 "import foo.baz.OuterWithTypeParam;", 312 GeneratedImport.importGeneratedAnnotationType(), 313 "", 314 "@Generated(\"com.google.auto.value.processor.AutoValueProcessor\")", 315 "final class AutoValue_Nesty extends Nesty {", 316 " private final @Annot(1) OuterWithTypeParam<@Annot(2) Double>" 317 + ".@Annot(3) InnerWithTypeParam<@Annot(4) String> inner;", 318 "", 319 " AutoValue_Nesty(", 320 " @Annot(1) OuterWithTypeParam<@Annot(2) Double>" 321 + ".@Annot(3) InnerWithTypeParam<@Annot(4) String> inner) {", 322 " if (inner == null) {", 323 " throw new NullPointerException(\"Null inner\");", 324 " }", 325 " this.inner = inner;", 326 " }", 327 "", 328 " @Override", 329 " @Annot(1) OuterWithTypeParam<@Annot(2) Double>" 330 + ".@Annot(3) InnerWithTypeParam<@Annot(4) String> inner() {", 331 " return inner;", 332 " }", 333 "", 334 " @Override", 335 " public String toString() {", 336 " return \"Nesty{\"", 337 " + \"inner=\" + inner", 338 " + \"}\";", 339 " }", 340 "", 341 " @Override", 342 " public boolean equals(Object o) {", 343 " if (o == this) {", 344 " return true;", 345 " }", 346 " if (o instanceof Nesty) {", 347 " Nesty that = (Nesty) o;", 348 " return this.inner.equals(that.inner());", 349 " }", 350 " return false;", 351 " }", 352 "", 353 " @Override", 354 " public int hashCode() {", 355 " int h$ = 1;", 356 " h$ *= 1000003;", 357 " h$ ^= inner.hashCode();", 358 " return h$;", 359 " }", 360 "}"); 361 362 Compilation compilation = 363 javac() 364 .withProcessors(new AutoValueProcessor()) 365 .withOptions( 366 "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=") 367 .compile(annotFileObject, outerFileObject, nestyFileObject); 368 assertThat(compilation).succeededWithoutWarnings(); 369 assertThat(compilation) 370 .generatedSourceFile("com.example.AutoValue_Nesty") 371 .hasSourceEquivalentTo(expectedOutput); 372 } 373 374 // Tests that type annotations are correctly copied from the bounds of type parameters in the 375 // @AutoValue class to the bounds of the corresponding parameters in the generated class. For 376 // example, if we have `@AutoValue abstract class Foo<T extends @NullableType Object>`, then the 377 // generated class should be `class AutoValue_Foo<T extends @NullableType Object> extends Foo<T>`. 378 // Some buggy versions of javac do not report type annotations correctly in this context. 379 // AutoValue can't copy them if it can't see them, so we make a special annotation processor to 380 // detect if we are in the presence of this bug and if so we don't fail. 381 @Test testTypeParametersWithAnnotationsOnBounds()382 public void testTypeParametersWithAnnotationsOnBounds() { 383 @SupportedAnnotationTypes("*") 384 class CompilerBugProcessor extends AbstractProcessor { 385 boolean checkedAnnotationsOnTypeBounds; 386 boolean reportsAnnotationsOnTypeBounds; 387 388 @Override 389 public SourceVersion getSupportedSourceVersion() { 390 return SourceVersion.latestSupported(); 391 } 392 393 @Override 394 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 395 if (roundEnv.processingOver()) { 396 TypeElement test = processingEnv.getElementUtils().getTypeElement("com.example.Test"); 397 TypeParameterElement t = test.getTypeParameters().get(0); 398 this.checkedAnnotationsOnTypeBounds = true; 399 this.reportsAnnotationsOnTypeBounds = 400 !t.getBounds().get(0).getAnnotationMirrors().isEmpty(); 401 } 402 return false; 403 } 404 } 405 CompilerBugProcessor compilerBugProcessor = new CompilerBugProcessor(); 406 JavaFileObject nullableTypeFileObject = 407 JavaFileObjects.forSourceLines( 408 "foo.bar.NullableType", 409 "package foo.bar;", 410 "", 411 "import java.lang.annotation.ElementType;", 412 "import java.lang.annotation.Target;", 413 "", 414 "@Target(ElementType.TYPE_USE)", 415 "public @interface NullableType {}"); 416 JavaFileObject autoValueFileObject = 417 JavaFileObjects.forSourceLines( 418 "com.example.Test", 419 "package com.example;", 420 "", 421 "import com.google.auto.value.AutoValue;", 422 "import foo.bar.NullableType;", 423 "", 424 "@AutoValue", 425 "abstract class Test<T extends @NullableType Object & @NullableType Cloneable> {}"); 426 Compilation compilation = 427 javac() 428 .withProcessors(new AutoValueProcessor(), compilerBugProcessor) 429 .withOptions("-Xlint:-processing", "-implicit:none") 430 .compile(nullableTypeFileObject, autoValueFileObject); 431 assertThat(compilation).succeededWithoutWarnings(); 432 assertThat(compilerBugProcessor.checkedAnnotationsOnTypeBounds).isTrue(); 433 if (compilerBugProcessor.reportsAnnotationsOnTypeBounds) { 434 assertThat(compilation) 435 .generatedSourceFile("com.example.AutoValue_Test") 436 .contentsAsUtf8String() 437 .contains( 438 "class AutoValue_Test<T extends @NullableType Object & @NullableType Cloneable>" 439 + " extends Test<T> {"); 440 } 441 } 442 443 // In the following few tests, see AutoValueProcessor.validateMethods for why unrecognized 444 // abstract methods provoke only a warning rather than an error. Compilation will fail anyway 445 // because the generated class is not abstract and does not implement the unrecognized methods. 446 447 @Test testAbstractVoid()448 public void testAbstractVoid() { 449 JavaFileObject javaFileObject = 450 JavaFileObjects.forSourceLines( 451 "foo.bar.Baz", 452 "package foo.bar;", 453 "import com.google.auto.value.AutoValue;", 454 "@AutoValue", 455 "public abstract class Baz {", 456 " public abstract void foo();", 457 "}"); 458 Compilation compilation = 459 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 460 assertThat(compilation).failed(); 461 assertThat(compilation) 462 .hadWarningContaining( 463 "Abstract method is neither a property getter nor a Builder converter") 464 .inFile(javaFileObject) 465 .onLineContaining("void foo()"); 466 } 467 468 @Test testAbstractWithParams()469 public void testAbstractWithParams() { 470 JavaFileObject javaFileObject = 471 JavaFileObjects.forSourceLines( 472 "foo.bar.Baz", 473 "package foo.bar;", 474 "import com.google.auto.value.AutoValue;", 475 "@AutoValue", 476 "public abstract class Baz {", 477 " public abstract int foo(int bar);", 478 "}"); 479 Compilation compilation = 480 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 481 assertThat(compilation).failed(); 482 assertThat(compilation) 483 .hadWarningContaining( 484 "Abstract method is neither a property getter nor a Builder converter") 485 .inFile(javaFileObject) 486 .onLineContaining("int foo(int bar)"); 487 } 488 489 @Test testPrimitiveArrayWarning()490 public void testPrimitiveArrayWarning() { 491 JavaFileObject javaFileObject = 492 JavaFileObjects.forSourceLines( 493 "foo.bar.Baz", 494 "package foo.bar;", 495 "import com.google.auto.value.AutoValue;", 496 "@AutoValue", 497 "public abstract class Baz {", 498 " public abstract byte[] bytes();", 499 " public static Baz create(byte[] bytes) {", 500 " return new AutoValue_Baz(bytes);", 501 " }", 502 "}"); 503 Compilation compilation = 504 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 505 assertThat(compilation).succeeded(); 506 assertThat(compilation) 507 .hadWarningContaining( 508 "An @AutoValue property that is a primitive array returns the original array") 509 .inFile(javaFileObject) 510 .onLineContaining("byte[] bytes()"); 511 } 512 513 @Test testPrimitiveArrayWarningFromParent()514 public void testPrimitiveArrayWarningFromParent() { 515 // If the array-valued property is defined by an ancestor then we shouldn't try to attach 516 // the warning to the method that defined it, but rather to the @AutoValue class itself. 517 JavaFileObject javaFileObject = 518 JavaFileObjects.forSourceLines( 519 "foo.bar.Baz", 520 "package foo.bar;", 521 "import com.google.auto.value.AutoValue;", 522 "public abstract class Baz {", 523 " public abstract byte[] bytes();", 524 "", 525 " @AutoValue", 526 " public abstract static class BazChild extends Baz {", 527 " public static BazChild create(byte[] bytes) {", 528 " return new AutoValue_Baz_BazChild(bytes);", 529 " }", 530 " }", 531 "}"); 532 Compilation compilation = 533 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 534 assertThat(compilation).succeeded(); 535 assertThat(compilation) 536 .hadWarningContainingMatch( 537 "An @AutoValue property that is a primitive array returns the original array" 538 + ".*foo\\.bar\\.Baz\\.bytes") 539 .inFile(javaFileObject) 540 .onLineContaining("BazChild extends Baz"); 541 } 542 543 @Test testPrimitiveArrayWarningSuppressed()544 public void testPrimitiveArrayWarningSuppressed() { 545 JavaFileObject javaFileObject = 546 JavaFileObjects.forSourceLines( 547 "foo.bar.Baz", 548 "package foo.bar;", 549 "import com.google.auto.value.AutoValue;", 550 "@AutoValue", 551 "public abstract class Baz {", 552 " @SuppressWarnings(\"mutable\")", 553 " public abstract byte[] bytes();", 554 " public static Baz create(byte[] bytes) {", 555 " return new AutoValue_Baz(bytes);", 556 " }", 557 "}"); 558 Compilation compilation = 559 javac() 560 .withProcessors(new AutoValueProcessor()) 561 .withOptions("-Xlint:-processing", "-implicit:none") 562 .compile(javaFileObject); 563 assertThat(compilation).succeededWithoutWarnings(); 564 } 565 566 @Test autoValueMustBeClass()567 public void autoValueMustBeClass() { 568 JavaFileObject javaFileObject = 569 JavaFileObjects.forSourceLines( 570 "foo.bar.Baz", 571 "package foo.bar;", 572 "", 573 "import com.google.auto.value.AutoValue;", 574 "", 575 "@AutoValue", 576 "public interface Baz {", 577 " String buh();", 578 "}"); 579 Compilation compilation = 580 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 581 assertThat(compilation) 582 .hadErrorContaining("@AutoValue only applies to classes") 583 .inFile(javaFileObject) 584 .onLineContaining("interface Baz"); 585 } 586 587 @Test autoValueMustNotBeFinal()588 public void autoValueMustNotBeFinal() { 589 JavaFileObject javaFileObject = 590 JavaFileObjects.forSourceLines( 591 "foo.bar.Baz", 592 "package foo.bar;", 593 "", 594 "import com.google.auto.value.AutoValue;", 595 "", 596 "@AutoValue", 597 "public final class Baz {", 598 " public Baz create() {", 599 " return new AutoValue_Baz();", 600 " }", 601 "}"); 602 Compilation compilation = 603 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 604 assertThat(compilation) 605 .hadErrorContaining("@AutoValue class must not be final") 606 .inFile(javaFileObject) 607 .onLineContaining("class Baz"); 608 } 609 610 @Test autoValueMustBeStatic()611 public void autoValueMustBeStatic() { 612 JavaFileObject javaFileObject = 613 JavaFileObjects.forSourceLines( 614 "foo.bar.Baz", 615 "package foo.bar;", 616 "", 617 "import com.google.auto.value.AutoValue;", 618 "", 619 "public class Baz {", 620 " @AutoValue", 621 " public abstract class NotStatic {", 622 " public abstract String buh();", 623 " public NotStatic create(String buh) {", 624 " return new AutoValue_Baz_NotStatic(buh);", 625 " }", 626 " }", 627 "}"); 628 Compilation compilation = 629 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 630 assertThat(compilation) 631 .hadErrorContaining("Nested @AutoValue class must be static") 632 .inFile(javaFileObject) 633 .onLineContaining("abstract class NotStatic"); 634 } 635 636 @Test autoValueMustNotBePrivate()637 public void autoValueMustNotBePrivate() { 638 JavaFileObject javaFileObject = 639 JavaFileObjects.forSourceLines( 640 "foo.bar.Baz", 641 "package foo.bar;", 642 "", 643 "import com.google.auto.value.AutoValue;", 644 "", 645 "public class Baz {", 646 " @AutoValue", 647 " private abstract static class Private {", 648 " public abstract String buh();", 649 " public Private create(String buh) {", 650 " return new AutoValue_Baz_Private(buh);", 651 " }", 652 " }", 653 "}"); 654 Compilation compilation = 655 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 656 assertThat(compilation) 657 .hadErrorContaining("@AutoValue class must not be private") 658 .inFile(javaFileObject) 659 .onLineContaining("class Private"); 660 } 661 662 @Test autoValueMustBeNotBeNestedInPrivate()663 public void autoValueMustBeNotBeNestedInPrivate() { 664 JavaFileObject javaFileObject = 665 JavaFileObjects.forSourceLines( 666 "foo.bar.Baz", 667 "package foo.bar;", 668 "", 669 "import com.google.auto.value.AutoValue;", 670 "", 671 "public class Baz {", 672 " private static class Private {", 673 " @AutoValue", 674 " abstract static class Nested {", 675 " public abstract String buh();", 676 " public Nested create(String buh) {", 677 " return new AutoValue_Baz_Private_Nested(buh);", 678 " }", 679 " }", 680 " }", 681 "}"); 682 Compilation compilation = 683 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 684 assertThat(compilation) 685 .hadErrorContaining("@AutoValue class must not be nested in a private class") 686 .inFile(javaFileObject) 687 .onLineContaining("class Nested"); 688 } 689 690 @Test autoValueMustHaveNoArgConstructor()691 public void autoValueMustHaveNoArgConstructor() { 692 JavaFileObject javaFileObject = 693 JavaFileObjects.forSourceLines( 694 "foo.bar.Baz", 695 "package foo.bar;", 696 "", 697 "import com.google.auto.value.AutoValue;", 698 "", 699 "@AutoValue", 700 "public abstract class Baz {", 701 " Baz(int buh) {}", 702 "", 703 " public abstract int buh();", 704 "}"); 705 Compilation compilation = 706 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 707 assertThat(compilation) 708 .hadErrorContaining("@AutoValue class must have a non-private no-arg constructor") 709 .inFile(javaFileObject) 710 .onLineContaining("class Baz"); 711 } 712 713 @Test autoValueMustHaveVisibleNoArgConstructor()714 public void autoValueMustHaveVisibleNoArgConstructor() { 715 JavaFileObject javaFileObject = 716 JavaFileObjects.forSourceLines( 717 "foo.bar.Baz", 718 "package foo.bar;", 719 "", 720 "import com.google.auto.value.AutoValue;", 721 "", 722 "@AutoValue", 723 "public abstract class Baz {", 724 " private Baz() {}", 725 "", 726 " public abstract int buh();", 727 "}"); 728 Compilation compilation = 729 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 730 assertThat(compilation) 731 .hadErrorContaining("@AutoValue class must have a non-private no-arg constructor") 732 .inFile(javaFileObject) 733 .onLineContaining("class Baz"); 734 } 735 736 @Test noMultidimensionalPrimitiveArrays()737 public void noMultidimensionalPrimitiveArrays() { 738 JavaFileObject javaFileObject = 739 JavaFileObjects.forSourceLines( 740 "foo.bar.Baz", 741 "package foo.bar;", 742 "", 743 "import com.google.auto.value.AutoValue;", 744 "", 745 "@AutoValue", 746 "public abstract class Baz {", 747 " public abstract int[][] ints();", 748 "", 749 " public static Baz create(int[][] ints) {", 750 " return new AutoValue_Baz(ints);", 751 " }", 752 "}"); 753 Compilation compilation = 754 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 755 assertThat(compilation) 756 .hadErrorContaining( 757 "@AutoValue class cannot define an array-valued property " 758 + "unless it is a primitive array") 759 .inFile(javaFileObject) 760 .onLineContaining("int[][] ints()"); 761 } 762 763 @Test noObjectArrays()764 public void noObjectArrays() { 765 JavaFileObject javaFileObject = 766 JavaFileObjects.forSourceLines( 767 "foo.bar.Baz", 768 "package foo.bar;", 769 "", 770 "import com.google.auto.value.AutoValue;", 771 "", 772 "@AutoValue", 773 "public abstract class Baz {", 774 " public abstract String[] strings();", 775 "", 776 " public static Baz create(String[] strings) {", 777 " return new AutoValue_Baz(strings);", 778 " }", 779 "}"); 780 Compilation compilation = 781 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 782 assertThat(compilation) 783 .hadErrorContaining( 784 "@AutoValue class cannot define an array-valued property " 785 + "unless it is a primitive array") 786 .inFile(javaFileObject) 787 .onLineContaining("String[] strings()"); 788 } 789 790 @Test annotationOnInterface()791 public void annotationOnInterface() { 792 JavaFileObject javaFileObject = 793 JavaFileObjects.forSourceLines( 794 "foo.bar.Baz", 795 "package foo.bar;", 796 "", 797 "import com.google.auto.value.AutoValue;", 798 "", 799 "@AutoValue", 800 "public interface Baz {}"); 801 Compilation compilation = 802 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 803 assertThat(compilation) 804 .hadErrorContaining("AutoValue only applies to classes") 805 .inFile(javaFileObject) 806 .onLineContaining("interface Baz"); 807 } 808 809 @Test annotationOnEnum()810 public void annotationOnEnum() { 811 JavaFileObject javaFileObject = 812 JavaFileObjects.forSourceLines( 813 "foo.bar.Baz", 814 "package foo.bar;", 815 "", 816 "import com.google.auto.value.AutoValue;", 817 "", 818 "@AutoValue", 819 "public enum Baz {}"); 820 Compilation compilation = 821 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 822 assertThat(compilation) 823 .hadErrorContaining("AutoValue only applies to classes") 824 .inFile(javaFileObject) 825 .onLineContaining("enum Baz"); 826 } 827 828 @Test extendAutoValue()829 public void extendAutoValue() { 830 JavaFileObject javaFileObject = 831 JavaFileObjects.forSourceLines( 832 "foo.bar.Outer", 833 "package foo.bar;", 834 "", 835 "import com.google.auto.value.AutoValue;", 836 "", 837 "public class Outer {", 838 " @AutoValue", 839 " static abstract class Parent {", 840 " static Parent create(int randomProperty) {", 841 " return new AutoValue_Outer_Parent(randomProperty);", 842 " }", 843 "", 844 " abstract int randomProperty();", 845 " }", 846 "", 847 " @AutoValue", 848 " static abstract class Child extends Parent {", 849 " static Child create(int randomProperty) {", 850 " return new AutoValue_Outer_Child(randomProperty);", 851 " }", 852 "", 853 " abstract int randomProperty();", 854 " }", 855 "}"); 856 Compilation compilation = 857 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 858 assertThat(compilation) 859 .hadErrorContaining("may not extend") 860 .inFile(javaFileObject) 861 .onLineContaining("Child extends Parent"); 862 } 863 864 @Test bogusSerialVersionUID()865 public void bogusSerialVersionUID() { 866 String[] mistakes = { 867 "final long serialVersionUID = 1234L", // not static 868 "static long serialVersionUID = 1234L", // not final 869 "static final Long serialVersionUID = 1234L", // not long 870 "static final long serialVersionUID = (Long) 1234L", // not a compile-time constant 871 }; 872 for (String mistake : mistakes) { 873 JavaFileObject javaFileObject = 874 JavaFileObjects.forSourceLines( 875 "foo.bar.Baz", 876 "package foo.bar;", 877 "", 878 "import com.google.auto.value.AutoValue;", 879 "", 880 "@AutoValue", 881 "public abstract class Baz implements java.io.Serializable {", 882 " " + mistake + ";", 883 "", 884 " public abstract int foo();", 885 "}"); 886 Compilation compilation = 887 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 888 expect 889 .about(compilations()) 890 .that(compilation) 891 .hadErrorContaining("serialVersionUID must be a static final long compile-time constant") 892 .inFile(javaFileObject) 893 .onLineContaining(mistake); 894 } 895 } 896 897 @Test nonExistentSuperclass()898 public void nonExistentSuperclass() { 899 // The main purpose of this test is to check that AutoValueProcessor doesn't crash the 900 // compiler in this case. 901 JavaFileObject javaFileObject = 902 JavaFileObjects.forSourceLines( 903 "foo.bar.Baz", 904 "package foo.bar;", 905 "", 906 "import com.google.auto.value.AutoValue;", 907 "", 908 "@AutoValue", 909 "public abstract class Existent extends NonExistent {", 910 "}"); 911 Compilation compilation = 912 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 913 assertThat(compilation) 914 .hadErrorContaining("NonExistent") 915 .inFile(javaFileObject) 916 .onLineContaining("NonExistent"); 917 } 918 919 @Test cannotImplementAnnotation()920 public void cannotImplementAnnotation() { 921 JavaFileObject javaFileObject = 922 JavaFileObjects.forSourceLines( 923 "foo.bar.RetentionImpl", 924 "package foo.bar;", 925 "", 926 "import com.google.auto.value.AutoValue;", 927 "import java.lang.annotation.Retention;", 928 "import java.lang.annotation.RetentionPolicy;", 929 "", 930 "@AutoValue", 931 "public abstract class RetentionImpl implements Retention {", 932 " public static Retention create(RetentionPolicy policy) {", 933 " return new AutoValue_RetentionImpl(policy);", 934 " }", 935 "", 936 " @Override public Class<? extends Retention> annotationType() {", 937 " return Retention.class;", 938 " }", 939 "", 940 " @Override public boolean equals(Object o) {", 941 " return (o instanceof Retention && value().equals((Retention) o).value());", 942 " }", 943 "", 944 " @Override public int hashCode() {", 945 " return (\"value\".hashCode() * 127) ^ value().hashCode();", 946 " }", 947 "}"); 948 Compilation compilation = 949 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 950 assertThat(compilation) 951 .hadErrorContaining("may not be used to implement an annotation interface") 952 .inFile(javaFileObject) 953 .onLineContaining("RetentionImpl implements Retention"); 954 } 955 956 @Test missingPropertyType()957 public void missingPropertyType() { 958 JavaFileObject javaFileObject = 959 JavaFileObjects.forSourceLines( 960 "foo.bar.Baz", 961 "package foo.bar;", 962 "", 963 "import com.google.auto.value.AutoValue;", 964 "", 965 "@AutoValue", 966 "public abstract class Baz {", 967 " public abstract MissingType missingType();", 968 "}"); 969 Compilation compilation = 970 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 971 assertThat(compilation) 972 .hadErrorContaining("MissingType") 973 .inFile(javaFileObject) 974 .onLineContaining("MissingType"); 975 assertThat(compilation) 976 .hadErrorContaining("references undefined types including MissingType"); 977 } 978 979 @Test missingGenericPropertyType()980 public void missingGenericPropertyType() { 981 JavaFileObject javaFileObject = 982 JavaFileObjects.forSourceLines( 983 "foo.bar.Baz", 984 "package foo.bar;", 985 "", 986 "import com.google.auto.value.AutoValue;", 987 "", 988 "@AutoValue", 989 "public abstract class Baz {", 990 " public abstract MissingType<?> missingType();", 991 "}"); 992 Compilation compilation = 993 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 994 assertThat(compilation) 995 .hadErrorContaining("MissingType") 996 .inFile(javaFileObject) 997 .onLineContaining("MissingType"); 998 } 999 1000 @Test missingComplexGenericPropertyType()1001 public void missingComplexGenericPropertyType() { 1002 JavaFileObject javaFileObject = 1003 JavaFileObjects.forSourceLines( 1004 "foo.bar.Baz", 1005 "package foo.bar;", 1006 "", 1007 "import com.google.auto.value.AutoValue;", 1008 "", 1009 "import java.util.Map;", 1010 "import java.util.Set;", 1011 "", 1012 "@AutoValue", 1013 "public abstract class Baz {", 1014 " public abstract Map<Set<?>, MissingType<?>> missingType();", 1015 "}"); 1016 Compilation compilation = 1017 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 1018 assertThat(compilation) 1019 .hadErrorContaining("MissingType") 1020 .inFile(javaFileObject) 1021 .onLineContaining("MissingType"); 1022 } 1023 1024 @Test missingSuperclassGenericParameter()1025 public void missingSuperclassGenericParameter() { 1026 JavaFileObject javaFileObject = 1027 JavaFileObjects.forSourceLines( 1028 "foo.bar.Baz", 1029 "package foo.bar;", 1030 "", 1031 "import com.google.auto.value.AutoValue;", 1032 "", 1033 "@AutoValue", 1034 "public abstract class Baz<T extends MissingType<?>> {", 1035 " public abstract int foo();", 1036 "}"); 1037 Compilation compilation = 1038 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 1039 assertThat(compilation) 1040 .hadErrorContaining("MissingType") 1041 .inFile(javaFileObject) 1042 .onLineContaining("MissingType"); 1043 } 1044 1045 @Test nullablePrimitive()1046 public void nullablePrimitive() { 1047 JavaFileObject javaFileObject = 1048 JavaFileObjects.forSourceLines( 1049 "foo.bar.Baz", 1050 "package foo.bar;", 1051 "", 1052 "import com.google.auto.value.AutoValue;", 1053 "", 1054 "@AutoValue", 1055 "public abstract class Baz {", 1056 " @interface Nullable {}", 1057 " public abstract @Nullable int foo();", 1058 "}"); 1059 Compilation compilation = 1060 javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject); 1061 assertThat(compilation) 1062 .hadErrorContaining("Primitive types cannot be @Nullable") 1063 .inFile(javaFileObject) 1064 .onLineContaining("@Nullable int"); 1065 } 1066 1067 @Test correctBuilder()1068 public void correctBuilder() { 1069 JavaFileObject javaFileObject = 1070 JavaFileObjects.forSourceLines( 1071 "foo.bar.Baz", 1072 "package foo.bar;", 1073 "", 1074 "import com.google.auto.value.AutoValue;", 1075 "import com.google.common.base.Optional;", 1076 "import com.google.common.collect.ImmutableMap;", 1077 "", 1078 "import java.util.ArrayList;", 1079 "import java.util.List;", 1080 "import java.util.Map;", 1081 "import javax.annotation.Nullable;", 1082 "", 1083 "@AutoValue", 1084 "public abstract class Baz<T extends Number> {", 1085 " public abstract int anInt();", 1086 " @SuppressWarnings(\"mutable\")", 1087 " public abstract byte[] aByteArray();", 1088 " @SuppressWarnings(\"mutable\")", 1089 " @Nullable public abstract int[] aNullableIntArray();", 1090 " public abstract List<T> aList();", 1091 " public abstract ImmutableMap<T, String> anImmutableMap();", 1092 " public abstract Optional<String> anOptionalString();", 1093 " public abstract NestedAutoValue<T> aNestedAutoValue();", 1094 "", 1095 " public abstract Builder<T> toBuilder();", 1096 "", 1097 " @AutoValue.Builder", 1098 " public abstract static class Builder<T extends Number> {", 1099 " public abstract Builder<T> anInt(int x);", 1100 " public abstract Builder<T> aByteArray(byte[] x);", 1101 " public abstract Builder<T> aNullableIntArray(@Nullable int[] x);", 1102 " public abstract Builder<T> aList(List<T> x);", 1103 " public abstract Builder<T> anImmutableMap(Map<T, String> x);", 1104 " public abstract ImmutableMap.Builder<T, String> anImmutableMapBuilder();", 1105 " public abstract Builder<T> anOptionalString(Optional<String> s);", 1106 " public abstract Builder<T> anOptionalString(String s);", 1107 " public abstract NestedAutoValue.Builder<T> aNestedAutoValueBuilder();", 1108 "", 1109 " public Builder<T> aList(ArrayList<T> x) {", 1110 // ArrayList should not be imported in the generated class. 1111 " return aList((List<T>) x);", 1112 " }", 1113 "", 1114 " public abstract Optional<Integer> anInt();", 1115 " public abstract List<T> aList();", 1116 " public abstract ImmutableMap<T, String> anImmutableMap();", 1117 "", 1118 " public abstract Baz<T> build();", 1119 " }", 1120 "", 1121 " public static <T extends Number> Builder<T> builder() {", 1122 " return AutoValue_Baz.builder();", 1123 " }", 1124 "}"); 1125 JavaFileObject nestedJavaFileObject = 1126 JavaFileObjects.forSourceLines( 1127 "foo.bar.NestedAutoValue", 1128 "package foo.bar;", 1129 "", 1130 "import com.google.auto.value.AutoValue;", 1131 "", 1132 "@AutoValue", 1133 "public abstract class NestedAutoValue<T extends Number> {", 1134 " public abstract T t();", 1135 "", 1136 " public abstract Builder<T> toBuilder();", 1137 "", 1138 " @AutoValue.Builder", 1139 " public abstract static class Builder<T extends Number> {", 1140 " public abstract Builder<T> t(T t);", 1141 " public abstract NestedAutoValue<T> build();", 1142 " }", 1143 "", 1144 " public static <T extends Number> Builder<T> builder() {", 1145 " return AutoValue_NestedAutoValue.builder();", 1146 " }", 1147 "}"); 1148 JavaFileObject expectedOutput = 1149 JavaFileObjects.forSourceLines( 1150 "foo.bar.AutoValue_Baz", 1151 "package foo.bar;", 1152 "", 1153 "import com.google.common.base.Optional;", 1154 "import com.google.common.collect.ImmutableMap;", 1155 "import java.util.Arrays;", 1156 "import java.util.List;", 1157 "import java.util.Map;", 1158 sorted( 1159 GeneratedImport.importGeneratedAnnotationType(), 1160 "import javax.annotation.Nullable;"), 1161 "", 1162 "@Generated(\"" + AutoValueProcessor.class.getName() + "\")", 1163 "final class AutoValue_Baz<T extends Number> extends Baz<T> {", 1164 " private final int anInt;", 1165 " private final byte[] aByteArray;", 1166 " @Nullable", 1167 " private final int[] aNullableIntArray;", 1168 " private final List<T> aList;", 1169 " private final ImmutableMap<T, String> anImmutableMap;", 1170 " private final Optional<String> anOptionalString;", 1171 " private final NestedAutoValue<T> aNestedAutoValue;", 1172 "", 1173 " private AutoValue_Baz(", 1174 " int anInt,", 1175 " byte[] aByteArray,", 1176 " @Nullable int[] aNullableIntArray,", 1177 " List<T> aList,", 1178 " ImmutableMap<T, String> anImmutableMap,", 1179 " Optional<String> anOptionalString,", 1180 " NestedAutoValue<T> aNestedAutoValue) {", 1181 " this.anInt = anInt;", 1182 " this.aByteArray = aByteArray;", 1183 " this.aNullableIntArray = aNullableIntArray;", 1184 " this.aList = aList;", 1185 " this.anImmutableMap = anImmutableMap;", 1186 " this.anOptionalString = anOptionalString;", 1187 " this.aNestedAutoValue = aNestedAutoValue;", 1188 " }", 1189 "", 1190 " @Override public int anInt() {", 1191 " return anInt;", 1192 " }", 1193 "", 1194 " @SuppressWarnings(\"mutable\")", 1195 " @Override public byte[] aByteArray() {", 1196 " return aByteArray;", 1197 " }", 1198 "", 1199 " @SuppressWarnings(\"mutable\")", 1200 " @Nullable", 1201 " @Override public int[] aNullableIntArray() {", 1202 " return aNullableIntArray;", 1203 " }", 1204 "", 1205 " @Override public List<T> aList() {", 1206 " return aList;", 1207 " }", 1208 "", 1209 " @Override public ImmutableMap<T, String> anImmutableMap() {", 1210 " return anImmutableMap;", 1211 " }", 1212 "", 1213 " @Override public Optional<String> anOptionalString() {", 1214 " return anOptionalString;", 1215 " }", 1216 "", 1217 " @Override public NestedAutoValue<T> aNestedAutoValue() {", 1218 " return aNestedAutoValue;", 1219 " }", 1220 "", 1221 " @Override public String toString() {", 1222 " return \"Baz{\"", 1223 " + \"anInt=\" + anInt + \", \"", 1224 " + \"aByteArray=\" + Arrays.toString(aByteArray) + \", \"", 1225 " + \"aNullableIntArray=\" + Arrays.toString(aNullableIntArray) + \", \"", 1226 " + \"aList=\" + aList + \", \"", 1227 " + \"anImmutableMap=\" + anImmutableMap + \", \"", 1228 " + \"anOptionalString=\" + anOptionalString + \", \"", 1229 " + \"aNestedAutoValue=\" + aNestedAutoValue", 1230 " + \"}\";", 1231 " }", 1232 "", 1233 " @Override public boolean equals(Object o) {", 1234 " if (o == this) {", 1235 " return true;", 1236 " }", 1237 " if (o instanceof Baz) {", 1238 " Baz<?> that = (Baz<?>) o;", 1239 " return this.anInt == that.anInt()", 1240 " && Arrays.equals(this.aByteArray, " 1241 + "(that instanceof AutoValue_Baz) " 1242 + "? ((AutoValue_Baz<?>) that).aByteArray : that.aByteArray())", 1243 " && Arrays.equals(this.aNullableIntArray, " 1244 + "(that instanceof AutoValue_Baz) " 1245 + "? ((AutoValue_Baz<?>) that).aNullableIntArray : that.aNullableIntArray())", 1246 " && this.aList.equals(that.aList())", 1247 " && this.anImmutableMap.equals(that.anImmutableMap())", 1248 " && this.anOptionalString.equals(that.anOptionalString())", 1249 " && this.aNestedAutoValue.equals(that.aNestedAutoValue());", 1250 " }", 1251 " return false;", 1252 " }", 1253 "", 1254 " @Override public int hashCode() {", 1255 " int h$ = 1;", 1256 " h$ *= 1000003;", 1257 " h$ ^= anInt;", 1258 " h$ *= 1000003;", 1259 " h$ ^= Arrays.hashCode(aByteArray);", 1260 " h$ *= 1000003;", 1261 " h$ ^= Arrays.hashCode(aNullableIntArray);", 1262 " h$ *= 1000003;", 1263 " h$ ^= aList.hashCode();", 1264 " h$ *= 1000003;", 1265 " h$ ^= anImmutableMap.hashCode();", 1266 " h$ *= 1000003;", 1267 " h$ ^= anOptionalString.hashCode();", 1268 " h$ *= 1000003;", 1269 " h$ ^= aNestedAutoValue.hashCode();", 1270 " return h$;", 1271 " }", 1272 "", 1273 " @Override public Baz.Builder<T> toBuilder() {", 1274 " return new Builder<T>(this);", 1275 " }", 1276 "", 1277 " static final class Builder<T extends Number> extends Baz.Builder<T> {", 1278 " private int anInt;", 1279 " private byte[] aByteArray;", 1280 " private int[] aNullableIntArray;", 1281 " private List<T> aList;", 1282 " private ImmutableMap.Builder<T, String> anImmutableMapBuilder$;", 1283 " private ImmutableMap<T, String> anImmutableMap;", 1284 " private Optional<String> anOptionalString = Optional.absent();", 1285 " private NestedAutoValue.Builder<T> aNestedAutoValueBuilder$;", 1286 " private NestedAutoValue<T> aNestedAutoValue;", 1287 " private byte set$0;", 1288 "", 1289 " Builder() {", 1290 " }", 1291 "", 1292 " private Builder(Baz<T> source) {", 1293 " this.anInt = source.anInt();", 1294 " this.aByteArray = source.aByteArray();", 1295 " this.aNullableIntArray = source.aNullableIntArray();", 1296 " this.aList = source.aList();", 1297 " this.anImmutableMap = source.anImmutableMap();", 1298 " this.anOptionalString = source.anOptionalString();", 1299 " this.aNestedAutoValue = source.aNestedAutoValue();", 1300 " set$0 = (byte) 1;", 1301 " }", 1302 "", 1303 " @Override", 1304 " public Baz.Builder<T> anInt(int anInt) {", 1305 " this.anInt = anInt;", 1306 " set$0 |= (byte) 1;", 1307 " return this;", 1308 " }", 1309 "", 1310 " @Override", 1311 " public Optional<Integer> anInt() {", 1312 " if ((set$0 & 1) == 0) {", 1313 " return Optional.absent();", 1314 " }", 1315 " return Optional.of(anInt);", 1316 " }", 1317 "", 1318 " @Override", 1319 " public Baz.Builder<T> aByteArray(byte[] aByteArray) {", 1320 " if (aByteArray == null) {", 1321 " throw new NullPointerException(\"Null aByteArray\");", 1322 " }", 1323 " this.aByteArray = aByteArray;", 1324 " return this;", 1325 " }", 1326 "", 1327 " @Override", 1328 " public Baz.Builder<T> aNullableIntArray(@Nullable int[] aNullableIntArray) {", 1329 " this.aNullableIntArray = aNullableIntArray;", 1330 " return this;", 1331 " }", 1332 "", 1333 " @Override", 1334 " public Baz.Builder<T> aList(List<T> aList) {", 1335 " if (aList == null) {", 1336 " throw new NullPointerException(\"Null aList\");", 1337 " }", 1338 " this.aList = aList;", 1339 " return this;", 1340 " }", 1341 "", 1342 " @Override", 1343 " public List<T> aList() {", 1344 " if (this.aList == null) {", 1345 " throw new IllegalStateException(\"Property \\\"aList\\\" has not been set\");", 1346 " }", 1347 " return aList;", 1348 " }", 1349 "", 1350 " @Override", 1351 " public Baz.Builder<T> anImmutableMap(Map<T, String> anImmutableMap) {", 1352 " if (anImmutableMapBuilder$ != null) {", 1353 " throw new IllegalStateException(" 1354 + "\"Cannot set anImmutableMap after calling anImmutableMapBuilder()\");", 1355 " }", 1356 " this.anImmutableMap = ImmutableMap.copyOf(anImmutableMap);", 1357 " return this;", 1358 " }", 1359 "", 1360 " @Override", 1361 " public ImmutableMap.Builder<T, String> anImmutableMapBuilder() {", 1362 " if (anImmutableMapBuilder$ == null) {", 1363 " if (anImmutableMap == null) {", 1364 " anImmutableMapBuilder$ = ImmutableMap.builder();", 1365 " } else {", 1366 " anImmutableMapBuilder$ = ImmutableMap.builder();", 1367 " anImmutableMapBuilder$.putAll(anImmutableMap);", 1368 " anImmutableMap = null;", 1369 " }", 1370 " }", 1371 " return anImmutableMapBuilder$;", 1372 " }", 1373 "", 1374 " @Override", 1375 " public ImmutableMap<T, String> anImmutableMap() {", 1376 " if (anImmutableMapBuilder$ != null) {", 1377 " return anImmutableMapBuilder$.buildOrThrow();", 1378 " }", 1379 " if (anImmutableMap == null) {", 1380 " anImmutableMap = ImmutableMap.of();", 1381 " }", 1382 " return anImmutableMap;", 1383 " }", 1384 "", 1385 " @Override", 1386 " public Baz.Builder<T> anOptionalString(Optional<String> anOptionalString) {", 1387 " if (anOptionalString == null) {", 1388 " throw new NullPointerException(\"Null anOptionalString\");", 1389 " }", 1390 " this.anOptionalString = anOptionalString;", 1391 " return this;", 1392 " }", 1393 "", 1394 " @Override", 1395 " public Baz.Builder<T> anOptionalString(String anOptionalString) {", 1396 " this.anOptionalString = Optional.of(anOptionalString);", 1397 " return this;", 1398 " }", 1399 "", 1400 " @Override", 1401 " public NestedAutoValue.Builder<T> aNestedAutoValueBuilder() {", 1402 " if (aNestedAutoValueBuilder$ == null) {", 1403 " if (aNestedAutoValue == null) {", 1404 " aNestedAutoValueBuilder$ = NestedAutoValue.builder();", 1405 " } else {", 1406 " aNestedAutoValueBuilder$ = aNestedAutoValue.toBuilder();", 1407 " aNestedAutoValue = null;", 1408 " }", 1409 " }", 1410 " return aNestedAutoValueBuilder$;", 1411 " }", 1412 "", 1413 " @Override", 1414 " public Baz<T> build() {", 1415 " if (anImmutableMapBuilder$ != null) {", 1416 " this.anImmutableMap = anImmutableMapBuilder$.buildOrThrow();", 1417 " } else if (this.anImmutableMap == null) {", 1418 " this.anImmutableMap = ImmutableMap.of();", 1419 " }", 1420 " if (aNestedAutoValueBuilder$ != null) {", 1421 " this.aNestedAutoValue = aNestedAutoValueBuilder$.build();", 1422 " } else if (this.aNestedAutoValue == null) {", 1423 " NestedAutoValue.Builder<T> aNestedAutoValue$builder = " 1424 + "NestedAutoValue.builder();", 1425 " this.aNestedAutoValue = aNestedAutoValue$builder.build();", 1426 " }", 1427 " if (set$0 != 1", 1428 " || this.aByteArray == null", 1429 " || this.aList == null) {", 1430 " StringBuilder missing = new StringBuilder();", 1431 " if ((set$0 & 1) == 0) {", 1432 " missing.append(\" anInt\");", 1433 " }", 1434 " if (this.aByteArray == null) {", 1435 " missing.append(\" aByteArray\");", 1436 " }", 1437 " if (this.aList == null) {", 1438 " missing.append(\" aList\");", 1439 " }", 1440 " throw new IllegalStateException(\"Missing required properties:\" + missing);", 1441 " }", 1442 " return new AutoValue_Baz<T>(", 1443 " this.anInt,", 1444 " this.aByteArray,", 1445 " this.aNullableIntArray,", 1446 " this.aList,", 1447 " this.anImmutableMap,", 1448 " this.anOptionalString,", 1449 " this.aNestedAutoValue);", 1450 " }", 1451 " }", 1452 "}"); 1453 Compilation compilation = 1454 javac() 1455 .withProcessors(new AutoValueProcessor()) 1456 .withOptions( 1457 "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=") 1458 .compile(javaFileObject, nestedJavaFileObject); 1459 assertThat(compilation).succeededWithoutWarnings(); 1460 assertThat(compilation) 1461 .generatedSourceFile("foo.bar.AutoValue_Baz") 1462 .hasSourceEquivalentTo(expectedOutput); 1463 } 1464 1465 @Test builderWithNullableTypeAnnotation()1466 public void builderWithNullableTypeAnnotation() { 1467 assume().that(typeAnnotationsWork).isTrue(); 1468 JavaFileObject javaFileObject = 1469 JavaFileObjects.forSourceLines( 1470 "foo.bar.Baz", 1471 "package foo.bar;", 1472 "", 1473 "import com.google.auto.value.AutoValue;", 1474 "import com.google.common.base.Optional;", 1475 "import com.google.common.collect.ImmutableMap;", 1476 "", 1477 "import java.util.ArrayList;", 1478 "import java.util.List;", 1479 "import java.util.Map;", 1480 "import org.checkerframework.checker.nullness.qual.Nullable;", 1481 "", 1482 "@AutoValue", 1483 "public abstract class Baz<T extends Number> {", 1484 " public abstract int anInt();", 1485 " @SuppressWarnings(\"mutable\")", 1486 " public abstract byte[] aByteArray();", 1487 " @SuppressWarnings(\"mutable\")", 1488 " public abstract int @Nullable [] aNullableIntArray();", 1489 " public abstract List<T> aList();", 1490 " public abstract ImmutableMap<T, String> anImmutableMap();", 1491 " public abstract Optional<String> anOptionalString();", 1492 "", 1493 " public abstract Builder<T> toBuilder();", 1494 "", 1495 " @AutoValue.Builder", 1496 " public abstract static class Builder<T extends Number> {", 1497 " public abstract Builder<T> anInt(int x);", 1498 " public abstract Builder<T> aByteArray(byte[] x);", 1499 " public abstract Builder<T> aNullableIntArray(int @Nullable [] x);", 1500 " public abstract Builder<T> aList(List<T> x);", 1501 " public abstract Builder<T> anImmutableMap(Map<T, String> x);", 1502 " public abstract ImmutableMap.Builder<T, String> anImmutableMapBuilder();", 1503 " public abstract Builder<T> anOptionalString(Optional<String> s);", 1504 " public abstract Baz<T> build();", 1505 " }", 1506 "", 1507 " public static <T extends Number> Builder<T> builder() {", 1508 " return AutoValue_Baz.builder();", 1509 " }", 1510 "}"); 1511 JavaFileObject expectedOutput = 1512 JavaFileObjects.forSourceLines( 1513 "foo.bar.AutoValue_Baz", 1514 "package foo.bar;", 1515 "", 1516 "import com.google.common.base.Optional;", 1517 "import com.google.common.collect.ImmutableMap;", 1518 "import java.util.Arrays;", 1519 "import java.util.List;", 1520 "import java.util.Map;", 1521 sorted( 1522 GeneratedImport.importGeneratedAnnotationType(), 1523 "import org.checkerframework.checker.nullness.qual.Nullable;"), 1524 "", 1525 "@Generated(\"" + AutoValueProcessor.class.getName() + "\")", 1526 "final class AutoValue_Baz<T extends Number> extends Baz<T> {", 1527 " private final int anInt;", 1528 " private final byte[] aByteArray;", 1529 " private final int @Nullable [] aNullableIntArray;", 1530 " private final List<T> aList;", 1531 " private final ImmutableMap<T, String> anImmutableMap;", 1532 " private final Optional<String> anOptionalString;", 1533 "", 1534 " private AutoValue_Baz(", 1535 " int anInt,", 1536 " byte[] aByteArray,", 1537 " int @Nullable [] aNullableIntArray,", 1538 " List<T> aList,", 1539 " ImmutableMap<T, String> anImmutableMap,", 1540 " Optional<String> anOptionalString) {", 1541 " this.anInt = anInt;", 1542 " this.aByteArray = aByteArray;", 1543 " this.aNullableIntArray = aNullableIntArray;", 1544 " this.aList = aList;", 1545 " this.anImmutableMap = anImmutableMap;", 1546 " this.anOptionalString = anOptionalString;", 1547 " }", 1548 "", 1549 " @Override public int anInt() {", 1550 " return anInt;", 1551 " }", 1552 "", 1553 " @SuppressWarnings(\"mutable\")", 1554 " @Override public byte[] aByteArray() {", 1555 " return aByteArray;", 1556 " }", 1557 "", 1558 " @SuppressWarnings(\"mutable\")", 1559 " @Override public int @Nullable [] aNullableIntArray() {", 1560 " return aNullableIntArray;", 1561 " }", 1562 "", 1563 " @Override public List<T> aList() {", 1564 " return aList;", 1565 " }", 1566 "", 1567 " @Override public ImmutableMap<T, String> anImmutableMap() {", 1568 " return anImmutableMap;", 1569 " }", 1570 "", 1571 " @Override public Optional<String> anOptionalString() {", 1572 " return anOptionalString;", 1573 " }", 1574 "", 1575 " @Override public String toString() {", 1576 " return \"Baz{\"", 1577 " + \"anInt=\" + anInt + \", \"", 1578 " + \"aByteArray=\" + Arrays.toString(aByteArray) + \", \"", 1579 " + \"aNullableIntArray=\" + Arrays.toString(aNullableIntArray) + \", \"", 1580 " + \"aList=\" + aList + \", \"", 1581 " + \"anImmutableMap=\" + anImmutableMap + \", \"", 1582 " + \"anOptionalString=\" + anOptionalString", 1583 " + \"}\";", 1584 " }", 1585 "", 1586 " @Override public boolean equals(@Nullable Object o) {", 1587 " if (o == this) {", 1588 " return true;", 1589 " }", 1590 " if (o instanceof Baz) {", 1591 " Baz<?> that = (Baz<?>) o;", 1592 " return this.anInt == that.anInt()", 1593 " && Arrays.equals(this.aByteArray, " 1594 + "(that instanceof AutoValue_Baz) " 1595 + "? ((AutoValue_Baz<?>) that).aByteArray : that.aByteArray())", 1596 " && Arrays.equals(this.aNullableIntArray, " 1597 + "(that instanceof AutoValue_Baz) " 1598 + "? ((AutoValue_Baz<?>) that).aNullableIntArray : that.aNullableIntArray())", 1599 " && this.aList.equals(that.aList())", 1600 " && this.anImmutableMap.equals(that.anImmutableMap())", 1601 " && this.anOptionalString.equals(that.anOptionalString());", 1602 " }", 1603 " return false;", 1604 " }", 1605 "", 1606 " @Override public int hashCode() {", 1607 " int h$ = 1;", 1608 " h$ *= 1000003;", 1609 " h$ ^= anInt;", 1610 " h$ *= 1000003;", 1611 " h$ ^= Arrays.hashCode(aByteArray);", 1612 " h$ *= 1000003;", 1613 " h$ ^= Arrays.hashCode(aNullableIntArray);", 1614 " h$ *= 1000003;", 1615 " h$ ^= aList.hashCode();", 1616 " h$ *= 1000003;", 1617 " h$ ^= anImmutableMap.hashCode();", 1618 " h$ *= 1000003;", 1619 " h$ ^= anOptionalString.hashCode();", 1620 " return h$;", 1621 " }", 1622 "", 1623 " @Override public Baz.Builder<T> toBuilder() {", 1624 " return new Builder<T>(this);", 1625 " }", 1626 "", 1627 " static final class Builder<T extends Number> extends Baz.Builder<T> {", 1628 " private int anInt;", 1629 " private byte @Nullable [] aByteArray;", 1630 " private int @Nullable [] aNullableIntArray;", 1631 " private @Nullable List<T> aList;", 1632 " private ImmutableMap.@Nullable Builder<T, String> anImmutableMapBuilder$;", 1633 " private @Nullable ImmutableMap<T, String> anImmutableMap;", 1634 " private Optional<String> anOptionalString = Optional.absent();", 1635 " private byte set$0;", 1636 "", 1637 " Builder() {", 1638 " }", 1639 "", 1640 " private Builder(Baz<T> source) {", 1641 " this.anInt = source.anInt();", 1642 " this.aByteArray = source.aByteArray();", 1643 " this.aNullableIntArray = source.aNullableIntArray();", 1644 " this.aList = source.aList();", 1645 " this.anImmutableMap = source.anImmutableMap();", 1646 " this.anOptionalString = source.anOptionalString();", 1647 " set$0 = (byte) 1;", 1648 " }", 1649 "", 1650 " @Override", 1651 " public Baz.Builder<T> anInt(int anInt) {", 1652 " this.anInt = anInt;", 1653 " set$0 |= (byte) 1;", 1654 " return this;", 1655 " }", 1656 "", 1657 " @Override", 1658 " public Baz.Builder<T> aByteArray(byte[] aByteArray) {", 1659 " if (aByteArray == null) {", 1660 " throw new NullPointerException(\"Null aByteArray\");", 1661 " }", 1662 " this.aByteArray = aByteArray;", 1663 " return this;", 1664 " }", 1665 "", 1666 " @Override", 1667 " public Baz.Builder<T> aNullableIntArray(int @Nullable [] aNullableIntArray) {", 1668 " this.aNullableIntArray = aNullableIntArray;", 1669 " return this;", 1670 " }", 1671 "", 1672 " @Override", 1673 " public Baz.Builder<T> aList(List<T> aList) {", 1674 " if (aList == null) {", 1675 " throw new NullPointerException(\"Null aList\");", 1676 " }", 1677 " this.aList = aList;", 1678 " return this;", 1679 " }", 1680 "", 1681 " @Override", 1682 " public Baz.Builder<T> anImmutableMap(Map<T, String> anImmutableMap) {", 1683 " if (anImmutableMapBuilder$ != null) {", 1684 " throw new IllegalStateException(" 1685 + "\"Cannot set anImmutableMap after calling anImmutableMapBuilder()\");", 1686 " }", 1687 " this.anImmutableMap = ImmutableMap.copyOf(anImmutableMap);", 1688 " return this;", 1689 " }", 1690 "", 1691 " @Override", 1692 " public ImmutableMap.Builder<T, String> anImmutableMapBuilder() {", 1693 " if (anImmutableMapBuilder$ == null) {", 1694 " if (anImmutableMap == null) {", 1695 " anImmutableMapBuilder$ = ImmutableMap.builder();", 1696 " } else {", 1697 " anImmutableMapBuilder$ = ImmutableMap.builder();", 1698 " anImmutableMapBuilder$.putAll(anImmutableMap);", 1699 " anImmutableMap = null;", 1700 " }", 1701 " }", 1702 " return anImmutableMapBuilder$;", 1703 " }", 1704 "", 1705 " @Override", 1706 " public Baz.Builder<T> anOptionalString(Optional<String> anOptionalString) {", 1707 " if (anOptionalString == null) {", 1708 " throw new NullPointerException(\"Null anOptionalString\");", 1709 " }", 1710 " this.anOptionalString = anOptionalString;", 1711 " return this;", 1712 " }", 1713 "", 1714 " @Override", 1715 " public Baz<T> build() {", 1716 " if (anImmutableMapBuilder$ != null) {", 1717 " this.anImmutableMap = anImmutableMapBuilder$.buildOrThrow();", 1718 " } else if (this.anImmutableMap == null) {", 1719 " this.anImmutableMap = ImmutableMap.of();", 1720 " }", 1721 " if (set$0 != 1", 1722 " || this.aByteArray == null", 1723 " || this.aList == null) {", 1724 " StringBuilder missing = new StringBuilder();", 1725 " if ((set$0 & 1) == 0) {", 1726 " missing.append(\" anInt\");", 1727 " }", 1728 " if (this.aByteArray == null) {", 1729 " missing.append(\" aByteArray\");", 1730 " }", 1731 " if (this.aList == null) {", 1732 " missing.append(\" aList\");", 1733 " }", 1734 " throw new IllegalStateException(\"Missing required properties:\" + missing);", 1735 " }", 1736 " return new AutoValue_Baz<T>(", 1737 " this.anInt,", 1738 " this.aByteArray,", 1739 " this.aNullableIntArray,", 1740 " this.aList,", 1741 " this.anImmutableMap,", 1742 " this.anOptionalString);", 1743 " }", 1744 " }", 1745 "}"); 1746 Compilation compilation = 1747 javac() 1748 .withProcessors(new AutoValueProcessor()) 1749 .withOptions( 1750 "-Xlint:-processing", 1751 "-implicit:none", 1752 "-A" + Nullables.NULLABLE_OPTION + "=org.checkerframework.checker.nullness.qual.Nullable") 1753 .compile(javaFileObject); 1754 assertThat(compilation).succeededWithoutWarnings(); 1755 assertThat(compilation) 1756 .generatedSourceFile("foo.bar.AutoValue_Baz") 1757 .hasSourceEquivalentTo(expectedOutput); 1758 } 1759 1760 @Test autoValueBuilderOnTopLevelClass()1761 public void autoValueBuilderOnTopLevelClass() { 1762 JavaFileObject javaFileObject = 1763 JavaFileObjects.forSourceLines( 1764 "foo.bar.Builder", 1765 "package foo.bar;", 1766 "", 1767 "import com.google.auto.value.AutoValue;", 1768 "", 1769 "@AutoValue.Builder", 1770 "public interface Builder {", 1771 " Builder foo(int x);", 1772 " Object build();", 1773 "}"); 1774 Compilation compilation = 1775 javac() 1776 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1777 .compile(javaFileObject); 1778 assertThat(compilation) 1779 .hadErrorContaining("can only be applied to a class or interface inside") 1780 .inFile(javaFileObject) 1781 .onLineContaining("public interface Builder"); 1782 } 1783 1784 @Test autoValueBuilderNotInsideAutoValue()1785 public void autoValueBuilderNotInsideAutoValue() { 1786 JavaFileObject javaFileObject = 1787 JavaFileObjects.forSourceLines( 1788 "foo.bar.Baz", 1789 "package foo.bar;", 1790 "", 1791 "import com.google.auto.value.AutoValue;", 1792 "", 1793 "public abstract class Baz {", 1794 " abstract int foo();", 1795 "", 1796 " static Builder builder() {", 1797 " return new AutoValue_Baz.Builder();", 1798 " }", 1799 "", 1800 " @AutoValue.Builder", 1801 " public interface Builder {", 1802 " Builder foo(int x);", 1803 " Baz build();", 1804 " }", 1805 "}"); 1806 Compilation compilation = 1807 javac() 1808 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1809 .compile(javaFileObject); 1810 assertThat(compilation) 1811 .hadErrorContaining("can only be applied to a class or interface inside") 1812 .inFile(javaFileObject) 1813 .onLineContaining("public interface Builder"); 1814 } 1815 1816 @Test autoValueBuilderNotStatic()1817 public void autoValueBuilderNotStatic() { 1818 JavaFileObject javaFileObject = 1819 JavaFileObjects.forSourceLines( 1820 "foo.bar.Example", 1821 "package foo.bar;", 1822 "", 1823 "import com.google.auto.value.AutoValue;", 1824 "", 1825 "class Example {", 1826 " @AutoValue", 1827 " abstract static class Baz {", 1828 " abstract int foo();", 1829 "", 1830 " static Builder builder() {", 1831 " return new AutoValue_Example_Baz.Builder();", 1832 " }", 1833 "", 1834 " @AutoValue.Builder", 1835 " abstract class Builder {", 1836 " abstract Builder foo(int x);", 1837 " abstract Baz build();", 1838 " }", 1839 " }", 1840 "}"); 1841 Compilation compilation = 1842 javac() 1843 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1844 .compile(javaFileObject); 1845 assertThat(compilation) 1846 .hadErrorContaining("@AutoValue.Builder cannot be applied to a non-static class") 1847 .inFile(javaFileObject) 1848 .onLineContaining("abstract class Builder"); 1849 } 1850 1851 @Test autoValueBuilderMustHaveNoArgConstructor()1852 public void autoValueBuilderMustHaveNoArgConstructor() { 1853 JavaFileObject javaFileObject = 1854 JavaFileObjects.forSourceLines( 1855 "foo.bar.Example", 1856 "package foo.bar;", 1857 "", 1858 "import com.google.auto.value.AutoValue;", 1859 "", 1860 "class Example {", 1861 " @AutoValue", 1862 " abstract static class Baz {", 1863 " abstract int foo();", 1864 "", 1865 " static Builder builder() {", 1866 " return new AutoValue_Example_Baz.Builder();", 1867 " }", 1868 "", 1869 " @AutoValue.Builder", 1870 " abstract static class Builder {", 1871 " Builder(int defaultFoo) {}", 1872 " abstract Builder foo(int x);", 1873 " abstract Baz build();", 1874 " }", 1875 " }", 1876 "}"); 1877 Compilation compilation = 1878 javac() 1879 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1880 .compile(javaFileObject); 1881 assertThat(compilation) 1882 .hadErrorContaining("@AutoValue.Builder class must have a non-private no-arg constructor") 1883 .inFile(javaFileObject) 1884 .onLineContaining("class Builder"); 1885 } 1886 1887 @Test autoValueBuilderOnEnum()1888 public void autoValueBuilderOnEnum() { 1889 JavaFileObject javaFileObject = 1890 JavaFileObjects.forSourceLines( 1891 "foo.bar.Baz", 1892 "package foo.bar;", 1893 "", 1894 "import com.google.auto.value.AutoValue;", 1895 "", 1896 "@AutoValue", 1897 "public abstract class Baz {", 1898 " abstract int foo();", 1899 "", 1900 " static Builder builder() {", 1901 " return null;", 1902 " }", 1903 "", 1904 " @AutoValue.Builder", 1905 " public enum Builder {}", 1906 "}"); 1907 Compilation compilation = 1908 javac() 1909 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1910 .compile(javaFileObject); 1911 assertThat(compilation) 1912 .hadErrorContaining("can only apply to a class or an interface") 1913 .inFile(javaFileObject) 1914 .onLineContaining("public enum Builder"); 1915 } 1916 1917 @Test autoValueBuilderDuplicate()1918 public void autoValueBuilderDuplicate() { 1919 JavaFileObject javaFileObject = 1920 JavaFileObjects.forSourceLines( 1921 "foo.bar.Baz", 1922 "package foo.bar;", 1923 "", 1924 "import com.google.auto.value.AutoValue;", 1925 "", 1926 "@AutoValue", 1927 "public abstract class Baz {", 1928 " @AutoValue.Builder", 1929 " public interface Builder1 {", 1930 " Baz build();", 1931 " }", 1932 "", 1933 " @AutoValue.Builder", 1934 " public interface Builder2 {", 1935 " Baz build();", 1936 " }", 1937 "}"); 1938 Compilation compilation = 1939 javac() 1940 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1941 .compile(javaFileObject); 1942 assertThat(compilation) 1943 .hadErrorContaining("already has a Builder: foo.bar.Baz.Builder1") 1944 .inFile(javaFileObject) 1945 .onLineContaining("public interface Builder2"); 1946 } 1947 1948 @Test autoValueBuilderMissingSetter()1949 public void autoValueBuilderMissingSetter() { 1950 JavaFileObject javaFileObject = 1951 JavaFileObjects.forSourceLines( 1952 "foo.bar.Baz", 1953 "package foo.bar;", 1954 "", 1955 "import com.google.auto.value.AutoValue;", 1956 "", 1957 "@AutoValue", 1958 "public abstract class Baz {", 1959 " abstract int blim();", 1960 " abstract String blam();", 1961 "", 1962 " @AutoValue.Builder", 1963 " public interface Builder {", 1964 " Builder blam(String x);", 1965 " Baz build();", 1966 " }", 1967 "}"); 1968 Compilation compilation = 1969 javac() 1970 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 1971 .compile(javaFileObject); 1972 assertThat(compilation) 1973 .hadErrorContaining("with this signature: foo.bar.Baz.Builder blim(int)") 1974 .inFile(javaFileObject) 1975 .onLineContaining("public interface Builder"); 1976 } 1977 1978 @Test autoValueBuilderMissingSetterUsingSetPrefix()1979 public void autoValueBuilderMissingSetterUsingSetPrefix() { 1980 JavaFileObject javaFileObject = 1981 JavaFileObjects.forSourceLines( 1982 "foo.bar.Baz", 1983 "package foo.bar;", 1984 "", 1985 "import com.google.auto.value.AutoValue;", 1986 "", 1987 "@AutoValue", 1988 "public abstract class Baz {", 1989 " abstract int blim();", 1990 " abstract String blam();", 1991 "", 1992 " @AutoValue.Builder", 1993 " public interface Builder {", 1994 " Builder setBlam(String x);", 1995 " Baz build();", 1996 " }", 1997 "}"); 1998 Compilation compilation = 1999 javac() 2000 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2001 .compile(javaFileObject); 2002 assertThat(compilation) 2003 .hadErrorContaining("with this signature: foo.bar.Baz.Builder setBlim(int)") 2004 .inFile(javaFileObject) 2005 .onLineContaining("public interface Builder"); 2006 } 2007 2008 @Test autoValueBuilderWrongTypeSetter()2009 public void autoValueBuilderWrongTypeSetter() { 2010 JavaFileObject javaFileObject = 2011 JavaFileObjects.forSourceLines( 2012 "foo.bar.Baz", 2013 "package foo.bar;", 2014 "", 2015 "import com.google.auto.value.AutoValue;", 2016 "", 2017 "@AutoValue", 2018 "public abstract class Baz {", 2019 " abstract int blim();", 2020 " abstract String blam();", 2021 "", 2022 " @AutoValue.Builder", 2023 " public interface Builder {", 2024 " Builder blim(String x);", 2025 " Builder blam(String x);", 2026 " Baz build();", 2027 " }", 2028 "}"); 2029 Compilation compilation = 2030 javac() 2031 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2032 .compile(javaFileObject); 2033 assertThat(compilation) 2034 .hadErrorContaining( 2035 "Parameter type java.lang.String of setter method should be int " 2036 + "to match property method foo.bar.Baz.blim()") 2037 .inFile(javaFileObject) 2038 .onLineContaining("Builder blim(String x)"); 2039 } 2040 2041 @Test autoValueBuilderSetterReturnsNullable()2042 public void autoValueBuilderSetterReturnsNullable() { 2043 JavaFileObject javaFileObject = 2044 JavaFileObjects.forSourceLines( 2045 "foo.bar.Baz", 2046 "package foo.bar;", 2047 "", 2048 "import com.google.auto.value.AutoValue;", 2049 "import javax.annotation.Nullable;", 2050 "", 2051 "@AutoValue", 2052 "public abstract class Baz {", 2053 " abstract String blam();", 2054 "", 2055 " @AutoValue.Builder", 2056 " public interface Builder {", 2057 " @Nullable Builder blam(String x);", 2058 " Baz build();", 2059 " }", 2060 "}"); 2061 Compilation compilation = 2062 javac() 2063 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2064 .compile(javaFileObject); 2065 assertThat(compilation) 2066 .hadWarningContaining( 2067 "Setter methods always return the Builder so @Nullable is not appropriate") 2068 .inFile(javaFileObject) 2069 .onLineContaining("Builder blam(String x)"); 2070 } 2071 2072 @Test autoValueBuilderWrongTypeSetterWithCopyOf()2073 public void autoValueBuilderWrongTypeSetterWithCopyOf() { 2074 JavaFileObject javaFileObject = 2075 JavaFileObjects.forSourceLines( 2076 "foo.bar.Baz", 2077 "package foo.bar;", 2078 "", 2079 "import com.google.auto.value.AutoValue;", 2080 "import com.google.common.collect.ImmutableList;", 2081 "", 2082 "@AutoValue", 2083 "public abstract class Baz {", 2084 " abstract String blim();", 2085 " abstract ImmutableList<String> blam();", 2086 "", 2087 " @AutoValue.Builder", 2088 " public interface Builder {", 2089 " Builder blim(String x);", 2090 " Builder blam(String x);", 2091 " Baz build();", 2092 " }", 2093 "}"); 2094 Compilation compilation = 2095 javac() 2096 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2097 .compile(javaFileObject); 2098 assertThat(compilation) 2099 .hadErrorContaining( 2100 "Parameter type java.lang.String of setter method should be" 2101 + " com.google.common.collect.ImmutableList<java.lang.String> to match property" 2102 + " method foo.bar.Baz.blam(), or it should be a type that can be passed to" 2103 + " ImmutableList.copyOf") 2104 .inFile(javaFileObject) 2105 .onLineContaining("Builder blam(String x)"); 2106 } 2107 2108 @Test autoValueBuilderWrongTypeSetterWithCopyOfGenericallyWrong()2109 public void autoValueBuilderWrongTypeSetterWithCopyOfGenericallyWrong() { 2110 JavaFileObject javaFileObject = 2111 JavaFileObjects.forSourceLines( 2112 "foo.bar.Baz", 2113 "package foo.bar;", 2114 "", 2115 "import com.google.auto.value.AutoValue;", 2116 "import com.google.common.collect.ImmutableList;", 2117 "import java.util.Collection;", 2118 "", 2119 "@AutoValue", 2120 "public abstract class Baz {", 2121 " abstract String blim();", 2122 " abstract ImmutableList<String> blam();", 2123 "", 2124 " @AutoValue.Builder", 2125 " public interface Builder {", 2126 " Builder blim(String x);", 2127 " Builder blam(Collection<Integer> x);", 2128 " Baz build();", 2129 " }", 2130 "}"); 2131 Compilation compilation = 2132 javac() 2133 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2134 .compile(javaFileObject); 2135 assertThat(compilation) 2136 .hadErrorContaining( 2137 "Parameter type java.util.Collection<java.lang.Integer> of setter method should be" 2138 + " com.google.common.collect.ImmutableList<java.lang.String> to match property" 2139 + " method foo.bar.Baz.blam(), or it should be a type that can be passed to" 2140 + " ImmutableList.copyOf to produce" 2141 + " com.google.common.collect.ImmutableList<java.lang.String>") 2142 .inFile(javaFileObject) 2143 .onLineContaining("Builder blam(Collection<Integer> x)"); 2144 } 2145 2146 @Test autoValueBuilderWrongTypeSetterWithGetPrefix()2147 public void autoValueBuilderWrongTypeSetterWithGetPrefix() { 2148 JavaFileObject javaFileObject = 2149 JavaFileObjects.forSourceLines( 2150 "foo.bar.Baz", 2151 "package foo.bar;", 2152 "", 2153 "import com.google.auto.value.AutoValue;", 2154 "", 2155 "@AutoValue", 2156 "public abstract class Baz {", 2157 " abstract int getBlim();", 2158 " abstract String getBlam();", 2159 "", 2160 " @AutoValue.Builder", 2161 " public interface Builder {", 2162 " Builder blim(String x);", 2163 " Builder blam(String x);", 2164 " Baz build();", 2165 " }", 2166 "}"); 2167 Compilation compilation = 2168 javac() 2169 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2170 .compile(javaFileObject); 2171 assertThat(compilation) 2172 .hadErrorContaining( 2173 "Parameter type java.lang.String of setter method should be int " 2174 + "to match property method foo.bar.Baz.getBlim()") 2175 .inFile(javaFileObject) 2176 .onLineContaining("Builder blim(String x)"); 2177 } 2178 2179 @Test autoValueBuilderNullableSetterForNonNullable()2180 public void autoValueBuilderNullableSetterForNonNullable() { 2181 JavaFileObject nullableFileObject = 2182 JavaFileObjects.forSourceLines( 2183 "foo.bar.Nullable", 2184 "package foo.bar;", 2185 "", 2186 "import java.lang.annotation.ElementType;", 2187 "import java.lang.annotation.Target;", 2188 "", 2189 "@Target(ElementType.TYPE_USE)", 2190 "public @interface Nullable {}"); 2191 JavaFileObject javaFileObject = 2192 JavaFileObjects.forSourceLines( 2193 "foo.bar.Baz", 2194 "package foo.bar;", 2195 "", 2196 "import com.google.auto.value.AutoValue;", 2197 "", 2198 "@AutoValue", 2199 "public abstract class Baz {", 2200 " abstract String notNull();", 2201 "", 2202 " @AutoValue.Builder", 2203 " public interface Builder {", 2204 " Builder setNotNull(@Nullable String x);", 2205 " Baz build();", 2206 " }", 2207 "}"); 2208 Compilation compilation = 2209 javac() 2210 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2211 .compile(javaFileObject, nullableFileObject); 2212 assertThat(compilation) 2213 .hadErrorContaining( 2214 "Parameter of setter method is @Nullable but property method" 2215 + " foo.bar.Baz.notNull() is not") 2216 .inFile(javaFileObject) 2217 .onLineContaining("setNotNull"); 2218 } 2219 2220 // Check that we get a helpful error message if some of your properties look like getters but 2221 // others don't. 2222 @Test autoValueBuilderBeansConfusion()2223 public void autoValueBuilderBeansConfusion() { 2224 JavaFileObject javaFileObject = 2225 JavaFileObjects.forSourceLines( 2226 "foo.bar.Item", 2227 "package foo.bar;", 2228 "", 2229 "import com.google.auto.value.AutoValue;", 2230 "", 2231 "@AutoValue", 2232 "public abstract class Item {", 2233 " abstract String getTitle();", 2234 " abstract boolean hasThumbnail();", 2235 "", 2236 " @AutoValue.Builder", 2237 " public interface Builder {", 2238 " Builder setTitle(String title);", 2239 " Builder setHasThumbnail(boolean t);", 2240 " Item build();", 2241 " }", 2242 "}"); 2243 Compilation compilation = 2244 javac() 2245 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2246 .compile(javaFileObject); 2247 assertThat(compilation) 2248 .hadErrorContaining( 2249 "Method setTitle does not correspond to a property method of foo.bar.Item") 2250 .inFile(javaFileObject) 2251 .onLineContaining("Builder setTitle(String title)"); 2252 assertThat(compilation) 2253 .hadNoteContaining("hasThumbnail") 2254 .inFile(javaFileObject) 2255 .onLineContaining("Builder setTitle(String title)"); 2256 } 2257 2258 @Test autoValueBuilderExtraSetter()2259 public void autoValueBuilderExtraSetter() { 2260 JavaFileObject javaFileObject = 2261 JavaFileObjects.forSourceLines( 2262 "foo.bar.Baz", 2263 "package foo.bar;", 2264 "", 2265 "import com.google.auto.value.AutoValue;", 2266 "", 2267 "@AutoValue", 2268 "public abstract class Baz {", 2269 " abstract String blam();", 2270 "", 2271 " @AutoValue.Builder", 2272 " public interface Builder {", 2273 " Builder blim(int x);", 2274 " Builder blam(String x);", 2275 " Baz build();", 2276 " }", 2277 "}"); 2278 Compilation compilation = 2279 javac() 2280 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2281 .compile(javaFileObject); 2282 assertThat(compilation) 2283 .hadErrorContaining("Method blim does not correspond to a property method of foo.bar.Baz") 2284 .inFile(javaFileObject) 2285 .onLineContaining("Builder blim(int x)"); 2286 } 2287 2288 @Test autoValueBuilderSetPrefixAndNoSetPrefix()2289 public void autoValueBuilderSetPrefixAndNoSetPrefix() { 2290 JavaFileObject javaFileObject = 2291 JavaFileObjects.forSourceLines( 2292 "foo.bar.Baz", 2293 "package foo.bar;", 2294 "", 2295 "import com.google.auto.value.AutoValue;", 2296 "", 2297 "@AutoValue", 2298 "public abstract class Baz {", 2299 " abstract int blim();", 2300 " abstract String blam();", 2301 "", 2302 " @AutoValue.Builder", 2303 " public interface Builder {", 2304 " Builder blim(int x);", 2305 " Builder setBlam(String x);", 2306 " Baz build();", 2307 " }", 2308 "}"); 2309 Compilation compilation = 2310 javac() 2311 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2312 .compile(javaFileObject); 2313 assertThat(compilation) 2314 .hadErrorContaining("If any setter methods use the setFoo convention then all must") 2315 .inFile(javaFileObject) 2316 .onLineContaining("Builder blim(int x)"); 2317 } 2318 2319 @Test autoValueBuilderSetterReturnType()2320 public void autoValueBuilderSetterReturnType() { 2321 // We do allow the return type of a setter to be a supertype of the builder type, to support 2322 // step builders. But we don't allow it to be Object. 2323 JavaFileObject javaFileObject = 2324 JavaFileObjects.forSourceLines( 2325 "foo.bar.Baz", 2326 "package foo.bar;", 2327 "", 2328 "import com.google.auto.value.AutoValue;", 2329 "", 2330 "@AutoValue", 2331 "public abstract class Baz {", 2332 " abstract int blim();", 2333 "", 2334 " @AutoValue.Builder", 2335 " public interface Builder {", 2336 " Object blim(int x);", 2337 " Baz build();", 2338 " }", 2339 "}"); 2340 Compilation compilation = 2341 javac() 2342 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2343 .compile(javaFileObject); 2344 assertThat(compilation) 2345 .hadErrorContaining("Setter methods must return foo.bar.Baz.Builder") 2346 .inFile(javaFileObject) 2347 .onLineContaining("Object blim(int x)"); 2348 } 2349 2350 @Test autoValueBuilderWrongTypeGetter()2351 public void autoValueBuilderWrongTypeGetter() { 2352 JavaFileObject javaFileObject = 2353 JavaFileObjects.forSourceLines( 2354 "foo.bar.Baz", 2355 "package foo.bar;", 2356 "", 2357 "import com.google.auto.value.AutoValue;", 2358 "", 2359 "@AutoValue", 2360 "public abstract class Baz<T, U> {", 2361 " abstract T blim();", 2362 " abstract U blam();", 2363 "", 2364 " @AutoValue.Builder", 2365 " public interface Builder<T, U> {", 2366 " Builder<T, U> blim(T x);", 2367 " Builder<T, U> blam(U x);", 2368 " T blim();", 2369 " T blam();", 2370 " Baz<T, U> build();", 2371 " }", 2372 "}"); 2373 Compilation compilation = 2374 javac() 2375 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2376 .compile(javaFileObject); 2377 assertThat(compilation) 2378 .hadErrorContainingMatch( 2379 "Method matches a property of foo\\.bar\\.Baz<T, ?U> but has return type T instead of" 2380 + " U") 2381 .inFile(javaFileObject) 2382 .onLineContaining("T blam()"); 2383 // The <T, ?U> is because we're depending on TypeMirror.toString(), and the JDK actually spells 2384 // this as <T,U> with no space. While it's not completely sound to expect a given string from 2385 // TypeMirror.toString(), in practice it's hard to imagine that it would be anything other 2386 // than "foo.bar.Baz<T,U>" or "foo.bar.Baz<T, U>" given the specification. 2387 } 2388 2389 @Test autoValueBuilderPropertyBuilderInvalidType()2390 public void autoValueBuilderPropertyBuilderInvalidType() { 2391 JavaFileObject javaFileObject = 2392 JavaFileObjects.forSourceLines( 2393 "foo.bar.Baz", 2394 "package foo.bar;", 2395 "", 2396 "import com.google.auto.value.AutoValue;", 2397 "", 2398 "@AutoValue", 2399 "public abstract class Baz<T, U> {", 2400 " abstract String blim();", 2401 "", 2402 " @AutoValue.Builder", 2403 " public interface Builder<T, U> {", 2404 " StringBuilder blimBuilder();", 2405 " Baz<T, U> build();", 2406 " }", 2407 "}"); 2408 Compilation compilation = 2409 javac() 2410 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2411 .compile(javaFileObject); 2412 assertThat(compilation) 2413 .hadErrorContaining( 2414 "Method looks like a property builder, but it returns java.lang.StringBuilder which " 2415 + "does not have a non-static build() or buildOrThrow() method") 2416 .inFile(javaFileObject) 2417 .onLineContaining("StringBuilder blimBuilder()"); 2418 } 2419 2420 @Test autoValueBuilderPropertyBuilderNullable()2421 public void autoValueBuilderPropertyBuilderNullable() { 2422 JavaFileObject javaFileObject = 2423 JavaFileObjects.forSourceLines( 2424 "foo.bar.Baz", 2425 "package foo.bar;", 2426 "", 2427 "import com.google.auto.value.AutoValue;", 2428 "import com.google.common.collect.ImmutableList;", 2429 "", 2430 "@AutoValue", 2431 "public abstract class Baz<T, U> {", 2432 " @interface Nullable {}", 2433 " abstract @Nullable ImmutableList<String> strings();", 2434 "", 2435 " @AutoValue.Builder", 2436 " public interface Builder<T, U> {", 2437 " ImmutableList.Builder<String> stringsBuilder();", 2438 " Baz<T, U> build();", 2439 " }", 2440 "}"); 2441 Compilation compilation = 2442 javac() 2443 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2444 .compile(javaFileObject); 2445 assertThat(compilation) 2446 .hadErrorContaining("Property strings is @Nullable so it cannot have a property builder") 2447 .inFile(javaFileObject) 2448 .onLineContaining("stringsBuilder()"); 2449 } 2450 2451 @Test autoValueBuilderPropertyBuilderNullableType()2452 public void autoValueBuilderPropertyBuilderNullableType() { 2453 JavaFileObject javaFileObject = 2454 JavaFileObjects.forSourceLines( 2455 "foo.bar.Baz", 2456 "package foo.bar;", 2457 "", 2458 "import com.google.auto.value.AutoValue;", 2459 "import com.google.common.collect.ImmutableList;", 2460 "import java.lang.annotation.ElementType;", 2461 "import java.lang.annotation.Target;", 2462 "", 2463 "@AutoValue", 2464 "public abstract class Baz<T, U> {", 2465 " @Target(ElementType.TYPE_USE)", 2466 " @interface Nullable {}", 2467 " abstract @Nullable ImmutableList<String> strings();", 2468 "", 2469 " @AutoValue.Builder", 2470 " public interface Builder<T, U> {", 2471 " ImmutableList.Builder<String> stringsBuilder();", 2472 " Baz<T, U> build();", 2473 " }", 2474 "}"); 2475 Compilation compilation = 2476 javac() 2477 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2478 .compile(javaFileObject); 2479 assertThat(compilation) 2480 .hadErrorContaining("Property strings is @Nullable so it cannot have a property builder") 2481 .inFile(javaFileObject) 2482 .onLineContaining("stringsBuilder()"); 2483 } 2484 2485 @Test autoValueBuilderPropertyBuilderWrongCollectionType()2486 public void autoValueBuilderPropertyBuilderWrongCollectionType() { 2487 JavaFileObject javaFileObject = 2488 JavaFileObjects.forSourceLines( 2489 "foo.bar.Baz", 2490 "package foo.bar;", 2491 "", 2492 "import com.google.auto.value.AutoValue;", 2493 "import com.google.common.collect.ImmutableList;", 2494 "import com.google.common.collect.ImmutableSet;", 2495 "", 2496 "@AutoValue", 2497 "public abstract class Baz<T, U> {", 2498 " abstract ImmutableList<T> blim();", 2499 "", 2500 " @AutoValue.Builder", 2501 " public interface Builder<T, U> {", 2502 " ImmutableSet.Builder<T> blimBuilder();", 2503 " Baz<T, U> build();", 2504 " }", 2505 "}"); 2506 Compilation compilation = 2507 javac() 2508 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2509 .compile(javaFileObject); 2510 assertThat(compilation) 2511 .hadErrorContaining( 2512 "Property builder for blim has type com.google.common.collect.ImmutableSet.Builder " 2513 + "whose build() method returns com.google.common.collect.ImmutableSet<T> " 2514 + "instead of com.google.common.collect.ImmutableList<T>") 2515 .inFile(javaFileObject) 2516 .onLineContaining("ImmutableSet.Builder<T> blimBuilder()"); 2517 } 2518 2519 @Test autoValueBuilderPropertyBuilderWeirdBuilderType()2520 public void autoValueBuilderPropertyBuilderWeirdBuilderType() { 2521 JavaFileObject javaFileObject = 2522 JavaFileObjects.forSourceLines( 2523 "foo.bar.Baz", 2524 "package foo.bar;", 2525 "", 2526 "import com.google.auto.value.AutoValue;", 2527 "import com.google.common.collect.ImmutableSet;", 2528 "", 2529 "@AutoValue", 2530 "public abstract class Baz<T, U> {", 2531 " abstract Integer blim();", 2532 "", 2533 " @AutoValue.Builder", 2534 " public interface Builder<T, U> {", 2535 " int blimBuilder();", 2536 " Baz<T, U> build();", 2537 " }", 2538 "}"); 2539 Compilation compilation = 2540 javac() 2541 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2542 .compile(javaFileObject); 2543 assertThat(compilation) 2544 .hadErrorContaining( 2545 "Method looks like a property builder, but its return type is not a class or interface") 2546 .inFile(javaFileObject) 2547 .onLineContaining("int blimBuilder()"); 2548 } 2549 2550 @Test autoValueBuilderPropertyBuilderWeirdBuiltType()2551 public void autoValueBuilderPropertyBuilderWeirdBuiltType() { 2552 JavaFileObject javaFileObject = 2553 JavaFileObjects.forSourceLines( 2554 "foo.bar.Baz", 2555 "package foo.bar;", 2556 "", 2557 "import com.google.auto.value.AutoValue;", 2558 "import com.google.common.collect.ImmutableSet;", 2559 "", 2560 "@AutoValue", 2561 "public abstract class Baz<T, U> {", 2562 " abstract int blim();", 2563 "", 2564 " @AutoValue.Builder", 2565 " public interface Builder<T, U> {", 2566 " Integer blimBuilder();", 2567 " Baz<T, U> build();", 2568 " }", 2569 "}"); 2570 Compilation compilation = 2571 javac() 2572 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2573 .compile(javaFileObject); 2574 assertThat(compilation) 2575 .hadErrorContaining( 2576 "Method looks like a property builder, but the type of property blim is not a class " 2577 + "or interface") 2578 .inFile(javaFileObject) 2579 .onLineContaining("Integer blimBuilder()"); 2580 } 2581 2582 @Test autoValueBuilderPropertyBuilderHasNoBuild()2583 public void autoValueBuilderPropertyBuilderHasNoBuild() { 2584 JavaFileObject javaFileObject = 2585 JavaFileObjects.forSourceLines( 2586 "foo.bar.Baz", 2587 "package foo.bar;", 2588 "", 2589 "import com.google.auto.value.AutoValue;", 2590 "import com.google.common.collect.ImmutableSet;", 2591 "", 2592 "@AutoValue", 2593 "public abstract class Baz<T, U> {", 2594 " abstract String blim();", 2595 "", 2596 " @AutoValue.Builder", 2597 " public interface Builder<T, U> {", 2598 " StringBuilder blimBuilder();", 2599 " Baz<T, U> build();", 2600 " }", 2601 "}"); 2602 Compilation compilation = 2603 javac() 2604 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2605 .compile(javaFileObject); 2606 assertThat(compilation) 2607 .hadErrorContaining( 2608 "Method looks like a property builder, but it returns java.lang.StringBuilder which " 2609 + "does not have a non-static build() or buildOrThrow() method") 2610 .inFile(javaFileObject) 2611 .onLineContaining("StringBuilder blimBuilder()"); 2612 } 2613 2614 @Test autoValueBuilderPropertyBuilderHasStaticBuild()2615 public void autoValueBuilderPropertyBuilderHasStaticBuild() { 2616 JavaFileObject javaFileObject = 2617 JavaFileObjects.forSourceLines( 2618 "foo.bar.Baz", 2619 "package foo.bar;", 2620 "", 2621 "import com.google.auto.value.AutoValue;", 2622 "import com.google.common.collect.ImmutableSet;", 2623 "", 2624 "@AutoValue", 2625 "public abstract class Baz<T, U> {", 2626 " abstract String blim();", 2627 "", 2628 " public static class StringFactory {", 2629 " public static String build() {", 2630 " return null;", 2631 " }", 2632 " }", 2633 "", 2634 " @AutoValue.Builder", 2635 " public interface Builder<T, U> {", 2636 " StringFactory blimBuilder();", 2637 " Baz<T, U> build();", 2638 " }", 2639 "}"); 2640 Compilation compilation = 2641 javac() 2642 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2643 .compile(javaFileObject); 2644 assertThat(compilation) 2645 .hadErrorContaining( 2646 "Method looks like a property builder, but it returns foo.bar.Baz.StringFactory which " 2647 + "does not have a non-static build() or buildOrThrow() method") 2648 .inFile(javaFileObject) 2649 .onLineContaining("StringFactory blimBuilder()"); 2650 } 2651 2652 @Test autoValueBuilderPropertyBuilderReturnsWrongType()2653 public void autoValueBuilderPropertyBuilderReturnsWrongType() { 2654 JavaFileObject javaFileObject = 2655 JavaFileObjects.forSourceLines( 2656 "foo.bar.Baz", 2657 "package foo.bar;", 2658 "", 2659 "import com.google.auto.value.AutoValue;", 2660 "import com.google.common.collect.ImmutableSet;", 2661 "import java.util.List;", 2662 "", 2663 "@AutoValue", 2664 "public abstract class Baz<E> {", 2665 " abstract List<E> blim();", 2666 "", 2667 " public static class ListFactory<E> {", 2668 " public List<? extends E> build() {", 2669 " return null;", 2670 " }", 2671 " }", 2672 "", 2673 " @AutoValue.Builder", 2674 " public interface Builder<E> {", 2675 " ListFactory<E> blimBuilder();", 2676 " Baz<E> build();", 2677 " }", 2678 "}"); 2679 Compilation compilation = 2680 javac() 2681 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2682 .compile(javaFileObject); 2683 assertThat(compilation) 2684 .hadErrorContaining( 2685 "Property builder for blim has type foo.bar.Baz.ListFactory whose build() method " 2686 + "returns java.util.List<? extends E> instead of java.util.List<E>") 2687 .inFile(javaFileObject) 2688 .onLineContaining("ListFactory<E> blimBuilder()"); 2689 } 2690 2691 @Test autoValueBuilderPropertyBuilderCantConstruct()2692 public void autoValueBuilderPropertyBuilderCantConstruct() { 2693 JavaFileObject javaFileObject = 2694 JavaFileObjects.forSourceLines( 2695 "foo.bar.Baz", 2696 "package foo.bar;", 2697 "", 2698 "import com.google.auto.value.AutoValue;", 2699 "import com.google.common.collect.ImmutableSet;", 2700 "", 2701 "@AutoValue", 2702 "public abstract class Baz<E> {", 2703 " abstract String blim();", 2704 "", 2705 " public static class StringFactory {", 2706 " private StringFactory() {}", 2707 "", 2708 " public String build() {", 2709 " return null;", 2710 " }", 2711 " }", 2712 "", 2713 " @AutoValue.Builder", 2714 " public interface Builder<E> {", 2715 " StringFactory blimBuilder();", 2716 " Baz<E> build();", 2717 " }", 2718 "}"); 2719 Compilation compilation = 2720 javac() 2721 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2722 .compile(javaFileObject); 2723 assertThat(compilation) 2724 .hadErrorContaining( 2725 "Method looks like a property builder, but its type foo.bar.Baz.StringFactory " 2726 + "does not have a public constructor and java.lang.String does not have a static " 2727 + "builder() or newBuilder() method that returns foo.bar.Baz.StringFactory") 2728 .inFile(javaFileObject) 2729 .onLineContaining("StringFactory blimBuilder()"); 2730 } 2731 2732 @Test autoValueBuilderPropertyBuilderCantReconstruct()2733 public void autoValueBuilderPropertyBuilderCantReconstruct() { 2734 JavaFileObject javaFileObject = 2735 JavaFileObjects.forSourceLines( 2736 "foo.bar.Baz", 2737 "package foo.bar;", 2738 "", 2739 "import com.google.auto.value.AutoValue;", 2740 "", 2741 "@AutoValue", 2742 "public abstract class Baz<E> {", 2743 " abstract String blim();", 2744 " abstract Builder<E> toBuilder();", 2745 "", 2746 " public static class StringFactory {", 2747 " public String build() {", 2748 " return null;", 2749 " }", 2750 " }", 2751 "", 2752 " @AutoValue.Builder", 2753 " public interface Builder<E> {", 2754 " StringFactory blimBuilder();", 2755 " Baz<E> build();", 2756 " }", 2757 "}"); 2758 Compilation compilation = 2759 javac() 2760 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2761 .compile(javaFileObject); 2762 assertThat(compilation) 2763 .hadErrorContaining( 2764 "Property builder method returns foo.bar.Baz.StringFactory but there is no way to make" 2765 + " that type from java.lang.String: java.lang.String does not have a non-static" 2766 + " toBuilder() method that returns foo.bar.Baz.StringFactory, and" 2767 + " foo.bar.Baz.StringFactory does not have a method addAll or putAll that accepts" 2768 + " an argument of type java.lang.String") 2769 .inFile(javaFileObject) 2770 .onLineContaining("StringFactory blimBuilder()"); 2771 } 2772 2773 @Test autoValueBuilderPropertyBuilderWrongTypeAddAll()2774 public void autoValueBuilderPropertyBuilderWrongTypeAddAll() { 2775 JavaFileObject javaFileObject = 2776 JavaFileObjects.forSourceLines( 2777 "foo.bar.Baz", 2778 "package foo.bar;", 2779 "", 2780 "import com.google.auto.value.AutoValue;", 2781 "import com.google.common.collect.ImmutableSet;", 2782 "import java.util.Iterator;", 2783 "", 2784 "@AutoValue", 2785 "public abstract class Baz<T> {", 2786 " abstract ImmutableSet<String> strings();", 2787 " abstract Builder<T> toBuilder();", 2788 "", 2789 " public static class ImmutableSetBuilder<E> {", 2790 " public void addAll(Iterator<? extends E> elements) {}", 2791 "", 2792 " public ImmutableSet<E> build() {", 2793 " return null;", 2794 " }", 2795 " }", 2796 "", 2797 " @AutoValue.Builder", 2798 " public interface Builder<T> {", 2799 " ImmutableSetBuilder<String> stringsBuilder();", 2800 " Baz<T> build();", 2801 " }", 2802 "}"); 2803 Compilation compilation = 2804 javac() 2805 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2806 .compile(javaFileObject); 2807 assertThat(compilation) 2808 .hadErrorContaining( 2809 "Property builder method returns foo.bar.Baz.ImmutableSetBuilder<java.lang.String> but" 2810 + " there is no way to make that type from" 2811 + " com.google.common.collect.ImmutableSet<java.lang.String>:" 2812 + " com.google.common.collect.ImmutableSet<java.lang.String> does not have a" 2813 + " non-static toBuilder() method that returns" 2814 + " foo.bar.Baz.ImmutableSetBuilder<java.lang.String>, and" 2815 + " foo.bar.Baz.ImmutableSetBuilder<java.lang.String> does not have a method" 2816 + " addAll or putAll that accepts an argument of type" 2817 + " com.google.common.collect.ImmutableSet<java.lang.String>") 2818 .inFile(javaFileObject) 2819 .onLineContaining("ImmutableSetBuilder<String> stringsBuilder();"); 2820 } 2821 2822 @Test autoValueBuilderPropertyBuilderCantSet()2823 public void autoValueBuilderPropertyBuilderCantSet() { 2824 JavaFileObject javaFileObject = 2825 JavaFileObjects.forSourceLines( 2826 "foo.bar.Baz", 2827 "package foo.bar;", 2828 "", 2829 "import com.google.auto.value.AutoValue;", 2830 "import com.google.common.collect.ImmutableSet;", 2831 "", 2832 "@AutoValue", 2833 "public abstract class Baz<E> {", 2834 " abstract String blim();", 2835 "", 2836 " public static class StringFactory {", 2837 " public String build() {", 2838 " return null;", 2839 " }", 2840 " }", 2841 "", 2842 " @AutoValue.Builder", 2843 " public interface Builder<E> {", 2844 " Builder<E> setBlim(String s);", 2845 " StringFactory blimBuilder();", 2846 " Baz<E> build();", 2847 " }", 2848 "}"); 2849 Compilation compilation = 2850 javac() 2851 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2852 .compile(javaFileObject); 2853 assertThat(compilation) 2854 .hadErrorContaining( 2855 "Property builder method returns foo.bar.Baz.StringFactory but there is no way to make " 2856 + "that type from java.lang.String: java.lang.String does not have a non-static " 2857 + "toBuilder() method that returns foo.bar.Baz.StringFactory") 2858 .inFile(javaFileObject) 2859 .onLineContaining("StringFactory blimBuilder()"); 2860 } 2861 2862 @Test autoValueBuilderPropertyBuilderWrongTypeToBuilder()2863 public void autoValueBuilderPropertyBuilderWrongTypeToBuilder() { 2864 JavaFileObject javaFileObject = 2865 JavaFileObjects.forSourceLines( 2866 "foo.bar.Baz", 2867 "package foo.bar;", 2868 "", 2869 "import com.google.auto.value.AutoValue;", 2870 "import com.google.common.collect.ImmutableSet;", 2871 "", 2872 "@AutoValue", 2873 "public abstract class Baz<E> {", 2874 " abstract Buh blim();", 2875 " abstract Builder<E> toBuilder();", 2876 "", 2877 " public static class Buh {", 2878 " StringBuilder toBuilder() {", 2879 " return null;", 2880 " }", 2881 " }", 2882 "", 2883 " public static class BuhBuilder {", 2884 " public Buh build() {", 2885 " return null;", 2886 " }", 2887 " }", 2888 "", 2889 " @AutoValue.Builder", 2890 " public interface Builder<E> {", 2891 " BuhBuilder blimBuilder();", 2892 " Baz<E> build();", 2893 " }", 2894 "}"); 2895 Compilation compilation = 2896 javac() 2897 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2898 .compile(javaFileObject); 2899 assertThat(compilation) 2900 .hadErrorContaining( 2901 "Property builder method returns foo.bar.Baz.BuhBuilder but there is no way to make " 2902 + "that type from foo.bar.Baz.Buh: foo.bar.Baz.Buh does not have a non-static " 2903 + "toBuilder() method that returns foo.bar.Baz.BuhBuilder") 2904 .inFile(javaFileObject) 2905 .onLineContaining("BuhBuilder blimBuilder()"); 2906 } 2907 2908 @Test autoValueBuilderPropertyBuilderWrongElementType()2909 public void autoValueBuilderPropertyBuilderWrongElementType() { 2910 JavaFileObject javaFileObject = 2911 JavaFileObjects.forSourceLines( 2912 "foo.bar.Baz", 2913 "package foo.bar;", 2914 "", 2915 "import com.google.auto.value.AutoValue;", 2916 "import com.google.common.collect.ImmutableSet;", 2917 "", 2918 "@AutoValue", 2919 "public abstract class Baz<T, U> {", 2920 " abstract ImmutableSet<T> blim();", 2921 "", 2922 " @AutoValue.Builder", 2923 " public interface Builder<T, U> {", 2924 " ImmutableSet.Builder<U> blimBuilder();", 2925 " Baz<T, U> build();", 2926 " }", 2927 "}"); 2928 Compilation compilation = 2929 javac() 2930 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2931 .compile(javaFileObject); 2932 assertThat(compilation) 2933 .hadErrorContaining( 2934 "Property builder for blim has type com.google.common.collect.ImmutableSet.Builder " 2935 + "whose build() method returns com.google.common.collect.ImmutableSet<U> " 2936 + "instead of com.google.common.collect.ImmutableSet<T>") 2937 .inFile(javaFileObject) 2938 .onLineContaining("ImmutableSet.Builder<U> blimBuilder()"); 2939 } 2940 2941 @Test autoValueBuilderAlienMethod0()2942 public void autoValueBuilderAlienMethod0() { 2943 JavaFileObject javaFileObject = 2944 JavaFileObjects.forSourceLines( 2945 "foo.bar.Baz", 2946 "package foo.bar;", 2947 "", 2948 "import com.google.auto.value.AutoValue;", 2949 "", 2950 "@AutoValue", 2951 "public abstract class Baz {", 2952 " abstract String blam();", 2953 "", 2954 " @AutoValue.Builder", 2955 " public interface Builder {", 2956 " Builder blam(String x);", 2957 " Builder whut();", 2958 " Baz build();", 2959 " }", 2960 "}"); 2961 Compilation compilation = 2962 javac() 2963 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2964 .compile(javaFileObject); 2965 assertThat(compilation) 2966 .hadErrorContaining( 2967 "Method without arguments should be a build method returning foo.bar.Baz, or a getter" 2968 + " method with the same name and type as a property method of foo.bar.Baz, or" 2969 + " fooBuilder() where foo() or getFoo() is a property method of foo.bar.Baz") 2970 .inFile(javaFileObject) 2971 .onLineContaining("Builder whut()"); 2972 } 2973 2974 @Test autoValueBuilderAlienMethod1()2975 public void autoValueBuilderAlienMethod1() { 2976 JavaFileObject javaFileObject = 2977 JavaFileObjects.forSourceLines( 2978 "foo.bar.Baz", 2979 "package foo.bar;", 2980 "", 2981 "import com.google.auto.value.AutoValue;", 2982 "", 2983 "@AutoValue", 2984 "public abstract class Baz {", 2985 " abstract String blam();", 2986 "", 2987 " @AutoValue.Builder", 2988 " public interface Builder {", 2989 " void whut(String x);", 2990 " Baz build();", 2991 " }", 2992 "}"); 2993 Compilation compilation = 2994 javac() 2995 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 2996 .compile(javaFileObject); 2997 assertThat(compilation) 2998 .hadErrorContaining("Method whut does not correspond to a property method of foo.bar.Baz") 2999 .inFile(javaFileObject) 3000 .onLineContaining("void whut(String x)"); 3001 } 3002 3003 @Test autoValueBuilderAlienMethod2()3004 public void autoValueBuilderAlienMethod2() { 3005 JavaFileObject javaFileObject = 3006 JavaFileObjects.forSourceLines( 3007 "foo.bar.Baz", 3008 "package foo.bar;", 3009 "", 3010 "import com.google.auto.value.AutoValue;", 3011 "", 3012 "@AutoValue", 3013 "public abstract class Baz {", 3014 " abstract String blam();", 3015 "", 3016 " @AutoValue.Builder", 3017 " public interface Builder {", 3018 " Builder blam(String x, String y);", 3019 " Baz build();", 3020 " }", 3021 "}"); 3022 Compilation compilation = 3023 javac() 3024 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3025 .compile(javaFileObject); 3026 assertThat(compilation) 3027 .hadErrorContaining("Builder methods must have 0 or 1 parameters") 3028 .inFile(javaFileObject) 3029 .onLineContaining("Builder blam(String x, String y)"); 3030 } 3031 3032 @Test autoValueBuilderMissingBuildMethod()3033 public void autoValueBuilderMissingBuildMethod() { 3034 JavaFileObject javaFileObject = 3035 JavaFileObjects.forSourceLines( 3036 "foo.bar.Baz", 3037 "package foo.bar;", 3038 "", 3039 "import com.google.auto.value.AutoValue;", 3040 "", 3041 "@AutoValue", 3042 "public abstract class Baz<T> {", 3043 " abstract T blam();", 3044 "", 3045 " @AutoValue.Builder", 3046 " public interface Builder<T> {", 3047 " Builder<T> blam(T x);", 3048 " }", 3049 "}"); 3050 Compilation compilation = 3051 javac() 3052 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3053 .compile(javaFileObject); 3054 assertThat(compilation) 3055 .hadErrorContaining( 3056 "Builder must have a single no-argument method, typically called build(), that returns" 3057 + " foo.bar.Baz<T>") 3058 .inFile(javaFileObject) 3059 .onLineContaining("public interface Builder<T>"); 3060 } 3061 3062 @Test autoValueBuilderDuplicateBuildMethods()3063 public void autoValueBuilderDuplicateBuildMethods() { 3064 JavaFileObject javaFileObject = 3065 JavaFileObjects.forSourceLines( 3066 "foo.bar.Baz", 3067 "package foo.bar;", 3068 "", 3069 "import com.google.auto.value.AutoValue;", 3070 "", 3071 "@AutoValue", 3072 "public abstract class Baz {", 3073 " abstract String blam();", 3074 "", 3075 " @AutoValue.Builder", 3076 " public interface Builder {", 3077 " Builder blam(String x);", 3078 " Baz build();", 3079 " Baz create();", 3080 " }", 3081 "}"); 3082 Compilation compilation = 3083 javac() 3084 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3085 .compile(javaFileObject); 3086 assertThat(compilation) 3087 .hadErrorContaining( 3088 "Builder must have a single no-argument method, typically called build(), that returns" 3089 + " foo.bar.Baz") 3090 .inFile(javaFileObject) 3091 .onLineContaining("Baz build()"); 3092 assertThat(compilation) 3093 .hadErrorContaining( 3094 "Builder must have a single no-argument method, typically called build(), that returns" 3095 + " foo.bar.Baz") 3096 .inFile(javaFileObject) 3097 .onLineContaining("Baz create()"); 3098 } 3099 3100 @Test autoValueBuilderWrongTypeBuildMethod()3101 public void autoValueBuilderWrongTypeBuildMethod() { 3102 JavaFileObject javaFileObject = 3103 JavaFileObjects.forSourceLines( 3104 "foo.bar.Baz", 3105 "package foo.bar;", 3106 "", 3107 "import com.google.auto.value.AutoValue;", 3108 "", 3109 "@AutoValue", 3110 "public abstract class Baz {", 3111 " abstract String blam();", 3112 "", 3113 " @AutoValue.Builder", 3114 " public interface Builder {", 3115 " Builder blam(String x);", 3116 " String build();", 3117 " }", 3118 "}"); 3119 Compilation compilation = 3120 javac() 3121 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3122 .compile(javaFileObject); 3123 assertThat(compilation) 3124 .hadErrorContaining( 3125 "Method without arguments should be a build method returning foo.bar.Baz") 3126 .inFile(javaFileObject) 3127 .onLineContaining("String build()"); 3128 } 3129 3130 @Test autoValueBuilderTypeParametersDontMatch1()3131 public void autoValueBuilderTypeParametersDontMatch1() { 3132 JavaFileObject javaFileObject = 3133 JavaFileObjects.forSourceLines( 3134 "foo.bar.Baz", 3135 "package foo.bar;", 3136 "", 3137 "import com.google.auto.value.AutoValue;", 3138 "", 3139 "@AutoValue", 3140 "public abstract class Baz<T> {", 3141 " abstract String blam();", 3142 "", 3143 " @AutoValue.Builder", 3144 " public interface Builder {", 3145 " Builder blam(String x);", 3146 " Baz build();", 3147 " }", 3148 "}"); 3149 Compilation compilation = 3150 javac() 3151 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3152 .compile(javaFileObject); 3153 assertThat(compilation) 3154 .hadErrorContaining( 3155 "Type parameters of foo.bar.Baz.Builder must have same names and " 3156 + "bounds as type parameters of foo.bar.Baz") 3157 .inFile(javaFileObject) 3158 .onLineContaining("public interface Builder"); 3159 } 3160 3161 @Test autoValueBuilderTypeParametersDontMatch2()3162 public void autoValueBuilderTypeParametersDontMatch2() { 3163 JavaFileObject javaFileObject = 3164 JavaFileObjects.forSourceLines( 3165 "foo.bar.Baz", 3166 "package foo.bar;", 3167 "", 3168 "import com.google.auto.value.AutoValue;", 3169 "", 3170 "@AutoValue", 3171 "public abstract class Baz<T> {", 3172 " abstract T blam();", 3173 "", 3174 " @AutoValue.Builder", 3175 " public interface Builder<E> {", 3176 " Builder<E> blam(E x);", 3177 " Baz build();", 3178 " }", 3179 "}"); 3180 Compilation compilation = 3181 javac() 3182 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3183 .compile(javaFileObject); 3184 assertThat(compilation) 3185 .hadErrorContaining( 3186 "Type parameters of foo.bar.Baz.Builder must have same names and " 3187 + "bounds as type parameters of foo.bar.Baz") 3188 .inFile(javaFileObject) 3189 .onLineContaining("public interface Builder<E>"); 3190 } 3191 3192 @Test autoValueBuilderTypeParametersDontMatch3()3193 public void autoValueBuilderTypeParametersDontMatch3() { 3194 JavaFileObject javaFileObject = 3195 JavaFileObjects.forSourceLines( 3196 "foo.bar.Baz", 3197 "package foo.bar;", 3198 "", 3199 "import com.google.auto.value.AutoValue;", 3200 "", 3201 "@AutoValue", 3202 "public abstract class Baz<T extends Number & Comparable<T>> {", 3203 " abstract T blam();", 3204 "", 3205 " @AutoValue.Builder", 3206 " public interface Builder<T extends Number> {", 3207 " Builder<T> blam(T x);", 3208 " Baz build();", 3209 " }", 3210 "}"); 3211 Compilation compilation = 3212 javac() 3213 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3214 .compile(javaFileObject); 3215 assertThat(compilation) 3216 .hadErrorContaining( 3217 "Type parameters of foo.bar.Baz.Builder must have same names and " 3218 + "bounds as type parameters of foo.bar.Baz") 3219 .inFile(javaFileObject) 3220 .onLineContaining("public interface Builder<T extends Number>"); 3221 } 3222 3223 @Test autoValueBuilderToBuilderWrongTypeParameters()3224 public void autoValueBuilderToBuilderWrongTypeParameters() { 3225 JavaFileObject javaFileObject = 3226 JavaFileObjects.forSourceLines( 3227 "foo.bar.Baz", 3228 "package foo.bar;", 3229 "", 3230 "import com.google.auto.value.AutoValue;", 3231 "", 3232 "@AutoValue", 3233 "abstract class Baz<K extends Comparable<K>, V> {", 3234 " abstract K key();", 3235 " abstract V value();", 3236 " abstract Builder<V, K> toBuilder1();", 3237 "", 3238 " @AutoValue.Builder", 3239 " interface Builder<K extends Comparable<K>, V> {", 3240 " Builder<K, V> key(K key);", 3241 " Builder<K, V> value(V value);", 3242 " Baz<K, V> build();", 3243 " }", 3244 "}"); 3245 Compilation compilation = 3246 javac() 3247 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3248 .compile(javaFileObject); 3249 assertThat(compilation) 3250 .hadErrorContaining("Builder converter method should return foo.bar.Baz.Builder<K, V>") 3251 .inFile(javaFileObject) 3252 .onLineContaining("abstract Builder<V, K> toBuilder1()"); 3253 } 3254 3255 @Test autoValueBuilderToBuilderDuplicate()3256 public void autoValueBuilderToBuilderDuplicate() { 3257 JavaFileObject javaFileObject = 3258 JavaFileObjects.forSourceLines( 3259 "foo.bar.Baz", 3260 "package foo.bar;", 3261 "", 3262 "import com.google.auto.value.AutoValue;", 3263 "", 3264 "@AutoValue", 3265 "abstract class Baz<K extends Comparable<K>, V> {", 3266 " abstract K key();", 3267 " abstract V value();", 3268 " abstract Builder<K, V> toBuilder1();", 3269 " abstract Builder<K, V> toBuilder2();", 3270 "", 3271 " @AutoValue.Builder", 3272 " interface Builder<K extends Comparable<K>, V> {", 3273 " Builder<K, V> key(K key);", 3274 " Builder<K, V> value(V value);", 3275 " Baz<K, V> build();", 3276 " }", 3277 "}"); 3278 Compilation compilation = 3279 javac() 3280 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3281 .compile(javaFileObject); 3282 assertThat(compilation) 3283 .hadErrorContaining("There can be at most one builder converter method") 3284 .inFile(javaFileObject) 3285 .onLineContaining("abstract Builder<K, V> toBuilder1()"); 3286 } 3287 3288 @Test getFooIsFoo()3289 public void getFooIsFoo() { 3290 JavaFileObject javaFileObject = 3291 JavaFileObjects.forSourceLines( 3292 "foo.bar.Baz", 3293 "package foo.bar;", 3294 "", 3295 "import com.google.auto.value.AutoValue;", 3296 "", 3297 "@AutoValue", 3298 "public abstract class Baz {", 3299 " abstract int getFoo();", 3300 " abstract boolean isFoo();", 3301 "}"); 3302 Compilation compilation = 3303 javac() 3304 .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) 3305 .compile(javaFileObject); 3306 assertThat(compilation) 3307 .hadErrorContaining("More than one @AutoValue property called foo") 3308 .inFile(javaFileObject) 3309 .onLineContaining("getFoo"); 3310 assertThat(compilation) 3311 .hadErrorContaining("More than one @AutoValue property called foo") 3312 .inFile(javaFileObject) 3313 .onLineContaining("isFoo"); 3314 } 3315 3316 @Retention(RetentionPolicy.SOURCE) 3317 public @interface Foo {} 3318 3319 /* Processor that generates an empty class BarFoo every time it sees a class Bar annotated with 3320 * @Foo. 3321 */ 3322 public static class FooProcessor extends AbstractProcessor { 3323 @Override getSupportedAnnotationTypes()3324 public Set<String> getSupportedAnnotationTypes() { 3325 return ImmutableSet.of(Foo.class.getCanonicalName()); 3326 } 3327 3328 @Override getSupportedSourceVersion()3329 public SourceVersion getSupportedSourceVersion() { 3330 return SourceVersion.latestSupported(); 3331 } 3332 3333 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)3334 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 3335 Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Foo.class); 3336 for (TypeElement type : ElementFilter.typesIn(elements)) { 3337 try { 3338 generateFoo(type); 3339 } catch (IOException e) { 3340 throw new AssertionError(e); 3341 } 3342 } 3343 return false; 3344 } 3345 generateFoo(TypeElement type)3346 private void generateFoo(TypeElement type) throws IOException { 3347 String pkg = TypeSimplifier.packageNameOf(type); 3348 String className = type.getSimpleName().toString(); 3349 String generatedClassName = className + "Foo"; 3350 JavaFileObject source = 3351 processingEnv.getFiler().createSourceFile(pkg + "." + generatedClassName, type); 3352 PrintWriter writer = new PrintWriter(source.openWriter()); 3353 writer.println("package " + pkg + ";"); 3354 writer.println("public class " + generatedClassName + " {}"); 3355 writer.close(); 3356 } 3357 } 3358 3359 @Test referencingGeneratedClass()3360 public void referencingGeneratedClass() { 3361 // Test that ensures that a type that does not exist can be the type of an @AutoValue property 3362 // as long as it later does come into existence. The BarFoo type referenced here does not exist 3363 // when the AutoValueProcessor runs on the first round, but the FooProcessor then generates it. 3364 // That generation provokes a further round of annotation processing and AutoValueProcessor 3365 // should succeed then. 3366 JavaFileObject bazFileObject = 3367 JavaFileObjects.forSourceLines( 3368 "foo.bar.Baz", 3369 "package foo.bar;", 3370 "", 3371 "import com.google.auto.value.AutoValue;", 3372 "", 3373 "@AutoValue", 3374 "public abstract class Baz {", 3375 " public abstract BarFoo barFoo();", 3376 "", 3377 " public static Baz create(BarFoo barFoo) {", 3378 " return new AutoValue_Baz(barFoo);", 3379 " }", 3380 "}"); 3381 JavaFileObject barFileObject = 3382 JavaFileObjects.forSourceLines( 3383 "foo.bar.Bar", 3384 "package foo.bar;", 3385 "", 3386 "@" + Foo.class.getCanonicalName(), 3387 "public abstract class Bar {", 3388 " public abstract BarFoo barFoo();", 3389 "}"); 3390 Compilation compilation = 3391 javac() 3392 .withProcessors(new AutoValueProcessor(), new FooProcessor()) 3393 .withOptions("-Xlint:-processing", "-implicit:none") 3394 .compile(bazFileObject, barFileObject); 3395 assertThat(compilation).succeededWithoutWarnings(); 3396 } 3397 3398 @Test referencingGeneratedClassInAnnotation()3399 public void referencingGeneratedClassInAnnotation() { 3400 // Test that ensures that a type that does not exist can be referenced by a copied annotation 3401 // as long as it later does come into existence. The BarFoo type referenced here does not exist 3402 // when the AutoValueProcessor runs on the first round, but the FooProcessor then generates it. 3403 // That generation provokes a further round of annotation processing and AutoValueProcessor 3404 // should succeed then. 3405 // We test the three places that a class reference could appear: as the value of a Class 3406 // element, as the value of a Class[] element, in a nested annotation. 3407 JavaFileObject barFileObject = 3408 JavaFileObjects.forSourceLines( 3409 "foo.bar.Bar", 3410 "package foo.bar;", 3411 "", 3412 "@" + Foo.class.getCanonicalName(), 3413 "public abstract class Bar {", 3414 "}"); 3415 JavaFileObject referenceClassFileObject = 3416 JavaFileObjects.forSourceLines( 3417 "foo.bar.ReferenceClass", 3418 "package foo.bar;", 3419 "", 3420 "@interface ReferenceClass {", 3421 " Class<?> value() default Void.class;", 3422 " Class<?>[] values() default {};", 3423 " Nested nested() default @Nested;", 3424 " @interface Nested {", 3425 " Class<?>[] values() default {};", 3426 " }", 3427 "}"); 3428 ImmutableList<String> annotations = ImmutableList.of( 3429 "@ReferenceClass(BarFoo.class)", 3430 "@ReferenceClass(values = {Void.class, BarFoo.class})", 3431 "@ReferenceClass(nested = @ReferenceClass.Nested(values = {Void.class, BarFoo.class}))"); 3432 for (String annotation : annotations) { 3433 JavaFileObject bazFileObject = 3434 JavaFileObjects.forSourceLines( 3435 "foo.bar.Baz", 3436 "package foo.bar;", 3437 "", 3438 "import com.google.auto.value.AutoValue;", 3439 "", 3440 "@AutoValue", 3441 "@AutoValue.CopyAnnotations", 3442 annotation, 3443 "public abstract class Baz {", 3444 " public abstract int foo();", 3445 "", 3446 " public static Baz create(int foo) {", 3447 " return new AutoValue_Baz(foo);", 3448 " }", 3449 "}"); 3450 Compilation compilation = 3451 javac() 3452 .withProcessors(new AutoValueProcessor(), new FooProcessor()) 3453 .withOptions("-Xlint:-processing", "-implicit:none") 3454 .compile(bazFileObject, barFileObject, referenceClassFileObject); 3455 expect.about(compilations()).that(compilation).succeededWithoutWarnings(); 3456 if (compilation.status().equals(Compilation.Status.SUCCESS)) { 3457 expect.about(compilations()).that(compilation) 3458 .generatedSourceFile("foo.bar.AutoValue_Baz") 3459 .contentsAsUtf8String() 3460 .contains(annotation); 3461 } 3462 } 3463 } 3464 3465 @Test annotationReferencesUndefined()3466 public void annotationReferencesUndefined() { 3467 // Test that we don't throw an exception if asked to compile @SuppressWarnings(UNDEFINED) 3468 // where UNDEFINED is an undefined symbol. 3469 JavaFileObject bazFileObject = 3470 JavaFileObjects.forSourceLines( 3471 "foo.bar.Baz", 3472 "package foo.bar;", 3473 "", 3474 "import com.google.auto.value.AutoValue;", 3475 "", 3476 "@AutoValue", 3477 "public abstract class Baz {", 3478 " @SuppressWarnings(UNDEFINED)", 3479 " public abstract int[] buh();", 3480 "}"); 3481 Compilation compilation1 = 3482 javac() 3483 .withOptions("-Xlint:-processing") 3484 .withProcessors(new AutoValueProcessor()) 3485 .compile(bazFileObject); 3486 assertThat(compilation1).hadErrorCount(1); 3487 assertThat(compilation1) 3488 .hadErrorContaining("UNDEFINED") 3489 .inFile(bazFileObject) 3490 .onLineContaining("UNDEFINED"); 3491 assertThat(compilation1).hadWarningCount(1); 3492 assertThat(compilation1) 3493 .hadWarningContaining("mutable") 3494 .inFile(bazFileObject) 3495 .onLineContaining("public abstract int[] buh()"); 3496 3497 // Same test, except we do successfully suppress the warning despite the UNDEFINED. 3498 bazFileObject = 3499 JavaFileObjects.forSourceLines( 3500 "foo.bar.Baz", 3501 "package foo.bar;", 3502 "", 3503 "import com.google.auto.value.AutoValue;", 3504 "", 3505 "@AutoValue", 3506 "public abstract class Baz {", 3507 " @SuppressWarnings({UNDEFINED, \"mutable\"})", 3508 " public abstract int[] buh();", 3509 "}"); 3510 Compilation compilation2 = 3511 javac() 3512 .withOptions("-Xlint:-processing") 3513 .withProcessors(new AutoValueProcessor()) 3514 .compile(bazFileObject); 3515 assertThat(compilation2).hadErrorCount(1); 3516 assertThat(compilation2) 3517 .hadErrorContaining("UNDEFINED") 3518 .inFile(bazFileObject) 3519 .onLineContaining("UNDEFINED"); 3520 assertThat(compilation2).hadWarningCount(0); 3521 } 3522 3523 @Test packagePrivateAnnotationFromOtherPackage()3524 public void packagePrivateAnnotationFromOtherPackage() { 3525 JavaFileObject bazFileObject = 3526 JavaFileObjects.forSourceLines( 3527 "foo.bar.Baz", 3528 "package foo.bar;", 3529 "", 3530 "import com.google.auto.value.AutoValue;", 3531 "", 3532 "@AutoValue", 3533 "public abstract class Baz extends otherpackage.Parent {", 3534 "}"); 3535 JavaFileObject parentFileObject = 3536 JavaFileObjects.forSourceLines( 3537 "otherpackage.Parent", 3538 "package otherpackage;", 3539 "", 3540 "public abstract class Parent {", 3541 " @PackageAnnotation", 3542 " public abstract String foo();", 3543 "", 3544 " @interface PackageAnnotation {}", 3545 "}"); 3546 Compilation compilation = 3547 javac() 3548 .withProcessors(new AutoValueProcessor()) 3549 .withOptions("-Xlint:-processing", "-implicit:none") 3550 .compile(bazFileObject, parentFileObject); 3551 assertThat(compilation).succeededWithoutWarnings(); 3552 assertThat(compilation).generatedSourceFile("foo.bar.AutoValue_Baz"); 3553 } 3554 3555 @Test visibleProtectedAnnotationFromOtherPackage()3556 public void visibleProtectedAnnotationFromOtherPackage() { 3557 JavaFileObject bazFileObject = 3558 JavaFileObjects.forSourceLines( 3559 "foo.bar.Baz", 3560 "package foo.bar;", 3561 "", 3562 "import com.google.auto.value.AutoValue;", 3563 "", 3564 "@AutoValue", 3565 "public abstract class Baz extends otherpackage.Parent {}"); 3566 JavaFileObject parentFileObject = 3567 JavaFileObjects.forSourceLines( 3568 "otherpackage.Parent", 3569 "package otherpackage;", 3570 "", 3571 "public abstract class Parent {", 3572 " @ProtectedAnnotation", 3573 " public abstract String foo();", 3574 "", 3575 " protected @interface ProtectedAnnotation {}", 3576 "}"); 3577 Compilation compilation = 3578 javac() 3579 .withProcessors(new AutoValueProcessor()) 3580 .withOptions("-Xlint:-processing", "-implicit:none") 3581 .compile(bazFileObject, parentFileObject); 3582 assertThat(compilation).succeededWithoutWarnings(); 3583 assertThat(compilation) 3584 .generatedSourceFile("foo.bar.AutoValue_Baz") 3585 .contentsAsUtf8String() 3586 .containsMatch("(?s:@Parent.ProtectedAnnotation\\s*@Override\\s*public String foo\\(\\))"); 3587 } 3588 3589 @Test methodAnnotationsCopiedInLexicographicalOrder()3590 public void methodAnnotationsCopiedInLexicographicalOrder() { 3591 JavaFileObject bazFileObject = 3592 JavaFileObjects.forSourceLines( 3593 "foo.bar.Baz", 3594 "package foo.bar;", 3595 "", 3596 "import com.google.auto.value.AutoValue;", 3597 "import com.package1.Annotation1;", 3598 "import com.package2.Annotation0;", 3599 "", 3600 "@AutoValue", 3601 "public abstract class Baz extends Parent {", 3602 " @Annotation0", 3603 " @Annotation1", 3604 " @Override", 3605 " public abstract String foo();", 3606 "}"); 3607 JavaFileObject parentFileObject = 3608 JavaFileObjects.forSourceLines( 3609 "foo.bar.Parent", 3610 "package foo.bar;", 3611 "", 3612 "public abstract class Parent {", 3613 " public abstract String foo();", 3614 "}"); 3615 JavaFileObject annotation1FileObject = 3616 JavaFileObjects.forSourceLines( 3617 "com.package1.Annotation1", 3618 "package com.package1;", 3619 "", 3620 "import java.lang.annotation.ElementType;", 3621 "import java.lang.annotation.Target;", 3622 "", 3623 "@Target({ElementType.FIELD, ElementType.METHOD})", 3624 "public @interface Annotation1 {}"); 3625 JavaFileObject annotation0FileObject = 3626 JavaFileObjects.forSourceLines( 3627 "com.package2.Annotation0", 3628 "package com.package2;", 3629 "", 3630 "public @interface Annotation0 {}"); 3631 Compilation compilation = 3632 javac() 3633 .withProcessors(new AutoValueProcessor()) 3634 .withOptions("-Xlint:-processing", "-implicit:none") 3635 .compile(bazFileObject, parentFileObject, annotation1FileObject, annotation0FileObject); 3636 assertThat(compilation).succeededWithoutWarnings(); 3637 assertThat(compilation) 3638 .generatedSourceFile("foo.bar.AutoValue_Baz") 3639 .contentsAsUtf8String() 3640 .containsMatch( 3641 "(?s:@Annotation1\\s+@Annotation0\\s+@Override\\s+public String foo\\(\\))"); 3642 // @Annotation1 precedes @Annotation 0 because 3643 // @com.package2.Annotation1 precedes @com.package1.Annotation0 3644 } 3645 3646 @Test nonVisibleProtectedAnnotationFromOtherPackage()3647 public void nonVisibleProtectedAnnotationFromOtherPackage() { 3648 JavaFileObject bazFileObject = 3649 JavaFileObjects.forSourceLines( 3650 "foo.bar.Baz", 3651 "package foo.bar;", 3652 "", 3653 "import com.google.auto.value.AutoValue;", 3654 "", 3655 "@AutoValue", 3656 "public abstract class Baz extends otherpackage.Parent {", 3657 "}"); 3658 JavaFileObject parentFileObject = 3659 JavaFileObjects.forSourceLines( 3660 "otherpackage.Parent", 3661 "package otherpackage;", 3662 "", 3663 "import otherpackage.Annotations.ProtectedAnnotation;", 3664 "", 3665 "public abstract class Parent {", 3666 " @ProtectedAnnotation", 3667 " public abstract String foo();", 3668 "}"); 3669 JavaFileObject annotationsFileObject = 3670 JavaFileObjects.forSourceLines( 3671 "otherpackage.Annotations", 3672 "package otherpackage;", 3673 "", 3674 "public class Annotations {", 3675 " protected @interface ProtectedAnnotation {}", 3676 "}"); 3677 Compilation compilation = 3678 javac() 3679 .withProcessors(new AutoValueProcessor()) 3680 .withOptions("-Xlint:-processing", "-implicit:none") 3681 .compile(bazFileObject, parentFileObject, annotationsFileObject); 3682 assertThat(compilation).succeededWithoutWarnings(); 3683 assertThat(compilation) 3684 .generatedSourceFile("foo.bar.AutoValue_Baz") 3685 .contentsAsUtf8String() 3686 .doesNotContain("ProtectedAnnotation"); 3687 } 3688 3689 @Test nonVisibleProtectedClassAnnotationFromOtherPackage()3690 public void nonVisibleProtectedClassAnnotationFromOtherPackage() { 3691 JavaFileObject bazFileObject = 3692 JavaFileObjects.forSourceLines( 3693 "foo.bar.Outer", 3694 "package foo.bar;", 3695 "", 3696 "import com.google.auto.value.AutoValue;", 3697 "", 3698 "class Outer extends otherpackage.Parent {", 3699 " @AutoValue", 3700 " @AutoValue.CopyAnnotations", 3701 " @ProtectedAnnotation", 3702 " abstract static class Inner {", 3703 " abstract String foo();", 3704 " }", 3705 "}"); 3706 JavaFileObject parentFileObject = 3707 JavaFileObjects.forSourceLines( 3708 "otherpackage.Parent", 3709 "package otherpackage;", 3710 "", 3711 "public abstract class Parent {", 3712 " protected @interface ProtectedAnnotation {}", 3713 "}"); 3714 Compilation compilation = 3715 javac() 3716 .withProcessors(new AutoValueProcessor()) 3717 .withOptions("-Xlint:-processing", "-implicit:none") 3718 .compile(bazFileObject, parentFileObject); 3719 assertThat(compilation).succeededWithoutWarnings(); 3720 assertThat(compilation) 3721 .generatedSourceFile("foo.bar.AutoValue_Outer_Inner") 3722 .contentsAsUtf8String() 3723 .doesNotContain("ProtectedAnnotation"); 3724 } 3725 3726 @Test builderWithVarArgsDoesNotImportJavaUtilArrays()3727 public void builderWithVarArgsDoesNotImportJavaUtilArrays() { 3728 // Repro from https://github.com/google/auto/issues/373. 3729 JavaFileObject testFileObject = 3730 JavaFileObjects.forSourceLines( 3731 "foo.bar.Test", 3732 "package foo.bar;", 3733 "", 3734 "import com.google.auto.value.AutoValue;", 3735 "import com.google.common.collect.ImmutableList;", 3736 "", 3737 "@AutoValue", 3738 "public abstract class Test {", 3739 " abstract ImmutableList<String> foo();", 3740 "", 3741 " @AutoValue.Builder", 3742 " abstract static class Builder {", 3743 " abstract Builder foo(String... foos);", 3744 " abstract Test build();", 3745 " }", 3746 "}"); 3747 Compilation compilation = 3748 javac() 3749 .withProcessors(new AutoValueProcessor()) 3750 .withOptions("-Xlint:-processing", "-implicit:none") 3751 .compile(testFileObject); 3752 assertThat(compilation).succeededWithoutWarnings(); 3753 assertThat(compilation) 3754 .generatedSourceFile("foo.bar.AutoValue_Test") 3755 .contentsAsUtf8String() 3756 .doesNotContain("java.util.Arrays"); 3757 } 3758 3759 @Test staticBuilderMethodInBuilderClass()3760 public void staticBuilderMethodInBuilderClass() { 3761 JavaFileObject javaFileObject = 3762 JavaFileObjects.forSourceLines( 3763 "com.example.Foo", 3764 "package com.example;", 3765 "", 3766 "import com.google.auto.value.AutoValue;", 3767 "", 3768 "@AutoValue", 3769 "public abstract class Foo {", 3770 " public abstract String bar();", 3771 "", 3772 " @AutoValue.Builder", 3773 " public abstract static class Builder {", 3774 " public static Builder builder() {", 3775 " return new AutoValue_Foo.Builder();", 3776 " }", 3777 "", 3778 " public abstract Builder setBar(String s);", 3779 " public abstract Foo build();", 3780 " }", 3781 "}"); 3782 Compilation compilation = 3783 javac() 3784 .withProcessors(new AutoValueProcessor()) 3785 .withOptions("-Xlint:-processing", "-implicit:none") 3786 .compile(javaFileObject); 3787 assertThat(compilation).succeeded(); 3788 assertThat(compilation) 3789 .hadWarningContaining("Static builder() method should be in the containing class") 3790 .inFile(javaFileObject) 3791 .onLineContaining("builder()"); 3792 } 3793 3794 /** 3795 * Tests behaviour when the package containing an {@code @AutoValue} class also has classes with 3796 * the same name as classes in {@code java.lang}. If you call a class {@code Object} you are 3797 * asking for trouble, but you could innocently call a class {@code Compiler} without realizing 3798 * there is a {@code java.lang.Compiler}. 3799 * 3800 * <p>The case where the class in question is mentioned in the {@code @AutoValue} class is the 3801 * easy one, because then our logic can easily see that there is a clash and will use 3802 * fully-qualified names. This is the case of the {@code Compiler} class below. The case where the 3803 * class is <i>not</i> mentioned is harder. We have to realize that we can't elide the package 3804 * name in {@code java.lang.Object} because there is also a {@code foo.bar.Object} in scope, and 3805 * in fact it takes precedence. 3806 */ 3807 @Test javaLangClash()3808 public void javaLangClash() { 3809 JavaFileObject object = 3810 JavaFileObjects.forSourceLines( 3811 "foo.bar.Object", // 3812 "package foo.bar;", 3813 "", 3814 "public class Object {}"); 3815 JavaFileObject string = 3816 JavaFileObjects.forSourceLines( 3817 "foo.bar.String", // 3818 "package foo.bar;", 3819 "", 3820 "public class String {}"); 3821 JavaFileObject integer = 3822 JavaFileObjects.forSourceLines( 3823 "foo.bar.Integer", // 3824 "package foo.bar;", 3825 "", 3826 "public class Integer {}"); 3827 JavaFileObject thread = 3828 JavaFileObjects.forSourceLines( 3829 "foo.bar.Thread", // 3830 "package foo.bar;", 3831 "", 3832 "public class Thread {}"); 3833 JavaFileObject override = 3834 JavaFileObjects.forSourceLines( 3835 "foo.bar.Override", // 3836 "package foo.bar;", 3837 "", 3838 "public class Override {}"); 3839 JavaFileObject test = 3840 JavaFileObjects.forSourceLines( 3841 "foo.bar.Test", 3842 "package foo.bar;", 3843 "", 3844 "import com.google.auto.value.AutoValue;", 3845 "", 3846 "@AutoValue", 3847 "public abstract class Test {", 3848 " public abstract java.lang.Integer integer();", 3849 " public abstract java.lang.Thread.State state();", 3850 " public static Builder builder() {", 3851 " return new AutoValue_Test.Builder();", 3852 " }", 3853 "", 3854 " @AutoValue.Builder", 3855 " public abstract static class Builder {", 3856 " public abstract Builder setInteger(java.lang.Integer x);", 3857 " public abstract Builder setState(java.lang.Thread.State x);", 3858 " public abstract Test build();", 3859 " }", 3860 "}"); 3861 Compilation compilation = 3862 javac() 3863 .withProcessors(new AutoValueProcessor()) 3864 .withOptions("-Xlint:-processing", "-implicit:none") 3865 .compile(object, string, integer, thread, override, test); 3866 assertThat(compilation).succeededWithoutWarnings(); 3867 } 3868 3869 // This is a regression test for the problem described in 3870 // https://github.com/google/auto/issues/847#issuecomment-629857642. 3871 @Test generatedParentWithGeneratedGetterButSetterInBuilder()3872 public void generatedParentWithGeneratedGetterButSetterInBuilder() { 3873 JavaFileObject test = 3874 JavaFileObjects.forSourceLines( 3875 "foo.bar.Test", 3876 "package foo.bar;", 3877 "", 3878 "import com.google.auto.value.AutoValue;", 3879 "import foo.baz.GeneratedParent;", 3880 "import foo.baz.GeneratedPropertyType;", 3881 "import java.util.Optional;", 3882 "", 3883 "@AutoValue", 3884 "public abstract class Test extends GeneratedParent {", 3885 " public abstract String string();", 3886 "", 3887 " public static Builder builder() {", 3888 " return new AutoValue_Test.Builder();", 3889 " }", 3890 "", 3891 " @AutoValue.Builder", 3892 " public abstract static class Builder extends GeneratedParent.Builder<Builder> {", 3893 " public abstract Builder setString(String x);", 3894 " public abstract Builder setGenerated(GeneratedPropertyType x);", 3895 " public abstract Test build();", 3896 " }", 3897 "}"); 3898 AutoValueProcessor autoValueProcessor = new AutoValueProcessor(); 3899 GeneratedParentProcessor generatedParentProcessor = 3900 new GeneratedParentProcessor(autoValueProcessor, expect); 3901 Compilation compilation = 3902 javac() 3903 .withProcessors(autoValueProcessor, generatedParentProcessor) 3904 .withOptions("-Xlint:-processing", "-implicit:none") 3905 .compile(test); 3906 assertThat(compilation).succeededWithoutWarnings(); 3907 assertThat(compilation) 3908 .generatedSourceFile("foo.bar.AutoValue_Test") 3909 .contentsAsUtf8String() 3910 .contains(" public int integer() {"); 3911 } 3912 3913 @SupportedAnnotationTypes("*") 3914 private static class GeneratedParentProcessor extends AbstractProcessor { 3915 private static final String GENERATED_PARENT = 3916 String.join( 3917 "\n", 3918 "package foo.baz;", 3919 "", 3920 "public abstract class GeneratedParent {", 3921 " public abstract int integer();", 3922 " public abstract GeneratedPropertyType generated();", 3923 "", 3924 " public abstract static class Builder<B extends Builder<B>> {", 3925 " public abstract B setInteger(int x);", 3926 " }", 3927 "}"); 3928 private static final String GENERATED_PROPERTY_TYPE = 3929 String.join( 3930 "\n", // 3931 "package foo.baz;", 3932 "", 3933 "public class GeneratedPropertyType {}"); 3934 private static final ImmutableMap<String, String> GENERATED_TYPES = 3935 ImmutableMap.of( 3936 "foo.baz.GeneratedParent", GENERATED_PARENT, 3937 "foo.baz.GeneratedPropertyType", GENERATED_PROPERTY_TYPE); 3938 3939 private final AutoValueProcessor autoValueProcessor; 3940 private final Expect expect; 3941 GeneratedParentProcessor(AutoValueProcessor autoValueProcessor, Expect expect)3942 GeneratedParentProcessor(AutoValueProcessor autoValueProcessor, Expect expect) { 3943 this.autoValueProcessor = autoValueProcessor; 3944 this.expect = expect; 3945 } 3946 3947 private boolean generated; 3948 3949 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)3950 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 3951 if (!generated) { 3952 generated = true; 3953 // Check that AutoValueProcessor has already run and deferred the foo.bar.Test type because 3954 // we haven't generated its parent yet. 3955 expect.that(autoValueProcessor.deferredTypeNames()).contains("foo.bar.Test"); 3956 GENERATED_TYPES.forEach( 3957 (typeName, source) -> { 3958 try { 3959 JavaFileObject generated = processingEnv.getFiler().createSourceFile(typeName); 3960 try (Writer writer = generated.openWriter()) { 3961 writer.write(source); 3962 } 3963 } catch (IOException e) { 3964 throw new UncheckedIOException(e); 3965 } 3966 }); 3967 } 3968 return false; 3969 } 3970 3971 @Override getSupportedSourceVersion()3972 public SourceVersion getSupportedSourceVersion() { 3973 return SourceVersion.latestSupported(); 3974 } 3975 } 3976 3977 // This is a regression test for the problem described in 3978 // https://github.com/google/auto/issues/1087. 3979 @Test kotlinMetadataAnnotationsAreImplicitlyExcludedFromCopying()3980 public void kotlinMetadataAnnotationsAreImplicitlyExcludedFromCopying() { 3981 JavaFileObject metadata = 3982 JavaFileObjects.forSourceLines( 3983 "kotlin.Metadata", "package kotlin;", "", "public @interface Metadata {", "}"); 3984 JavaFileObject test = 3985 JavaFileObjects.forSourceLines( 3986 "foo.bar.Test", 3987 "package foo.bar;", 3988 "", 3989 "import com.google.auto.value.AutoValue;", 3990 "import kotlin.Metadata;", 3991 "", 3992 "@AutoValue.CopyAnnotations", 3993 "@Metadata", 3994 "@AutoValue", 3995 "public abstract class Test {", 3996 " public abstract String string();", 3997 "}"); 3998 AutoValueProcessor autoValueProcessor = new AutoValueProcessor(); 3999 Compilation compilation = 4000 javac() 4001 .withProcessors(autoValueProcessor) 4002 .withOptions("-Xlint:-processing", "-implicit:none") 4003 .compile(test, metadata); 4004 assertThat(compilation).succeededWithoutWarnings(); 4005 assertThat(compilation) 4006 .generatedSourceFile("foo.bar.AutoValue_Test") 4007 .contentsAsUtf8String() 4008 .doesNotContain("kotlin.Metadata"); 4009 } 4010 sorted(String... imports)4011 private static String sorted(String... imports) { 4012 return stream(imports).sorted().collect(joining("\n")); 4013 } 4014 } 4015