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

Tue, 15 Oct 2013 15:57:13 -0700

author
jjg
date
Tue, 15 Oct 2013 15:57:13 -0700
changeset 2134
b0c086cd4520
parent 2133
19e8eebfbe52
child 2525
2eb010b6cb22
child 3722
4560a907f04f
permissions
-rw-r--r--

8026564: import changes from type-annotations forest
Reviewed-by: jjg
Contributed-by: wdietl@gmail.com, steve.sides@oracle.com

jfranck@1313 1 /*
jjg@1492 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
jfranck@1313 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jfranck@1313 4 *
jfranck@1313 5 * This code is free software; you can redistribute it and/or modify it
jfranck@1313 6 * under the terms of the GNU General Public License version 2 only, as
jfranck@1313 7 * published by the Free Software Foundation. Oracle designates this
jfranck@1313 8 * particular file as subject to the "Classpath" exception as provided
jfranck@1313 9 * by Oracle in the LICENSE file that accompanied this code.
jfranck@1313 10 *
jfranck@1313 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jfranck@1313 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jfranck@1313 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jfranck@1313 14 * version 2 for more details (a copy is included in the LICENSE file that
jfranck@1313 15 * accompanied this code).
jfranck@1313 16 *
jfranck@1313 17 * You should have received a copy of the GNU General Public License version
jfranck@1313 18 * 2 along with this work; if not, write to the Free Software Foundation,
jfranck@1313 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jfranck@1313 20 *
jfranck@1313 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jfranck@1313 22 * or visit www.oracle.com if you need additional information or have any
jfranck@1313 23 * questions.
jfranck@1313 24 */
jfranck@1313 25
jfranck@1313 26 package com.sun.tools.javac.code;
jfranck@1313 27
jfranck@1313 28 import java.util.Map;
jjg@1357 29
jfranck@1313 30 import javax.tools.JavaFileObject;
jfranck@1313 31
jfranck@1313 32 import com.sun.tools.javac.comp.Annotate;
jfranck@1313 33 import com.sun.tools.javac.comp.AttrContext;
jfranck@1313 34 import com.sun.tools.javac.comp.Env;
jjg@1357 35 import com.sun.tools.javac.util.*;
jfranck@1313 36 import com.sun.tools.javac.util.Assert;
jfranck@1313 37 import com.sun.tools.javac.util.List;
jfranck@1313 38 import com.sun.tools.javac.util.Log;
jfranck@1313 39 import com.sun.tools.javac.util.Pair;
jfranck@1313 40 import static com.sun.tools.javac.code.Kinds.PCK;
jfranck@1313 41
jfranck@1313 42 /**
jfranck@1313 43 * Container for all annotations (attributes in javac) on a Symbol.
jfranck@1313 44 *
jfranck@1313 45 * This class is explicitly mutable. Its contents will change when attributes
jfranck@1313 46 * are annotated onto the Symbol. However this class depends on the facts that
jfranck@1313 47 * List (in javac) is immutable.
jfranck@1313 48 *
jfranck@1313 49 * An instance of this class can be in one of three states:
jfranck@1313 50 *
jjg@1521 51 * NOT_STARTED indicates that the Symbol this instance belongs to has not been
jfranck@1313 52 * annotated (yet). Specifically if the declaration is not annotated this
jfranck@1313 53 * instance will never move past NOT_STARTED. You can never go back to
jfranck@1313 54 * NOT_STARTED.
jfranck@1313 55 *
jfranck@1313 56 * IN_PROGRESS annotations have been found on the declaration. Will be processed
jfranck@1313 57 * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list
jfranck@1313 58 * of attributes (and this moves out of the IN_PROGRESS state).
jfranck@1313 59 *
jfranck@2014 60 * "unnamed" this SymbolMetadata contains some attributes, possibly the final set.
jfranck@1313 61 * While in this state you can only prepend or append to the attributes not set
jjg@1521 62 * it directly. You can also move back to the IN_PROGRESS state using reset().
jfranck@1313 63 *
jfranck@1313 64 * <p><b>This is NOT part of any supported API. If you write code that depends
jfranck@1313 65 * on this, you do so at your own risk. This code and its internal interfaces
jfranck@1313 66 * are subject to change or deletion without notice.</b>
jfranck@1313 67 */
jfranck@2014 68 public class SymbolMetadata {
jfranck@1313 69
jjg@1521 70 private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null);
jjg@1521 71 private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null);
jjg@1521 72
jfranck@1313 73 /*
jfranck@1313 74 * This field should never be null
jfranck@1313 75 */
jjg@1521 76 private List<Attribute.Compound> attributes = DECL_NOT_STARTED;
jjg@1521 77
jfranck@1313 78 /*
jjg@1755 79 * Type attributes for this symbol.
jjg@1755 80 * This field should never be null.
jjg@1521 81 */
jjg@1521 82 private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil();
jjg@1521 83
jjg@1521 84 /*
jjg@1755 85 * Type attributes of initializers in this class.
jjg@1755 86 * Unused if the current symbol is not a ClassSymbol.
jjg@1755 87 */
jjg@1755 88 private List<Attribute.TypeCompound> init_type_attributes = List.<Attribute.TypeCompound>nil();
jjg@1755 89
jjg@1755 90 /*
jjg@1755 91 * Type attributes of class initializers in this class.
jjg@1755 92 * Unused if the current symbol is not a ClassSymbol.
jjg@1755 93 */
jjg@1755 94 private List<Attribute.TypeCompound> clinit_type_attributes = List.<Attribute.TypeCompound>nil();
jjg@1755 95
jjg@1755 96 /*
jfranck@2014 97 * The Symbol this SymbolMetadata instance belongs to
jfranck@1313 98 */
jfranck@1445 99 private final Symbol sym;
jfranck@1313 100
jfranck@2014 101 public SymbolMetadata(Symbol sym) {
jfranck@1445 102 this.sym = sym;
jfranck@1313 103 }
jfranck@1313 104
jjg@1521 105 public List<Attribute.Compound> getDeclarationAttributes() {
jjg@1521 106 return filterDeclSentinels(attributes);
jfranck@1313 107 }
jfranck@1313 108
jjg@1521 109 public List<Attribute.TypeCompound> getTypeAttributes() {
jjg@1521 110 return type_attributes;
jjg@1521 111 }
jjg@1521 112
jjg@1755 113 public List<Attribute.TypeCompound> getInitTypeAttributes() {
jjg@1755 114 return init_type_attributes;
jjg@1755 115 }
jjg@1755 116
jjg@1755 117 public List<Attribute.TypeCompound> getClassInitTypeAttributes() {
jjg@1755 118 return clinit_type_attributes;
jjg@1755 119 }
jjg@1755 120
jjg@1521 121 public void setDeclarationAttributes(List<Attribute.Compound> a) {
jfranck@1313 122 Assert.check(pendingCompletion() || !isStarted());
jfranck@1313 123 if (a == null) {
jfranck@1313 124 throw new NullPointerException();
jfranck@1313 125 }
jfranck@1313 126 attributes = a;
jfranck@1313 127 }
jfranck@1313 128
jjg@1521 129 public void setTypeAttributes(List<Attribute.TypeCompound> a) {
jjg@1521 130 if (a == null) {
jjg@1521 131 throw new NullPointerException();
jjg@1521 132 }
jjg@1521 133 type_attributes = a;
jjg@1521 134 }
jjg@1521 135
jjg@1755 136 public void setInitTypeAttributes(List<Attribute.TypeCompound> a) {
jjg@1755 137 if (a == null) {
jjg@1755 138 throw new NullPointerException();
jjg@1755 139 }
jjg@1755 140 init_type_attributes = a;
jjg@1755 141 }
jjg@1755 142
jjg@1755 143 public void setClassInitTypeAttributes(List<Attribute.TypeCompound> a) {
jjg@1755 144 if (a == null) {
jjg@1755 145 throw new NullPointerException();
jjg@1755 146 }
jjg@1755 147 clinit_type_attributes = a;
jjg@1755 148 }
jjg@1755 149
jfranck@2014 150 public void setAttributes(SymbolMetadata other) {
jfranck@1313 151 if (other == null) {
jfranck@1313 152 throw new NullPointerException();
jfranck@1313 153 }
jjg@1521 154 setDeclarationAttributes(other.getDeclarationAttributes());
jjg@1521 155 setTypeAttributes(other.getTypeAttributes());
jjg@1755 156 setInitTypeAttributes(other.getInitTypeAttributes());
jjg@1755 157 setClassInitTypeAttributes(other.getClassInitTypeAttributes());
jfranck@1313 158 }
jfranck@1313 159
jjg@1521 160 public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) {
jfranck@1445 161 Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
jjg@1521 162 this.setDeclarationAttributes(getAttributesForCompletion(ctx));
jjg@1521 163 }
jfranck@1313 164
jjg@1521 165 public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) {
jjg@1521 166 this.appendUniqueTypes(getAttributesForCompletion(ctx));
jjg@1521 167 }
jjg@1521 168
jjg@1521 169 private <T extends Attribute.Compound> List<T> getAttributesForCompletion(
jjg@1521 170 final Annotate.AnnotateRepeatedContext<T> ctx) {
jjg@1521 171
jjg@1521 172 Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated;
jfranck@1313 173 boolean atLeastOneRepeated = false;
jjg@1521 174 List<T> buf = List.<T>nil();
jjg@1521 175 for (ListBuffer<T> lb : annotated.values()) {
jfranck@1313 176 if (lb.size() == 1) {
jfranck@1313 177 buf = buf.prepend(lb.first());
jfranck@1313 178 } else { // repeated
jjg@1521 179 // This will break when other subtypes of Attributs.Compound
jjg@1521 180 // are introduced, because PlaceHolder is a subtype of TypeCompound.
jjg@1521 181 T res;
jjg@1521 182 @SuppressWarnings("unchecked")
jjg@1521 183 T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym);
jjg@1521 184 res = ph;
jjg@1521 185 buf = buf.prepend(res);
jfranck@1313 186 atLeastOneRepeated = true;
jfranck@1313 187 }
jfranck@1313 188 }
jfranck@1313 189
jfranck@1313 190 if (atLeastOneRepeated) {
jfranck@1313 191 // The Symbol s is now annotated with a combination of
jfranck@1313 192 // finished non-repeating annotations and placeholders for
jfranck@1313 193 // repeating annotations.
jfranck@1313 194 //
jfranck@1313 195 // We need to do this in two passes because when creating
jfranck@1313 196 // a container for a repeating annotation we must
jjg@1492 197 // guarantee that the @Repeatable on the
jfranck@1313 198 // contained annotation is fully annotated
jfranck@1313 199 //
jfranck@1313 200 // The way we force this order is to do all repeating
jfranck@1313 201 // annotations in a pass after all non-repeating are
jjg@1492 202 // finished. This will work because @Repeatable
jfranck@1313 203 // is non-repeating and therefore will be annotated in the
jfranck@1313 204 // fist pass.
jfranck@1313 205
jfranck@1313 206 // Queue a pass that will replace Attribute.Placeholders
jfranck@1313 207 // with Attribute.Compound (made from synthesized containers).
jlahoda@2133 208 ctx.annotateRepeated(new Annotate.Worker() {
jfranck@1313 209 @Override
jfranck@1313 210 public String toString() {
jfranck@1445 211 return "repeated annotation pass of: " + sym + " in: " + sym.owner;
jfranck@1313 212 }
jfranck@1313 213
jfranck@1313 214 @Override
jlahoda@2133 215 public void run() {
jfranck@1313 216 complete(ctx);
jfranck@1313 217 }
jfranck@1313 218 });
jfranck@1313 219 }
jjg@1521 220 // Add non-repeating attributes
jjg@1521 221 return buf.reverse();
jfranck@1313 222 }
jfranck@1313 223
jfranck@2014 224 public SymbolMetadata reset() {
jjg@1521 225 attributes = DECL_IN_PROGRESS;
jfranck@1313 226 return this;
jfranck@1313 227 }
jfranck@1313 228
jfranck@1313 229 public boolean isEmpty() {
jfranck@1313 230 return !isStarted()
jfranck@1313 231 || pendingCompletion()
jfranck@1313 232 || attributes.isEmpty();
jfranck@1313 233 }
jfranck@1313 234
jjg@1521 235 public boolean isTypesEmpty() {
jjg@1521 236 return type_attributes.isEmpty();
jjg@1521 237 }
jjg@1521 238
jfranck@1313 239 public boolean pendingCompletion() {
jjg@1521 240 return attributes == DECL_IN_PROGRESS;
jfranck@1313 241 }
jfranck@1313 242
jfranck@2014 243 public SymbolMetadata append(List<Attribute.Compound> l) {
jjg@1521 244 attributes = filterDeclSentinels(attributes);
jfranck@1313 245
jfranck@1313 246 if (l.isEmpty()) {
jfranck@1313 247 ; // no-op
jfranck@1313 248 } else if (attributes.isEmpty()) {
jfranck@1313 249 attributes = l;
jfranck@1313 250 } else {
jfranck@1313 251 attributes = attributes.appendList(l);
jfranck@1313 252 }
jfranck@1313 253 return this;
jfranck@1313 254 }
jfranck@1313 255
jfranck@2014 256 public SymbolMetadata appendUniqueTypes(List<Attribute.TypeCompound> l) {
jjg@1521 257 if (l.isEmpty()) {
jjg@1521 258 ; // no-op
jjg@1521 259 } else if (type_attributes.isEmpty()) {
jjg@1521 260 type_attributes = l;
jjg@1521 261 } else {
jjg@1521 262 // TODO: in case we expect a large number of annotations, this
jjg@1521 263 // might be inefficient.
jjg@1521 264 for (Attribute.TypeCompound tc : l) {
jjg@1521 265 if (!type_attributes.contains(tc))
jjg@1521 266 type_attributes = type_attributes.append(tc);
jjg@1521 267 }
jjg@1521 268 }
jjg@1521 269 return this;
jjg@1521 270 }
jjg@1521 271
jfranck@2014 272 public SymbolMetadata appendInitTypeAttributes(List<Attribute.TypeCompound> l) {
jjg@1755 273 if (l.isEmpty()) {
jjg@1755 274 ; // no-op
jjg@1755 275 } else if (init_type_attributes.isEmpty()) {
jjg@1755 276 init_type_attributes = l;
jjg@1755 277 } else {
jjg@1755 278 init_type_attributes = init_type_attributes.appendList(l);
jjg@1755 279 }
jjg@1755 280 return this;
jjg@1755 281 }
jjg@1755 282
jfranck@2014 283 public SymbolMetadata appendClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
jjg@1755 284 if (l.isEmpty()) {
jjg@1755 285 ; // no-op
jjg@1755 286 } else if (clinit_type_attributes.isEmpty()) {
jjg@1755 287 clinit_type_attributes = l;
jjg@1755 288 } else {
jjg@1755 289 clinit_type_attributes = clinit_type_attributes.appendList(l);
jjg@1755 290 }
jjg@1755 291 return this;
jjg@1755 292 }
jjg@1755 293
jfranck@2014 294 public SymbolMetadata prepend(List<Attribute.Compound> l) {
jjg@1521 295 attributes = filterDeclSentinels(attributes);
jfranck@1313 296
jfranck@1313 297 if (l.isEmpty()) {
jfranck@1313 298 ; // no-op
jfranck@1313 299 } else if (attributes.isEmpty()) {
jfranck@1313 300 attributes = l;
jfranck@1313 301 } else {
jfranck@1313 302 attributes = attributes.prependList(l);
jfranck@1313 303 }
jfranck@1313 304 return this;
jfranck@1313 305 }
jfranck@1313 306
jjg@1521 307 private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) {
jjg@1521 308 return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED)
jfranck@1313 309 ? List.<Attribute.Compound>nil()
jfranck@1313 310 : a;
jfranck@1313 311 }
jfranck@1313 312
jfranck@1313 313 private boolean isStarted() {
jjg@1521 314 return attributes != DECL_NOT_STARTED;
jfranck@1313 315 }
jfranck@1313 316
jfranck@1313 317 private List<Attribute.Compound> getPlaceholders() {
jfranck@1313 318 List<Attribute.Compound> res = List.<Attribute.Compound>nil();
jjg@1521 319 for (Attribute.Compound a : filterDeclSentinels(attributes)) {
jjg@1521 320 if (a instanceof Placeholder) {
jjg@1521 321 res = res.prepend(a);
jjg@1521 322 }
jjg@1521 323 }
jjg@1521 324 return res.reverse();
jjg@1521 325 }
jjg@1521 326
jjg@1521 327 private List<Attribute.TypeCompound> getTypePlaceholders() {
jjg@1521 328 List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil();
jjg@1521 329 for (Attribute.TypeCompound a : type_attributes) {
jfranck@1313 330 if (a instanceof Placeholder) {
jfranck@1313 331 res = res.prepend(a);
jfranck@1313 332 }
jfranck@1313 333 }
jfranck@1313 334 return res.reverse();
jfranck@1313 335 }
jfranck@1313 336
jfranck@1313 337 /*
jfranck@1313 338 * Replace Placeholders for repeating annotations with their containers
jfranck@1313 339 */
jjg@1521 340 private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) {
jfranck@1313 341 Log log = ctx.log;
jfranck@1313 342 Env<AttrContext> env = ctx.env;
jfranck@1313 343 JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
jfranck@1313 344 try {
jjg@1521 345 // TODO: can we reduce duplication in the following branches?
jjg@1521 346 if (ctx.isTypeCompound) {
jjg@1521 347 Assert.check(!isTypesEmpty());
jfranck@1313 348
jjg@1521 349 if (isTypesEmpty()) {
jjg@1521 350 return;
jjg@1521 351 }
jjg@1521 352
jjg@1521 353 List<Attribute.TypeCompound> result = List.nil();
jjg@1521 354 for (Attribute.TypeCompound a : getTypeAttributes()) {
jjg@1521 355 if (a instanceof Placeholder) {
jjg@1521 356 @SuppressWarnings("unchecked")
jjg@1521 357 Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a;
jjg@1521 358 Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());
jjg@1521 359
jjg@1521 360 if (null != replacement) {
jjg@1521 361 result = result.prepend(replacement);
jjg@1521 362 }
jjg@1521 363 } else {
jjg@1521 364 result = result.prepend(a);
jjg@1521 365 }
jjg@1521 366 }
jjg@1521 367
jjg@1521 368 type_attributes = result.reverse();
jjg@1521 369
jfranck@2014 370 Assert.check(SymbolMetadata.this.getTypePlaceholders().isEmpty());
jjg@1521 371 } else {
jjg@1521 372 Assert.check(!pendingCompletion());
jjg@1521 373
jjg@1521 374 if (isEmpty()) {
jjg@1521 375 return;
jjg@1521 376 }
jjg@1521 377
jjg@1521 378 List<Attribute.Compound> result = List.nil();
jjg@1521 379 for (Attribute.Compound a : getDeclarationAttributes()) {
jjg@1521 380 if (a instanceof Placeholder) {
jjg@1521 381 @SuppressWarnings("unchecked")
jjg@1521 382 Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx);
jjg@1521 383
jjg@1521 384 if (null != replacement) {
jjg@1521 385 result = result.prepend(replacement);
jjg@1521 386 }
jjg@1521 387 } else {
jjg@1521 388 result = result.prepend(a);
jjg@1521 389 }
jjg@1521 390 }
jjg@1521 391
jjg@1521 392 attributes = result.reverse();
jjg@1521 393
jfranck@2014 394 Assert.check(SymbolMetadata.this.getPlaceholders().isEmpty());
jfranck@1313 395 }
jfranck@1313 396 } finally {
jfranck@1313 397 log.useSource(oldSource);
jfranck@1313 398 }
jfranck@1313 399 }
jfranck@1313 400
jjg@1521 401 private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) {
jfranck@1313 402 Log log = ctx.log;
jfranck@1313 403
jfranck@1313 404 // Process repeated annotations
jjg@1521 405 T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym);
jfranck@1313 406
jfranck@1313 407 if (validRepeated != null) {
jfranck@1313 408 // Check that the container isn't manually
jfranck@1313 409 // present along with repeated instances of
jfranck@1313 410 // its contained annotation.
jjg@1521 411 ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
jfranck@1313 412 if (manualContainer != null) {
jjg@1492 413 log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
jfranck@1313 414 manualContainer.first().type.tsym);
jfranck@1313 415 }
jfranck@1313 416 }
jfranck@1313 417
jfranck@1313 418 // A null return will delete the Placeholder
jfranck@1313 419 return validRepeated;
jfranck@1313 420 }
jfranck@1313 421
jjg@1521 422 private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound {
jfranck@1313 423
jjg@1521 424 private final Annotate.AnnotateRepeatedContext<T> ctx;
jjg@1521 425 private final List<T> placeholderFor;
jjg@1521 426 private final Symbol on;
jfranck@1313 427
jjg@1521 428 public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) {
jjg@1521 429 super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
jjg@1521 430 ctx.isTypeCompound ?
jjg@1521 431 ((Attribute.TypeCompound)placeholderFor.head).position :
jjg@2134 432 new TypeAnnotationPosition());
jjg@1521 433 this.ctx = ctx;
jfranck@1313 434 this.placeholderFor = placeholderFor;
jfranck@1313 435 this.on = on;
jfranck@1313 436 }
jfranck@1313 437
jfranck@1313 438 @Override
jfranck@1313 439 public String toString() {
jfranck@1313 440 return "<placeholder: " + placeholderFor + " on: " + on + ">";
jfranck@1313 441 }
jfranck@1313 442
jjg@1521 443 public List<T> getPlaceholderFor() {
jfranck@1313 444 return placeholderFor;
jfranck@1313 445 }
jjg@1521 446
jjg@1521 447 public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() {
jjg@1521 448 return ctx;
jjg@1521 449 }
jfranck@1313 450 }
jfranck@1313 451 }

mercurial