src/share/classes/com/sun/tools/javac/comp/Annotate.java

Fri, 02 Mar 2012 12:57:47 +0000

author
mcimadamore
date
Fri, 02 Mar 2012 12:57:47 +0000
changeset 1216
6aafebe9a394
parent 1127
ca49d50318dc
child 1313
873ddd9f4900
permissions
-rw-r--r--

7148242: Regression: valid code rejected during generic type well-formedness check
Summary: Redundant type-var substitution makes generic-type well-formedness check to fail
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2003, 2011, 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.comp;
    28 import com.sun.tools.javac.util.*;
    29 import com.sun.tools.javac.code.*;
    30 import com.sun.tools.javac.code.Symbol.*;
    31 import com.sun.tools.javac.tree.*;
    32 import com.sun.tools.javac.tree.JCTree.*;
    34 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    36 /** Enter annotations on symbols.  Annotations accumulate in a queue,
    37  *  which is processed at the top level of any set of recursive calls
    38  *  requesting it be processed.
    39  *
    40  *  <p><b>This is NOT part of any supported API.
    41  *  If you write code that depends on this, you do so at your own risk.
    42  *  This code and its internal interfaces are subject to change or
    43  *  deletion without notice.</b>
    44  */
    45 public class Annotate {
    46     protected static final Context.Key<Annotate> annotateKey =
    47         new Context.Key<Annotate>();
    49     public static Annotate instance(Context context) {
    50         Annotate instance = context.get(annotateKey);
    51         if (instance == null)
    52             instance = new Annotate(context);
    53         return instance;
    54     }
    56     final Attr attr;
    57     final TreeMaker make;
    58     final Log log;
    59     final Symtab syms;
    60     final Names names;
    61     final Resolve rs;
    62     final Types types;
    63     final ConstFold cfolder;
    64     final Check chk;
    66     protected Annotate(Context context) {
    67         context.put(annotateKey, this);
    68         attr = Attr.instance(context);
    69         make = TreeMaker.instance(context);
    70         log = Log.instance(context);
    71         syms = Symtab.instance(context);
    72         names = Names.instance(context);
    73         rs = Resolve.instance(context);
    74         types = Types.instance(context);
    75         cfolder = ConstFold.instance(context);
    76         chk = Check.instance(context);
    77     }
    79 /* ********************************************************************
    80  * Queue maintenance
    81  *********************************************************************/
    83     private int enterCount = 0;
    85     ListBuffer<Annotator> q = new ListBuffer<Annotator>();
    87     public void later(Annotator a) {
    88         q.append(a);
    89     }
    91     public void earlier(Annotator a) {
    92         q.prepend(a);
    93     }
    95     /** Called when the Enter phase starts. */
    96     public void enterStart() {
    97         enterCount++;
    98     }
   100     /** Called after the Enter phase completes. */
   101     public void enterDone() {
   102         enterCount--;
   103         flush();
   104     }
   106     public void flush() {
   107         if (enterCount != 0) return;
   108         enterCount++;
   109         try {
   110             while (q.nonEmpty())
   111                 q.next().enterAnnotation();
   112         } finally {
   113             enterCount--;
   114         }
   115     }
   117     /** A client that has annotations to add registers an annotator,
   118      *  the method it will use to add the annotation.  There are no
   119      *  parameters; any needed data should be captured by the
   120      *  Annotator.
   121      */
   122     public interface Annotator {
   123         void enterAnnotation();
   124         String toString();
   125     }
   128 /* ********************************************************************
   129  * Compute an attribute from its annotation.
   130  *********************************************************************/
   132     /** Process a single compound annotation, returning its
   133      *  Attribute. Used from MemberEnter for attaching the attributes
   134      *  to the annotated symbol.
   135      */
   136     Attribute.Compound enterAnnotation(JCAnnotation a,
   137                                        Type expected,
   138                                        Env<AttrContext> env) {
   139         // The annotation might have had its type attributed (but not checked)
   140         // by attr.attribAnnotationTypes during MemberEnter, in which case we do not
   141         // need to do it again.
   142         Type at = (a.annotationType.type != null ? a.annotationType.type
   143                   : attr.attribType(a.annotationType, env));
   144         a.type = chk.checkType(a.annotationType.pos(), at, expected);
   145         if (a.type.isErroneous())
   146             return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
   147         if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
   148             log.error(a.annotationType.pos(),
   149                       "not.annotation.type", a.type.toString());
   150             return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
   151         }
   152         List<JCExpression> args = a.args;
   153         if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
   154             // special case: elided "value=" assumed
   155             args.head = make.at(args.head.pos).
   156                 Assign(make.Ident(names.value), args.head);
   157         }
   158         ListBuffer<Pair<MethodSymbol,Attribute>> buf =
   159             new ListBuffer<Pair<MethodSymbol,Attribute>>();
   160         for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
   161             JCExpression t = tl.head;
   162             if (!t.hasTag(ASSIGN)) {
   163                 log.error(t.pos(), "annotation.value.must.be.name.value");
   164                 continue;
   165             }
   166             JCAssign assign = (JCAssign)t;
   167             if (!assign.lhs.hasTag(IDENT)) {
   168                 log.error(t.pos(), "annotation.value.must.be.name.value");
   169                 continue;
   170             }
   171             JCIdent left = (JCIdent)assign.lhs;
   172             Symbol method = rs.resolveQualifiedMethod(left.pos(),
   173                                                           env,
   174                                                           a.type,
   175                                                           left.name,
   176                                                           List.<Type>nil(),
   177                                                           null);
   178             left.sym = method;
   179             left.type = method.type;
   180             if (method.owner != a.type.tsym)
   181                 log.error(left.pos(), "no.annotation.member", left.name, a.type);
   182             Type result = method.type.getReturnType();
   183             Attribute value = enterAttributeValue(result, assign.rhs, env);
   184             if (!method.type.isErroneous())
   185                 buf.append(new Pair<MethodSymbol,Attribute>
   186                            ((MethodSymbol)method, value));
   187             t.type = result;
   188         }
   189         return new Attribute.Compound(a.type, buf.toList());
   190     }
   192     Attribute enterAttributeValue(Type expected,
   193                                   JCExpression tree,
   194                                   Env<AttrContext> env) {
   195         //first, try completing the attribution value sym - if a completion
   196         //error is thrown, we should recover gracefully, and display an
   197         //ordinary resolution diagnostic.
   198         try {
   199             expected.tsym.complete();
   200         } catch(CompletionFailure e) {
   201             log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
   202             return new Attribute.Error(expected);
   203         }
   204         if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
   205             Type result = attr.attribExpr(tree, env, expected);
   206             if (result.isErroneous())
   207                 return new Attribute.Error(expected);
   208             if (result.constValue() == null) {
   209                 log.error(tree.pos(), "attribute.value.must.be.constant");
   210                 return new Attribute.Error(expected);
   211             }
   212             result = cfolder.coerce(result, expected);
   213             return new Attribute.Constant(expected, result.constValue());
   214         }
   215         if (expected.tsym == syms.classType.tsym) {
   216             Type result = attr.attribExpr(tree, env, expected);
   217             if (result.isErroneous())
   218                 return new Attribute.Error(expected);
   219             if (TreeInfo.name(tree) != names._class) {
   220                 log.error(tree.pos(), "annotation.value.must.be.class.literal");
   221                 return new Attribute.Error(expected);
   222             }
   223             return new Attribute.Class(types,
   224                                        (((JCFieldAccess) tree).selected).type);
   225         }
   226         if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
   227             if (!tree.hasTag(ANNOTATION)) {
   228                 log.error(tree.pos(), "annotation.value.must.be.annotation");
   229                 expected = syms.errorType;
   230             }
   231             return enterAnnotation((JCAnnotation)tree, expected, env);
   232         }
   233         if (expected.tag == TypeTags.ARRAY) { // should really be isArray()
   234             if (!tree.hasTag(NEWARRAY)) {
   235                 tree = make.at(tree.pos).
   236                     NewArray(null, List.<JCExpression>nil(), List.of(tree));
   237             }
   238             JCNewArray na = (JCNewArray)tree;
   239             if (na.elemtype != null) {
   240                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
   241                 return new Attribute.Error(expected);
   242             }
   243             ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
   244             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
   245                 buf.append(enterAttributeValue(types.elemtype(expected),
   246                                                l.head,
   247                                                env));
   248             }
   249             na.type = expected;
   250             return new Attribute.
   251                 Array(expected, buf.toArray(new Attribute[buf.length()]));
   252         }
   253         if (expected.tag == TypeTags.CLASS &&
   254             (expected.tsym.flags() & Flags.ENUM) != 0) {
   255             attr.attribExpr(tree, env, expected);
   256             Symbol sym = TreeInfo.symbol(tree);
   257             if (sym == null ||
   258                 TreeInfo.nonstaticSelect(tree) ||
   259                 sym.kind != Kinds.VAR ||
   260                 (sym.flags() & Flags.ENUM) == 0) {
   261                 log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
   262                 return new Attribute.Error(expected);
   263             }
   264             VarSymbol enumerator = (VarSymbol) sym;
   265             return new Attribute.Enum(expected, enumerator);
   266         }
   267         if (!expected.isErroneous())
   268             log.error(tree.pos(), "annotation.value.not.allowable.type");
   269         return new Attribute.Error(attr.attribExpr(tree, env, expected));
   270     }
   271 }

mercurial