001    /*
002     * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.comp;
027    
028    import com.sun.tools.javac.util.*;
029    import com.sun.tools.javac.code.*;
030    import com.sun.tools.javac.code.Symbol.*;
031    import com.sun.tools.javac.tree.*;
032    import com.sun.tools.javac.tree.JCTree.*;
033    
034    /** Enter annotations on symbols.  Annotations accumulate in a queue,
035     *  which is processed at the top level of any set of recursive calls
036     *  requesting it be processed.
037     *
038     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
039     *  you write code that depends on this, you do so at your own risk.
040     *  This code and its internal interfaces are subject to change or
041     *  deletion without notice.</b>
042     */
043    public class Annotate {
044        protected static final Context.Key<Annotate> annotateKey =
045            new Context.Key<Annotate>();
046    
047        public static Annotate instance(Context context) {
048            Annotate instance = context.get(annotateKey);
049            if (instance == null)
050                instance = new Annotate(context);
051            return instance;
052        }
053    
054        final Attr attr;
055        final TreeMaker make;
056        final Log log;
057        final Symtab syms;
058        final Names names;
059        final Resolve rs;
060        final Types types;
061        final ConstFold cfolder;
062        final Check chk;
063    
064        protected Annotate(Context context) {
065            context.put(annotateKey, this);
066            attr = Attr.instance(context);
067            make = TreeMaker.instance(context);
068            log = Log.instance(context);
069            syms = Symtab.instance(context);
070            names = Names.instance(context);
071            rs = Resolve.instance(context);
072            types = Types.instance(context);
073            cfolder = ConstFold.instance(context);
074            chk = Check.instance(context);
075        }
076    
077    /* ********************************************************************
078     * Queue maintenance
079     *********************************************************************/
080    
081        private int enterCount = 0;
082    
083        ListBuffer<Annotator> q = new ListBuffer<Annotator>();
084    
085        public void later(Annotator a) {
086            q.append(a);
087        }
088    
089        public void earlier(Annotator a) {
090            q.prepend(a);
091        }
092    
093        /** Called when the Enter phase starts. */
094        public void enterStart() {
095            enterCount++;
096        }
097    
098        /** Called after the Enter phase completes. */
099        public void enterDone() {
100            enterCount--;
101            flush();
102        }
103    
104        public void flush() {
105            if (enterCount != 0) return;
106            enterCount++;
107            try {
108                while (q.nonEmpty())
109                    q.next().enterAnnotation();
110            } finally {
111                enterCount--;
112            }
113        }
114    
115        /** A client that has annotations to add registers an annotator,
116         *  the method it will use to add the annotation.  There are no
117         *  parameters; any needed data should be captured by the
118         *  Annotator.
119         */
120        public interface Annotator {
121            void enterAnnotation();
122            String toString();
123        }
124    
125    
126    /* ********************************************************************
127     * Compute an attribute from its annotation.
128     *********************************************************************/
129    
130        /** Process a single compound annotation, returning its
131         *  Attribute. Used from MemberEnter for attaching the attributes
132         *  to the annotated symbol.
133         */
134        Attribute.Compound enterAnnotation(JCAnnotation a,
135                                           Type expected,
136                                           Env<AttrContext> env) {
137            // The annotation might have had its type attributed (but not checked)
138            // by attr.attribAnnotationTypes during MemberEnter, in which case we do not
139            // need to do it again.
140            Type at = (a.annotationType.type != null ? a.annotationType.type
141                      : attr.attribType(a.annotationType, env));
142            a.type = chk.checkType(a.annotationType.pos(), at, expected);
143            if (a.type.isErroneous())
144                return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
145            if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
146                log.error(a.annotationType.pos(),
147                          "not.annotation.type", a.type.toString());
148                return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
149            }
150            List<JCExpression> args = a.args;
151            if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) {
152                // special case: elided "value=" assumed
153                args.head = make.at(args.head.pos).
154                    Assign(make.Ident(names.value), args.head);
155            }
156            ListBuffer<Pair<MethodSymbol,Attribute>> buf =
157                new ListBuffer<Pair<MethodSymbol,Attribute>>();
158            for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
159                JCExpression t = tl.head;
160                if (t.getTag() != JCTree.ASSIGN) {
161                    log.error(t.pos(), "annotation.value.must.be.name.value");
162                    continue;
163                }
164                JCAssign assign = (JCAssign)t;
165                if (assign.lhs.getTag() != JCTree.IDENT) {
166                    log.error(t.pos(), "annotation.value.must.be.name.value");
167                    continue;
168                }
169                JCIdent left = (JCIdent)assign.lhs;
170                Symbol method = rs.resolveQualifiedMethod(left.pos(),
171                                                          env,
172                                                          a.type,
173                                                          left.name,
174                                                          List.<Type>nil(),
175                                                          null);
176                left.sym = method;
177                left.type = method.type;
178                if (method.owner != a.type.tsym)
179                    log.error(left.pos(), "no.annotation.member", left.name, a.type);
180                Type result = method.type.getReturnType();
181                Attribute value = enterAttributeValue(result, assign.rhs, env);
182                if (!method.type.isErroneous())
183                    buf.append(new Pair<MethodSymbol,Attribute>
184                               ((MethodSymbol)method, value));
185            }
186            return new Attribute.Compound(a.type, buf.toList());
187        }
188    
189        Attribute enterAttributeValue(Type expected,
190                                      JCExpression tree,
191                                      Env<AttrContext> env) {
192            if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
193                Type result = attr.attribExpr(tree, env, expected);
194                if (result.isErroneous())
195                    return new Attribute.Error(expected);
196                if (result.constValue() == null) {
197                    log.error(tree.pos(), "attribute.value.must.be.constant");
198                    return new Attribute.Error(expected);
199                }
200                result = cfolder.coerce(result, expected);
201                return new Attribute.Constant(expected, result.constValue());
202            }
203            if (expected.tsym == syms.classType.tsym) {
204                Type result = attr.attribExpr(tree, env, expected);
205                if (result.isErroneous())
206                    return new Attribute.Error(expected);
207                if (TreeInfo.name(tree) != names._class) {
208                    log.error(tree.pos(), "annotation.value.must.be.class.literal");
209                    return new Attribute.Error(expected);
210                }
211                return new Attribute.Class(types,
212                                           (((JCFieldAccess) tree).selected).type);
213            }
214            if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
215                if (tree.getTag() != JCTree.ANNOTATION) {
216                    log.error(tree.pos(), "annotation.value.must.be.annotation");
217                    expected = syms.errorType;
218                }
219                return enterAnnotation((JCAnnotation)tree, expected, env);
220            }
221            if (expected.tag == TypeTags.ARRAY) { // should really be isArray()
222                if (tree.getTag() != JCTree.NEWARRAY) {
223                    tree = make.at(tree.pos).
224                        NewArray(null, List.<JCExpression>nil(), List.of(tree));
225                }
226                JCNewArray na = (JCNewArray)tree;
227                if (na.elemtype != null) {
228                    log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
229                    return new Attribute.Error(expected);
230                }
231                ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
232                for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
233                    buf.append(enterAttributeValue(types.elemtype(expected),
234                                                   l.head,
235                                                   env));
236                }
237                return new Attribute.
238                    Array(expected, buf.toArray(new Attribute[buf.length()]));
239            }
240            if (expected.tag == TypeTags.CLASS &&
241                (expected.tsym.flags() & Flags.ENUM) != 0) {
242                attr.attribExpr(tree, env, expected);
243                Symbol sym = TreeInfo.symbol(tree);
244                if (sym == null ||
245                    TreeInfo.nonstaticSelect(tree) ||
246                    sym.kind != Kinds.VAR ||
247                    (sym.flags() & Flags.ENUM) == 0) {
248                    log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
249                    return new Attribute.Error(expected);
250                }
251                VarSymbol enumerator = (VarSymbol) sym;
252                return new Attribute.Enum(expected, enumerator);
253            }
254            if (!expected.isErroneous())
255                log.error(tree.pos(), "annotation.value.not.allowable.type");
256            return new Attribute.Error(attr.attribExpr(tree, env, expected));
257        }
258    }