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 +}