2323
2424/*
2525 * @test
26- * @bug 8306112
26+ * @bug 8306112 8309568
2727 * @summary Test basic processing of unnamed classes.
2828 * @library /tools/javac/lib
2929 * @modules java.compiler
3030 * jdk.compiler
3131 * @build JavacTestingAbstractProcessor TestUnnamedClass
32- * @compile -processor TestUnnamedClass -proc:only --enable-preview --release ${jdk.version} Anonymous.java
32+ * @compile -processor TestUnnamedClass --enable-preview --release ${jdk.version} Anonymous.java
33+ * @clean Nameless.java
34+ * @compile/process -processor TestUnnamedClass -proc:only --enable-preview --release ${jdk.version} -Xprefer:newer -AclassOnly Anonymous Nameless
3335 */
3436
37+ // The first @compile line processes Anonymous.java and a
38+ // Nameless.java class generated using the Filer. Both of those
39+ // unnamed classes are then compiled down to class files. The second
40+ // @compile line, as directed by -Xprefer:newer, builds and checks the
41+ // language model objects constructed from those class files, ignoring
42+ // any source files for those types.
3543
3644import java .lang .annotation .*;
3745import java .io .Writer ;
4351import static javax .lang .model .util .ElementFilter .*;
4452import javax .tools .JavaFileObject ;
4553
46- /*
47- * Ideally, this processor would test both the compile-time
48- * representation of an unnamed class starting from a source file as
49- * well as the representation starting from a class file. Currently,
50- * only the source file based view will be tested.
51- *
52- * For future work to test the class file based view, an additional jtreg directive like the following could
53- * be used:
54- *
55- * @compile/process -processor TestUnnamedClass -proc:only Anonymous Nameless
54+ /**
55+ * Test annotation processing representation of unnamed classes
56+ * constructed from either a source file or a class file.
5657 */
5758@ SuppressWarnings ("preview" )
59+ @ SupportedOptions ("classOnly" )
5860public class TestUnnamedClass extends JavacTestingAbstractProcessor {
5961
6062 private static int round = 0 ;
63+ private static int checkedClassesCount = 0 ;
64+ private static boolean classOnly = false ;
6165
6266 public boolean process (Set <? extends TypeElement > annotations ,
6367 RoundEnvironment roundEnv ) {
64- if (round == 0 ) { // Check file from comamnd line
65- checkRoots ( roundEnv );
66- generateUnnamed ();
67- }
68+ if (round == 0 ) {
69+ classOnly = options . containsKey ( "classOnly" );
70+
71+ checkRoots ( roundEnv ); // Check any files from the comamnd line
6872
69- if (!roundEnv .processingOver ()) { // Test generated file(s)
70- checkRoots (roundEnv );
73+ // Don't generate any files if testing pre-existing class files
74+ if (!classOnly ) {
75+ generateUnnamed ();
76+ }
77+ } else {
78+ if (!roundEnv .processingOver ()) { // Test generated file(s)
79+ checkRoots (roundEnv );
80+ } else { // Should have checked at least one class before processing is over
81+ if (checkedClassesCount == 0 ) {
82+ messager .printError ("No unnamed classes checked." );
83+ }
84+ }
7185 }
7286
7387 round ++;
@@ -77,7 +91,6 @@ public boolean process(Set<? extends TypeElement> annotations,
7791 private void checkRoots (RoundEnvironment roundEnv ) {
7892 int checks = 0 ;
7993 for (TypeElement type : typesIn (roundEnv .getRootElements ())) {
80- System .out .println ("Checking " + type .getQualifiedName ());
8194 checks ++;
8295 checkUnnamedClassProperties (type );
8396 }
@@ -129,6 +142,11 @@ void main() {
129142 * It is a compile-time error if this class does not declare a candidate main method (12.1.4).
130143 */
131144 void checkUnnamedClassProperties (TypeElement unnamedClass ) {
145+ checkedClassesCount ++;
146+ Name expectedName = unnamedClass .getSimpleName ();
147+
148+ System .out .println ("Checking " + expectedName );
149+
132150 if (unnamedClass .getNestingKind () != NestingKind .TOP_LEVEL ) {
133151 messager .printError ("Unnamed class is not top-level." , unnamedClass );
134152 }
@@ -138,13 +156,18 @@ void checkUnnamedClassProperties(TypeElement unnamedClass) {
138156 }
139157
140158 if (unnamedClass .getSimpleName ().isEmpty ()) {
141- messager .printError ("Unnamed class does have an empty simple name." , unnamedClass );
159+ messager .printError ("Unnamed class has an empty simple name." , unnamedClass );
142160 }
143161
144162 if (!unnamedClass .getQualifiedName ().isEmpty ()) {
145163 messager .printError ("Unnamed class does _not_ have an empty qualified name." , unnamedClass );
146164 }
147165
166+ Name binaryName = elements .getBinaryName (unnamedClass );
167+ if (!expectedName .equals (binaryName )) {
168+ messager .printError ("Unnamed has unexpected binary name" + binaryName + "." , unnamedClass );
169+ }
170+
148171 if (unnamedClass .getModifiers ().contains (Modifier .ABSTRACT )) {
149172 messager .printError ("Unnamed class is abstract." , unnamedClass );
150173 }
@@ -177,9 +200,12 @@ void checkUnnamedClassProperties(TypeElement unnamedClass) {
177200 messager .printError ("Did not find exactly one constructor" , unnamedClass );
178201 }
179202
180- ExecutableElement ctor = ctors .getFirst ();
181- if (elements .getOrigin (ctor ) != Elements .Origin .MANDATED ) {
182- messager .printError ("Constructor was not marked as mandated" , ctor );
203+ if (!classOnly ) {
204+ // Mandated-ness of default constructors not preserved in class files
205+ ExecutableElement ctor = ctors .getFirst ();
206+ if (elements .getOrigin (ctor ) != Elements .Origin .MANDATED ) {
207+ messager .printError ("Constructor was not marked as mandated" , ctor );
208+ }
183209 }
184210
185211 List <ExecutableElement > methods = methodsIn (unnamedClass .getEnclosedElements ());
0 commit comments