1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug  8888888
  27  * @summary Test basic modeling of a record type
  28  * @library /tools/javac/lib
  29  * @modules jdk.compiler
  30  * @build   JavacTestingAbstractProcessor TestRecord
  31  * @compile -processor TestRecord -proc:only TestRecord.java
  32  */
  33 
  34 import java.io.*;
  35 import javax.annotation.processing.*;
  36 import javax.lang.model.*;
  37 import javax.lang.model.element.*;
  38 import javax.lang.model.type.*;
  39 import javax.lang.model.util.*;
  40 import java.time.*;
  41 import java.util.*;
  42 
  43 /**
  44  * Basic tests of modeling a record type.
  45  */
  46 public class TestRecord extends JavacTestingAbstractProcessor {
  47     int recordCount = 0;
  48 
  49     public boolean process(Set<? extends TypeElement> annotations,
  50                           RoundEnvironment roundEnv) {
  51        if (!roundEnv.processingOver()) {
  52            ElementScanner scanner = new RecordScanner();
  53            for(Element rootElement : roundEnv.getRootElements()) {
  54                scanner.visit(rootElement);
  55            }
  56 
  57            if (recordCount != 1)
  58                throw new RuntimeException("Bad record count " +
  59                                           recordCount);
  60        }
  61        return true;
  62     }
  63 
  64     static record PersonalBest(Duration marathonTime) implements Serializable {
  65         private static final Duration MIN_QUAL_TIME = Duration.ofHours(3);
  66         public boolean bostonQualified() {
  67             return marathonTime.compareTo(MIN_QUAL_TIME) <= 0;
  68         }
  69     }
  70 
  71     /**
  72      * Verify that a record modeled as an element behaves as expected
  73      * under 6 and latest specific visitors.
  74      */
  75     private static void testRecord(Element element, Elements elements) {
  76         ElementVisitor visitor6 = new ElementKindVisitor6<Void, Void>() {};
  77 
  78         try {
  79             visitor6.visit(element);
  80             throw new RuntimeException("Expected UnknownElementException not thrown.");
  81         } catch (UnknownElementException uee) {
  82             ; // Expected.
  83         }
  84 
  85         ElementKindVisitor visitorLatest =
  86             new ElementKindVisitor<Object, Void>() {
  87             @Override
  88             public Object visitTypeAsRecord(TypeElement e,
  89                                             Void p) {
  90                 System.out.println("printing record " + e);
  91                 List<? extends Element> enclosedElements = e.getEnclosedElements();
  92                 for (Element elem : enclosedElements) {
  93                     System.out.println("name " + elem.getSimpleName());
  94                     System.out.println("origin " + elements.getOrigin(elem));
  95                     switch (elem.getSimpleName().toString()) {
  96                         case "marathonTime": case "toString":
  97                         case "<init>": case "hashCode":
  98                         case "equals": case "readResolve":
  99                             if (elements.getOrigin(elem) != Elements.Origin.MANDATED) {
 100                                 throw new RuntimeException("MANDATED origin expected");
 101                             }
 102                             break;
 103                         default:
 104                             break;
 105                     }
 106                 }
 107                 return e; // a non-null value
 108             }
 109         };
 110 
 111         if (visitorLatest.visit(element) == null) {
 112             throw new RuntimeException("Null result of record visitation.");
 113         }
 114     }
 115 
 116     class RecordScanner extends ElementScanner<Void, Void> {
 117 
 118        public RecordScanner() {
 119            super();
 120        }
 121 
 122        @Override
 123        public Void visitType(TypeElement element, Void p) {
 124            System.out.println("Name: " + element.getSimpleName() +
 125                               "\tKind: " + element.getKind());
 126            if (element.getKind() == ElementKind.RECORD) {
 127                testRecord(element, elements);
 128                recordCount++;
 129            }
 130            return super.visitType(element, p);
 131        }
 132     }
 133 }