src/share/classes/com/sun/tools/javac/code/Annotations.java

changeset 1313
873ddd9f4900
child 1357
c75be5bc5283
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Annotations.java	Fri Aug 31 10:37:46 2012 +0100
     1.3 @@ -0,0 +1,294 @@
     1.4 +/*
     1.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package com.sun.tools.javac.code;
    1.30 +
    1.31 +import java.util.Map;
    1.32 +import javax.tools.JavaFileObject;
    1.33 +
    1.34 +import com.sun.tools.javac.comp.Annotate;
    1.35 +import com.sun.tools.javac.comp.AttrContext;
    1.36 +import com.sun.tools.javac.comp.Env;
    1.37 +import com.sun.tools.javac.util.Assert;
    1.38 +import com.sun.tools.javac.util.List;
    1.39 +import com.sun.tools.javac.util.Log;
    1.40 +import com.sun.tools.javac.util.Pair;
    1.41 +
    1.42 +import static com.sun.tools.javac.code.Kinds.PCK;
    1.43 +import com.sun.tools.javac.util.*;
    1.44 +
    1.45 +/**
    1.46 + * Container for all annotations (attributes in javac) on a Symbol.
    1.47 + *
    1.48 + * This class is explicitly mutable. Its contents will change when attributes
    1.49 + * are annotated onto the Symbol. However this class depends on the facts that
    1.50 + * List (in javac) is immutable.
    1.51 + *
    1.52 + * An instance of this class can be in one of three states:
    1.53 + *
    1.54 + * NOT_STARTED indicates that the Symbol this instance belongs to have not been
    1.55 + * annotated (yet). Specifically if the declaration is not annotated this
    1.56 + * instance will never move past NOT_STARTED. You can never go back to
    1.57 + * NOT_STARTED.
    1.58 + *
    1.59 + * IN_PROGRESS annotations have been found on the declaration. Will be processed
    1.60 + * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list
    1.61 + * of attributes (and this moves out of the IN_PROGRESS state).
    1.62 + *
    1.63 + * "unnamed" this Annotations contains some attributes, possibly the final set.
    1.64 + * While in this state you can only prepend or append to the attributes not set
    1.65 + * it directly. You can also move back to the IN_PROGRESS sate using reset().
    1.66 + *
    1.67 + * <p><b>This is NOT part of any supported API. If you write code that depends
    1.68 + * on this, you do so at your own risk. This code and its internal interfaces
    1.69 + * are subject to change or deletion without notice.</b>
    1.70 + */
    1.71 +public class Annotations {
    1.72 +
    1.73 +    private static final List<Attribute.Compound> NOT_STARTED = List.of(null);
    1.74 +    private static final List<Attribute.Compound> IN_PROGRESS = List.of(null);
    1.75 +    /*
    1.76 +     * This field should never be null
    1.77 +     */
    1.78 +    private List<Attribute.Compound> attributes = NOT_STARTED;
    1.79 +    /*
    1.80 +     * The Symbol this Annotatios belong to
    1.81 +     */
    1.82 +    private final Symbol s;
    1.83 +
    1.84 +    public Annotations(Symbol s) {
    1.85 +        this.s = s;
    1.86 +    }
    1.87 +
    1.88 +    public List<Attribute.Compound> getAttributes() {
    1.89 +        return filterSentinels(attributes);
    1.90 +    }
    1.91 +
    1.92 +    public void setAttributes(List<Attribute.Compound> a) {
    1.93 +        Assert.check(pendingCompletion() || !isStarted());
    1.94 +        if (a == null) {
    1.95 +            throw new NullPointerException();
    1.96 +        }
    1.97 +        attributes = a;
    1.98 +    }
    1.99 +
   1.100 +    public void setAttributes(Annotations other) {
   1.101 +        if (other == null) {
   1.102 +            throw new NullPointerException();
   1.103 +        }
   1.104 +        setAttributes(other.getAttributes());
   1.105 +    }
   1.106 +
   1.107 +    public void setAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) {
   1.108 +        Assert.check(pendingCompletion() || (!isStarted() && s.kind == PCK));
   1.109 +
   1.110 +        Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated = ctx.annotated;
   1.111 +        boolean atLeastOneRepeated = false;
   1.112 +        List<Attribute.Compound> buf = List.<Attribute.Compound>nil();
   1.113 +        for (ListBuffer<Attribute.Compound> lb : annotated.values()) {
   1.114 +            if (lb.size() == 1) {
   1.115 +                buf = buf.prepend(lb.first());
   1.116 +            } else { // repeated
   1.117 +                buf = buf.prepend(new Placeholder(lb.toList(), s));
   1.118 +                atLeastOneRepeated = true;
   1.119 +            }
   1.120 +        }
   1.121 +
   1.122 +        // Add non-repeating attributes
   1.123 +        setAttributes(buf.reverse());
   1.124 +
   1.125 +        if (atLeastOneRepeated) {
   1.126 +            // The Symbol s is now annotated with a combination of
   1.127 +            // finished non-repeating annotations and placeholders for
   1.128 +            // repeating annotations.
   1.129 +            //
   1.130 +            // We need to do this in two passes because when creating
   1.131 +            // a container for a repeating annotation we must
   1.132 +            // guarantee that the @ContainedBy on the
   1.133 +            // contained annotation is fully annotated
   1.134 +            //
   1.135 +            // The way we force this order is to do all repeating
   1.136 +            // annotations in a pass after all non-repeating are
   1.137 +            // finished. This will work because @ContainedBy
   1.138 +            // is non-repeating and therefore will be annotated in the
   1.139 +            // fist pass.
   1.140 +
   1.141 +            // Queue a pass that will replace Attribute.Placeholders
   1.142 +            // with Attribute.Compound (made from synthesized containers).
   1.143 +            ctx.annotateRepeated(new Annotate.Annotator() {
   1.144 +
   1.145 +                @Override
   1.146 +                public String toString() {
   1.147 +                    return "repeated annotation pass of: " + s + " in: " + s.owner;
   1.148 +                }
   1.149 +
   1.150 +                @Override
   1.151 +                public void enterAnnotation() {
   1.152 +                    complete(ctx);
   1.153 +                }
   1.154 +            });
   1.155 +        }
   1.156 +    }
   1.157 +
   1.158 +    public Annotations reset() {
   1.159 +        attributes = IN_PROGRESS;
   1.160 +        return this;
   1.161 +    }
   1.162 +
   1.163 +    public boolean isEmpty() {
   1.164 +        return !isStarted()
   1.165 +                || pendingCompletion()
   1.166 +                || attributes.isEmpty();
   1.167 +    }
   1.168 +
   1.169 +    public boolean pendingCompletion() {
   1.170 +        return attributes == IN_PROGRESS;
   1.171 +    }
   1.172 +
   1.173 +    public Annotations append(List<Attribute.Compound> l) {
   1.174 +        attributes = filterSentinels(attributes);
   1.175 +
   1.176 +        if (l.isEmpty()) {
   1.177 +            ; // no-op
   1.178 +        } else if (attributes.isEmpty()) {
   1.179 +            attributes = l;
   1.180 +        } else {
   1.181 +            attributes = attributes.appendList(l);
   1.182 +        }
   1.183 +        return this;
   1.184 +    }
   1.185 +
   1.186 +    public Annotations prepend(List<Attribute.Compound> l) {
   1.187 +        attributes = filterSentinels(attributes);
   1.188 +
   1.189 +        if (l.isEmpty()) {
   1.190 +            ; // no-op
   1.191 +        } else if (attributes.isEmpty()) {
   1.192 +            attributes = l;
   1.193 +        } else {
   1.194 +            attributes = attributes.prependList(l);
   1.195 +        }
   1.196 +        return this;
   1.197 +    }
   1.198 +
   1.199 +    private List<Attribute.Compound> filterSentinels(List<Attribute.Compound> a) {
   1.200 +        return (a == IN_PROGRESS || a == NOT_STARTED)
   1.201 +                ? List.<Attribute.Compound>nil()
   1.202 +                : a;
   1.203 +    }
   1.204 +
   1.205 +    private boolean isStarted() {
   1.206 +        return attributes != NOT_STARTED;
   1.207 +    }
   1.208 +
   1.209 +    private List<Attribute.Compound> getPlaceholders() {
   1.210 +        List<Attribute.Compound> res = List.<Attribute.Compound>nil();
   1.211 +        for (Attribute.Compound a : filterSentinels(attributes)) {
   1.212 +            if (a instanceof Placeholder) {
   1.213 +                res = res.prepend(a);
   1.214 +            }
   1.215 +        }
   1.216 +        return res.reverse();
   1.217 +    }
   1.218 +
   1.219 +    /*
   1.220 +     * Replace Placeholders for repeating annotations with their containers
   1.221 +     */
   1.222 +    private void complete(Annotate.AnnotateRepeatedContext ctx) {
   1.223 +        Assert.check(!pendingCompletion());
   1.224 +        Log log = ctx.log;
   1.225 +        Env<AttrContext> env = ctx.env;
   1.226 +        JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
   1.227 +        try {
   1.228 +
   1.229 +            if (isEmpty()) {
   1.230 +                return;
   1.231 +            }
   1.232 +
   1.233 +            List<Attribute.Compound> result = List.nil();
   1.234 +            for (Attribute.Compound a : getAttributes()) {
   1.235 +                if (a instanceof Placeholder) {
   1.236 +                    Attribute.Compound replacement = replaceOne((Placeholder) a, ctx);
   1.237 +
   1.238 +                    if (null != replacement) {
   1.239 +                        result = result.prepend(replacement);
   1.240 +                    }
   1.241 +                } else {
   1.242 +                    result = result.prepend(a);
   1.243 +                }
   1.244 +            }
   1.245 +
   1.246 +            attributes = result.reverse();
   1.247 +
   1.248 +            Assert.check(Annotations.this.getPlaceholders().isEmpty());
   1.249 +        } finally {
   1.250 +            log.useSource(oldSource);
   1.251 +        }
   1.252 +    }
   1.253 +
   1.254 +    private Attribute.Compound replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) {
   1.255 +        Log log = ctx.log;
   1.256 +
   1.257 +        // Process repeated annotations
   1.258 +        Attribute.Compound validRepeated =
   1.259 +                ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor());
   1.260 +
   1.261 +        if (validRepeated != null) {
   1.262 +            // Check that the container isn't manually
   1.263 +            // present along with repeated instances of
   1.264 +            // its contained annotation.
   1.265 +            ListBuffer<Attribute.Compound> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
   1.266 +            if (manualContainer != null) {
   1.267 +                log.error(ctx.pos.get(manualContainer.first()), "invalid.containedby.annotation.repeated.and.container.present",
   1.268 +                        manualContainer.first().type.tsym);
   1.269 +            }
   1.270 +        }
   1.271 +
   1.272 +        // A null return will delete the Placeholder
   1.273 +        return validRepeated;
   1.274 +
   1.275 +    }
   1.276 +
   1.277 +    private static class Placeholder extends Attribute.Compound {
   1.278 +
   1.279 +        private List<Attribute.Compound> placeholderFor;
   1.280 +        private Symbol on;
   1.281 +
   1.282 +        public Placeholder(List<Attribute.Compound> placeholderFor, Symbol on) {
   1.283 +            super(Type.noType, List.<Pair<Symbol.MethodSymbol, Attribute>>nil());
   1.284 +            this.placeholderFor = placeholderFor;
   1.285 +            this.on = on;
   1.286 +        }
   1.287 +
   1.288 +        @Override
   1.289 +        public String toString() {
   1.290 +            return "<placeholder: " + placeholderFor + " on: " + on + ">";
   1.291 +        }
   1.292 +
   1.293 +        public List<Attribute.Compound> getPlaceholderFor() {
   1.294 +            return placeholderFor;
   1.295 +        }
   1.296 +    }
   1.297 +}

mercurial