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