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