changeset 56927:e458917a1c54 records-and-sealed

pushing down declaration annotations on records, initial support
author vromero
date Fri, 12 Jul 2019 14:47:44 -0400
parents 7c3537750620
children 7559b9413ba7 b2747f122ad9
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java test/langtools/tools/javac/records/annotations/BadAnnotations.java test/langtools/tools/javac/records/annotations/BadAnnotations.out
diffstat 10 files changed, 194 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Jul 12 14:47:44 2019 -0400
@@ -1646,8 +1646,6 @@
                     return ElementKind.PARAMETER;
             } else if ((flags & ENUM) != 0) {
                 return ElementKind.ENUM_CONSTANT;
-            } else if ((flags & RECORD) != 0) {
-                return ElementKind.STATE_COMPONENT;
             } else if (owner.kind == TYP || owner.kind == ERR) {
                 return ElementKind.FIELD;
             } else if (isResourceVariable()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java	Fri Jul 12 14:47:44 2019 -0400
@@ -255,4 +255,36 @@
     private boolean isStarted() {
         return attributes != DECL_NOT_STARTED;
     }
+
+    private List<Attribute.Compound> removeFromCompoundList(List<Attribute.Compound> l, Attribute.Compound compound) {
+        ListBuffer<Attribute.Compound> lb = new ListBuffer<>();
+        for (Attribute.Compound c : l) {
+            if (c != compound) {
+                lb.add(c);
+            }
+        }
+        return lb.toList();
+    }
+
+    private List<Attribute.TypeCompound> removeFromTypeCompoundList(List<Attribute.TypeCompound> l, Attribute.TypeCompound compound) {
+        ListBuffer<Attribute.TypeCompound> lb = new ListBuffer<>();
+        for (Attribute.TypeCompound c : l) {
+            if (c != compound) {
+                lb.add(c);
+            }
+        }
+        return lb.toList();
+    }
+
+    public void remove(Attribute.Compound compound) {
+        if (attributes.contains(compound)) {
+            attributes = removeFromCompoundList(attributes, compound);
+        } else if (type_attributes.contains(compound)) {
+            type_attributes = removeFromTypeCompoundList(type_attributes, (TypeCompound)compound);
+        } else if (init_type_attributes.contains(compound)) {
+            init_type_attributes = removeFromTypeCompoundList(init_type_attributes, (TypeCompound)compound);
+        } else if (clinit_type_attributes.contains(compound)) {
+            clinit_type_attributes = removeFromTypeCompoundList(clinit_type_attributes, (TypeCompound)compound);
+        }
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Fri Jul 12 14:47:44 2019 -0400
@@ -1266,7 +1266,7 @@
                 // No type annotations can occur here.
             } else {
                 // There is nothing else in a variable declaration that needs separation.
-                Assert.error("Unhandled variable kind");
+                Assert.error("Unhandled variable kind: " + tree.sym.getKind());
             }
 
             scan(tree.mods);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Fri Jul 12 14:47:44 2019 -0400
@@ -276,7 +276,7 @@
         validate(() -> { //validate annotations
             JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
             try {
-                chk.validateAnnotations(annotations, s);
+                chk.validateAnnotations(annotations, TreeInfo.declarationFor(s, localEnv.tree), s);
             } finally {
                 log.useSource(prev);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jul 12 14:47:44 2019 -0400
@@ -2839,9 +2839,9 @@
 
     /** Check the annotations of a symbol.
      */
-    public void validateAnnotations(List<JCAnnotation> annotations, Symbol s) {
+    public void validateAnnotations(List<JCAnnotation> annotations, JCTree declarationTree, Symbol s) {
         for (JCAnnotation a : annotations)
-            validateAnnotation(a, s);
+            validateAnnotation(a, declarationTree, s);
     }
 
     /** Check the type annotations.
@@ -2853,11 +2853,48 @@
 
     /** Check an annotation of a symbol.
      */
-    private void validateAnnotation(JCAnnotation a, Symbol s) {
+    private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) {
         validateAnnotationTree(a);
 
-        if (a.type.tsym.isAnnotationType() && !annotationApplicable(a, s))
-            log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
+        if (s.isRecord() && s.flags_field == (Flags.PRIVATE | Flags.FINAL | Flags.MANDATED | Flags.RECORD) && declarationTree.hasTag(VARDEF)) {
+            // we are seeing a record field, which had the original annotations, now is the moment,
+            // before stripping some of them just below, to check if the original annotations
+            // applied to records at all, first version only cares about declaration annotations
+            // we will add type annotations later on
+            Name[] targets = getTargetNames(a, s);
+            boolean appliesToRecords = false;
+            for (Name target : targets) {
+                appliesToRecords = target == names.FIELD || target == names.PARAMETER || target == names.METHOD;
+                if (appliesToRecords) {
+                    break;
+                }
+            }
+            if (!appliesToRecords) {
+                log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
+            }
+        }
+
+        if (a.type.tsym.isAnnotationType() && !annotationApplicable(a, s)) {
+            // debug
+            //System.out.println("at Check.validateAnnotation: flags: " + Flags.toString(s.flags_field) + ", declaration tree " + declarationTree);
+            if (s.isRecord() || s.owner.isRecord() && (s.flags_field & Flags.MANDATED) != 0) {
+                JCModifiers modifiers = TreeInfo.getModifiers(declarationTree);
+                // lets first remove the annotation from the modifier
+                if (modifiers != null) {
+                    ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<>();
+                    for (JCAnnotation anno : modifiers.annotations) {
+                        if (anno != a) {
+                            newAnnotations.add(anno);
+                        }
+                    }
+                    modifiers.annotations = newAnnotations.toList();
+                }
+                // now lets remove it from the symbol
+                s.getMetadata().remove(a.attribute);
+            } else {
+                log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
+            }
+        }
 
         if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) {
             if (s.kind != TYP) {
@@ -3107,10 +3144,9 @@
         }
 
     /** Is the annotation applicable to the symbol? */
-    boolean annotationApplicable(JCAnnotation a, Symbol s) {
+    Name[] getTargetNames(JCAnnotation a, Symbol s) {
         Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
         Name[] targets;
-
         if (arr == null) {
             targets = defaultTargetMetaInfo(a, s);
         } else {
@@ -3119,12 +3155,21 @@
             for (int i=0; i<arr.values.length; ++i) {
                 Attribute app = arr.values[i];
                 if (!(app instanceof Attribute.Enum)) {
-                    return true; // recovery
+                    return new Name[0];
                 }
                 Attribute.Enum e = (Attribute.Enum) app;
                 targets[i] = e.value.name;
             }
         }
+        return targets;
+    }
+
+    boolean annotationApplicable(JCAnnotation a, Symbol s) {
+        Name[] targets = getTargetNames(a, s);
+        if (targets.length == 0) {
+            // recovery
+            return true;
+        }
         for (Name target : targets) {
             if (target == names.TYPE) {
                 if (s.kind == TYP)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Jul 12 14:47:44 2019 -0400
@@ -28,7 +28,9 @@
 import java.util.HashSet;
 import java.util.Set;
 import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 
+import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.code.*;
@@ -949,7 +951,7 @@
                         }
                     }
                 } else if ((sym.flags() & RECORD) != 0) {
-                    helper = new RecordConstructorHelper(sym, TreeInfo.recordFields(tree).map(vd -> vd.sym));
+                    helper = new RecordConstructorHelper(sym, TreeInfo.recordFields(tree));
                 }
                 if (helper != null) {
                     JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
@@ -965,9 +967,7 @@
                                     TreeInfo.getConstructorInvocationName(((JCMethodDecl)def).body.stats, names, true);
                             if (constructorInvocationName == names.empty ||
                                     constructorInvocationName == names._super) {
-                                RecordConstructorHelper helper = new RecordConstructorHelper(
-                                        sym,
-                                        TreeInfo.recordFields(tree).map(vd -> vd.sym));
+                                RecordConstructorHelper helper = new RecordConstructorHelper(sym, TreeInfo.recordFields(tree));
                                 JCMethodDecl methDecl = (JCMethodDecl)def;
                                 if (constructorInvocationName == names.empty) {
                                     JCStatement supCall = make.at(methDecl.body.pos).Exec(make.Apply(List.nil(),
@@ -1052,14 +1052,14 @@
                 (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) {
                 addEnumMembers(tree, env);
             }
-            List<JCTree> defsToEnter = (tree.sym.flags_field & RECORD) != 0 ?
+            boolean isRecord = (tree.sym.flags_field & RECORD) != 0;
+            List<JCTree> defsToEnter = isRecord ?
                     tree.defs.diff(List.convert(JCTree.class, TreeInfo.recordFields(tree))) : tree.defs;
             memberEnter.memberEnter(defsToEnter, env);
-            if ((tree.mods.flags & RECORD) != 0) {
-                if ((tree.mods.flags & (RECORD | ABSTRACT)) == RECORD) {
-                    addRecordMembersIfNeeded(tree, env, defaultConstructorGenerated);
-                }
+            if (isRecord) {
+                addRecordMembersIfNeeded(tree, env, defaultConstructorGenerated);
                 addAccessorsIfNeeded(tree, env);
+                //List<JCVariableDecl> recordFields = TreeInfo.recordFields(tree);
             }
 
             if (tree.sym.isAnnotationType()) {
@@ -1130,7 +1130,7 @@
                 Type accessorType = accessor.fst.accessorType(syms, tree.sym.type);
                 MethodSymbol implSym = lookupMethod(env.enclClass.sym, accessor.snd, accessorType.getParameterTypes());
                 if (implSym == null || (implSym.flags_field & MANDATED) != 0) {
-                    JCMethodDecl getter = make.at(tree.pos).MethodDef(make.Modifiers(Flags.PUBLIC | Flags.MANDATED),
+                    JCMethodDecl getter = make.at(tree.pos).MethodDef(make.Modifiers(Flags.PUBLIC | Flags.MANDATED, tree.mods.annotations),
                               accessor.snd,
                               make.Type(accessorType.getReturnType()),
                               List.nil(),
@@ -1213,7 +1213,7 @@
                         null :
                         canonicalDecl.sym;
                 if (canonicalInit == null) {
-                    RecordConstructorHelper helper = new RecordConstructorHelper(tree.sym, TreeInfo.recordFields(tree).map(vd -> vd.sym));
+                    RecordConstructorHelper helper = new RecordConstructorHelper(tree.sym, TreeInfo.recordFields(tree));
                     JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
                     tree.defs = tree.defs.prepend(constrDef);
                     defaultConstructorGenerated = true;
@@ -1314,6 +1314,7 @@
        TypeSymbol owner();
        List<Name> superArgs();
        List<Name> inits();
+       default JCMethodDecl finalAdjustment(JCMethodDecl md) { return md; }
     }
 
     class BasicConstructorHelper implements DefaultConstructorHelper {
@@ -1435,17 +1436,19 @@
 
     class RecordConstructorHelper extends BasicConstructorHelper {
 
-        List<VarSymbol> recordFields;
+        List<VarSymbol> recordFieldSymbols;
+        List<JCVariableDecl> recordFieldDecls;
 
-        RecordConstructorHelper(TypeSymbol owner, List<VarSymbol> recordFields) {
+        RecordConstructorHelper(TypeSymbol owner, List<JCVariableDecl> recordFieldDecls) {
             super(owner);
-            this.recordFields = recordFields;
+            this.recordFieldDecls = recordFieldDecls;
+            this.recordFieldSymbols = recordFieldDecls.map(vd -> vd.sym);
         }
 
         @Override
         public Type constructorType() {
             if (constructorType == null) {
-                List<Type> argtypes = recordFields.map(v -> v.type);
+                List<Type> argtypes = recordFieldSymbols.map(v -> v.type);
                 constructorType = new MethodType(argtypes, syms.voidType, List.nil(), syms.methodClass);
             }
             return constructorType;
@@ -1455,8 +1458,8 @@
         public MethodSymbol constructorSymbol() {
             MethodSymbol csym = super.constructorSymbol();
             ListBuffer<VarSymbol> params = new ListBuffer<>();
-            for (VarSymbol p : recordFields) {
-                params.add(new VarSymbol(MANDATED | PARAMETER, p.name, p.type, csym));
+            for (VarSymbol p : recordFieldSymbols) {
+                params.add(new VarSymbol(MANDATED | PARAMETER | RECORD, p.name, p.type, csym));
             }
             csym.params = params.toList();
             csym.flags_field |= RECORD | PUBLIC;
@@ -1465,7 +1468,17 @@
 
         @Override
         public List<Name> inits() {
-            return recordFields.map(v -> v.name);
+            return recordFieldSymbols.map(v -> v.name);
+        }
+
+        @Override
+        public JCMethodDecl finalAdjustment(JCMethodDecl md) {
+            List<JCVariableDecl> tmpRecordFieldDecls = recordFieldDecls;
+            for (JCVariableDecl arg : md.params) {
+                arg.mods.annotations = tmpRecordFieldDecls.head.mods.annotations;
+                tmpRecordFieldDecls = tmpRecordFieldDecls.tail;
+            }
+            return md;
         }
     }
 
@@ -1488,8 +1501,8 @@
         helper.inits().forEach((initName) -> {
             stats.add(make.Exec(make.Assign(make.Select(make.Ident(names._this), initName), make.Ident(initName))));
         });
-        JCTree result = make.MethodDef(initSym, make.Block(0, stats.toList()));
-        return result;
+        JCMethodDecl result = make.MethodDef(initSym, make.Block(0, stats.toList()));
+        return helper.finalAdjustment(result);
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jul 12 14:47:44 2019 -0400
@@ -3824,7 +3824,7 @@
         if (mods.flags != 0) {
             log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers);
         }
-        mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE;
+        mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE | Flags.MANDATED;
         JCExpression type = parseType();
         int pos = token.pos;
         Name id = ident();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Jul 09 20:37:08 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Jul 12 14:47:44 2019 -0400
@@ -922,6 +922,24 @@
         }
     }
 
+    /** If this tree has a modifiers field, return it otherwise return null
+     */
+    public static JCModifiers getModifiers(JCTree tree) {
+        tree = skipParens(tree);
+        switch (tree.getTag()) {
+            case VARDEF:
+                return ((JCVariableDecl) tree).mods;
+            case METHODDEF:
+                return ((JCMethodDecl) tree).mods;
+            case CLASSDEF:
+                return ((JCClassDecl) tree).mods;
+            case MODULEDEF:
+                return ((JCModuleDecl) tree).mods;
+            default:
+                return null;
+        }
+    }
+
     /** Return true if this is a nonstatic selection. */
     public static boolean nonstaticSelect(JCTree tree) {
         tree = skipParens(tree);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/records/annotations/BadAnnotations.java	Fri Jul 12 14:47:44 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary bad declaration annotations on records
+ * @compile/fail/ref=BadAnnotations.out -XDrawDiagnostics BadAnnotations.java
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+class BadAnnotations {
+    @Target({ ElementType.CONSTRUCTOR })
+    @interface Foo1 {}
+    record R1(@Foo1 int i) {}
+
+    @Target({ ElementType.TYPE })
+    @interface Foo2 {}
+    record R2(@Foo2 int i) {}
+
+    @Target({ ElementType.LOCAL_VARIABLE })
+    @interface Foo3 {}
+    record R3(@Foo3 int i) {}
+
+    @Target({ ElementType.PACKAGE })
+    @interface Foo4 {}
+    record R4(@Foo4 int i) {}
+
+    @Target({ ElementType.MODULE })
+    @interface Foo5 {}
+    record R5(@Foo5 int i) {}
+
+    // positive cases
+    @Target({ ElementType.FIELD })
+    @interface Foo6 {}
+    record R6(@Foo6 int i) {}
+
+    @Target({ ElementType.METHOD })
+    @interface Foo7 {}
+    record R7(@Foo7 int i) {}
+
+    @Target({ ElementType.PARAMETER })
+    @interface Foo8 {}
+    record R8(@Foo8 int i) {}
+
+    // no target applies to all
+    @interface Foo9 {}
+    record R9(@Foo9 int i) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/records/annotations/BadAnnotations.out	Fri Jul 12 14:47:44 2019 -0400
@@ -0,0 +1,6 @@
+BadAnnotations.java:15:15: compiler.err.annotation.type.not.applicable
+BadAnnotations.java:19:15: compiler.err.annotation.type.not.applicable
+BadAnnotations.java:23:15: compiler.err.annotation.type.not.applicable
+BadAnnotations.java:27:15: compiler.err.annotation.type.not.applicable
+BadAnnotations.java:31:15: compiler.err.annotation.type.not.applicable
+5 errors