1 /*
   2  * Copyright (c) 2003, 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.LinkedHashMap;
  29 import java.util.Map;
  30 import javax.lang.model.element.AnnotationMirror;
  31 import javax.lang.model.element.AnnotationValue;
  32 import javax.lang.model.element.AnnotationValueVisitor;
  33 import javax.lang.model.type.DeclaredType;
  34 import com.sun.tools.javac.code.Symbol.*;
  35 import com.sun.tools.javac.util.*;
  36 import com.sun.tools.javac.util.DefinedBy.Api;
  37 
  38 /** An annotation value.
  39  *
  40  *  <p><b>This is NOT part of any supported API.
  41  *  If you write code that depends on this, you do so at your own risk.
  42  *  This code and its internal interfaces are subject to change or
  43  *  deletion without notice.</b>
  44  */
  45 public abstract class Attribute implements AnnotationValue {
  46 
  47     /** The type of the annotation element. */
  48     public Type type;
  49 
  50     public Attribute(Type type) {
  51         this.type = type;
  52     }
  53 
  54     public abstract void accept(Visitor v);
  55 
  56     @DefinedBy(Api.LANGUAGE_MODEL)
  57     public Object getValue() {
  58         throw new UnsupportedOperationException();
  59     }
  60 
  61     @DefinedBy(Api.LANGUAGE_MODEL)
  62     public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
  63         throw new UnsupportedOperationException();
  64     }
  65 
  66     @Override
  67     @DefinedBy(Api.LANGUAGE_MODEL)
  68     public boolean equals(Object o) {
  69         if (o instanceof AnnotationValue) {
  70             AnnotationValue that = (AnnotationValue) o;
  71             return getValue().equals(that.getValue());
  72         } else {
  73             return false;
  74         }
  75     }
  76 
  77     @Override
  78     @DefinedBy(Api.LANGUAGE_MODEL)
  79     public int hashCode() {
  80         return getValue().hashCode();
  81     }
  82 
  83     public boolean isSynthesized() {
  84         return false;
  85     }
  86 
  87     public TypeAnnotationPosition getPosition() { return null; }
  88 
  89     /** The value for an annotation element of primitive type or String. */
  90     public static class Constant extends Attribute {
  91         public final Object value;
  92         public void accept(Visitor v) { v.visitConstant(this); }
  93         public Constant(Type type, Object value) {
  94             super(type);
  95             this.value = value;
  96         }
  97         @DefinedBy(Api.LANGUAGE_MODEL)
  98         public String toString() {
  99             return Constants.format(value, type);
 100         }
 101         @DefinedBy(Api.LANGUAGE_MODEL)
 102         public Object getValue() {
 103             return Constants.decode(value, type);
 104         }
 105         @DefinedBy(Api.LANGUAGE_MODEL)
 106         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 107             if (value instanceof String)
 108                 return v.visitString((String) value, p);
 109             if (value instanceof Integer) {
 110                 int i = (Integer) value;
 111                 switch (type.getTag()) {
 112                 case BOOLEAN:   return v.visitBoolean(i != 0, p);
 113                 case CHAR:      return v.visitChar((char) i, p);
 114                 case BYTE:      return v.visitByte((byte) i, p);
 115                 case SHORT:     return v.visitShort((short) i, p);
 116                 case INT:       return v.visitInt(i, p);
 117                 }
 118             }
 119             switch (type.getTag()) {
 120             case LONG:          return v.visitLong((Long) value, p);
 121             case FLOAT:         return v.visitFloat((Float) value, p);
 122             case DOUBLE:        return v.visitDouble((Double) value, p);
 123             }
 124             throw new AssertionError("Bad annotation element value: " + value);
 125         }
 126     }
 127 
 128     /** The value for an annotation element of type java.lang.Class,
 129      *  represented as a ClassSymbol.
 130      */
 131     public static class Class extends Attribute {
 132         public final Type classType;
 133         public void accept(Visitor v) { v.visitClass(this); }
 134         public Class(Types types, Type type) {
 135             super(makeClassType(types, type));
 136             this.classType = type;
 137         }
 138         static Type makeClassType(Types types, Type type) {
 139             Type arg = type.isPrimitive()
 140                 ? types.boxedClass(type).type
 141                 : types.erasure(type);
 142             return new Type.ClassType(types.syms.classType.getEnclosingType(),
 143                                       List.of(arg),
 144                                       types.syms.classType.tsym);
 145         }
 146         @DefinedBy(Api.LANGUAGE_MODEL)
 147         public String toString() {
 148             return classType + ".class";
 149         }
 150         @DefinedBy(Api.LANGUAGE_MODEL)
 151         public Type getValue() {
 152             return classType;
 153         }
 154         @DefinedBy(Api.LANGUAGE_MODEL)
 155         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 156             return v.visitType(classType, p);
 157         }
 158     }
 159 
 160     /** A compound annotation element value, the type of which is an
 161      *  attribute interface.
 162      */
 163     public static class Compound extends Attribute implements AnnotationMirror {
 164         /** The attributes values, as pairs.  Each pair contains a
 165          *  reference to the accessing method in the attribute interface
 166          *  and the value to be returned when that method is called to
 167          *  access this attribute.
 168          */
 169         public final List<Pair<MethodSymbol,Attribute>> values;
 170         public TypeAnnotationPosition position;
 171 
 172         private boolean synthesized = false;
 173 
 174         @Override
 175         public boolean isSynthesized() {
 176             return synthesized;
 177         }
 178 
 179         public void setSynthesized(boolean synthesized) {
 180             this.synthesized = synthesized;
 181         }
 182 
 183         public Compound(Type type,
 184                         List<Pair<MethodSymbol,Attribute>> values,
 185                         TypeAnnotationPosition position) {
 186             super(type);
 187             this.values = values;
 188             this.position = position;
 189         }
 190 
 191         public Compound(Type type,
 192                         List<Pair<MethodSymbol,Attribute>> values) {
 193             this(type, values, null);
 194         }
 195 
 196         @Override
 197         public TypeAnnotationPosition getPosition() {
 198             if (hasUnknownPosition()) {
 199                 if (values.size() != 0) {
 200                     Name valueName = values.head.fst.name.table.names.value;
 201                     Pair<MethodSymbol, Attribute> res = getElemPair(valueName);
 202                     position = res == null ? null : res.snd.getPosition();
 203                 }
 204             }
 205             return position;
 206         }
 207 
 208         public boolean isContainerTypeCompound() {
 209             if (isSynthesized() && values.size() == 1)
 210                 return getFirstEmbeddedTC() != null;
 211             return false;
 212         }
 213 
 214         private Compound getFirstEmbeddedTC() {
 215             if (values.size() == 1) {
 216                 Pair<MethodSymbol, Attribute> val = values.get(0);
 217                 if (val.fst.getSimpleName().contentEquals("value")
 218                         && val.snd instanceof Array) {
 219                     Array arr = (Array) val.snd;
 220                     if (arr.values.length != 0
 221                             && arr.values[0] instanceof Attribute.TypeCompound)
 222                         return (Attribute.TypeCompound) arr.values[0];
 223                 }
 224             }
 225             return null;
 226         }
 227 
 228         public boolean tryFixPosition() {
 229             if (!isContainerTypeCompound())
 230                 return false;
 231 
 232             Compound from = getFirstEmbeddedTC();
 233             if (from != null && from.position != null &&
 234                     from.position.type != TargetType.UNKNOWN) {
 235                 position = from.position;
 236                 return true;
 237             }
 238             return false;
 239         }
 240 
 241         public boolean hasUnknownPosition() {
 242             return position.type == TargetType.UNKNOWN;
 243         }
 244 
 245         public void accept(Visitor v) { v.visitCompound(this); }
 246 
 247         /**
 248          * Returns a string representation of this annotation.
 249          * String is of one of the forms:
 250          * <pre>
 251          *     {@code @com.example.foo(name1=val1, name2=val2)}
 252          *     {@code @com.example.foo(val)}
 253          *     {@code @com.example.foo}
 254          * </pre>
 255          * Omit parens for marker annotations, and omit "value=" when allowed.
 256          */
 257         @DefinedBy(Api.LANGUAGE_MODEL)
 258         public String toString() {
 259             StringBuilder buf = new StringBuilder();
 260             buf.append("@");
 261             buf.append(type);
 262             int len = values.length();
 263             if (len > 0) {
 264                 buf.append('(');
 265                 boolean first = true;
 266                 for (Pair<MethodSymbol, Attribute> value : values) {
 267                     if (!first) buf.append(", ");
 268                     first = false;
 269 
 270                     Name name = value.fst.name;
 271                     if (len > 1 || name != name.table.names.value) {
 272                         buf.append(name);
 273                         buf.append('=');
 274                     }
 275                     buf.append(value.snd);
 276                 }
 277                 buf.append(')');
 278             }
 279             return buf.toString();
 280         }
 281 
 282         @Override
 283         @DefinedBy(Api.LANGUAGE_MODEL)
 284         public boolean equals(Object o) {
 285             if (o instanceof AnnotationMirror) {
 286                 AnnotationMirror that = (AnnotationMirror) o;
 287                 return
 288                     getAnnotationType().equals(that.getAnnotationType()) &&
 289                     getElementValues().equals(that.getElementValues());
 290             } else {
 291                 return false;
 292             }
 293         }
 294 
 295         @Override
 296         @DefinedBy(Api.LANGUAGE_MODEL)
 297         public int hashCode() {
 298              return getAnnotationType().hashCode() ^
 299                  getElementValues().hashCode();
 300         }
 301 
 302         public Attribute member(Name member) {
 303             Pair<MethodSymbol,Attribute> res = getElemPair(member);
 304             return res == null ? null : res.snd;
 305         }
 306 
 307         private Pair<MethodSymbol, Attribute> getElemPair(Name member) {
 308             for (Pair<MethodSymbol,Attribute> pair : values)
 309                 if (pair.fst.name == member) return pair;
 310             return null;
 311         }
 312 
 313         @DefinedBy(Api.LANGUAGE_MODEL)
 314         public Attribute.Compound getValue() {
 315             return this;
 316         }
 317 
 318         @DefinedBy(Api.LANGUAGE_MODEL)
 319         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 320             return v.visitAnnotation(this, p);
 321         }
 322 
 323         @DefinedBy(Api.LANGUAGE_MODEL)
 324         public DeclaredType getAnnotationType() {
 325             return (DeclaredType) type;
 326         }
 327 
 328         @DefinedBy(Api.LANGUAGE_MODEL)
 329         public Map<MethodSymbol, Attribute> getElementValues() {
 330             Map<MethodSymbol, Attribute> valmap = new LinkedHashMap<>();
 331             for (Pair<MethodSymbol, Attribute> value : values)
 332                 valmap.put(value.fst, value.snd);
 333             return valmap;
 334         }
 335     }
 336 
 337     public static class TypeCompound extends Compound {
 338         public TypeCompound(Compound compound,
 339                              TypeAnnotationPosition position) {
 340             super(compound.type, compound.values, position);
 341         }
 342 
 343         public TypeCompound(Type type,
 344                              List<Pair<MethodSymbol,Attribute>> values,
 345                              TypeAnnotationPosition position) {
 346             super(type, values, position);
 347         }
 348     }
 349 
 350     /** The value for an annotation element of an array type.
 351      */
 352     public static class Array extends Attribute {
 353         public final Attribute[] values;
 354         public Array(Type type, Attribute[] values) {
 355             super(type);
 356             this.values = values;
 357         }
 358 
 359         public Array(Type type, List<Attribute> values) {
 360             super(type);
 361             this.values = values.toArray(new Attribute[values.size()]);
 362         }
 363 
 364         public void accept(Visitor v) { v.visitArray(this); }
 365         @DefinedBy(Api.LANGUAGE_MODEL)
 366         public String toString() {
 367             StringBuilder buf = new StringBuilder();
 368             buf.append('{');
 369             boolean first = true;
 370             for (Attribute value : values) {
 371                 if (!first)
 372                     buf.append(", ");
 373                 first = false;
 374                 buf.append(value);
 375             }
 376             buf.append('}');
 377             return buf.toString();
 378         }
 379         @DefinedBy(Api.LANGUAGE_MODEL)
 380         public List<Attribute> getValue() {
 381             return List.from(values);
 382         }
 383         @DefinedBy(Api.LANGUAGE_MODEL)
 384         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 385             return v.visitArray(getValue(), p);
 386         }
 387 
 388         @Override
 389         public TypeAnnotationPosition getPosition() {
 390             if (values.length != 0)
 391                 return values[0].getPosition();
 392             else
 393                 return null;
 394         }
 395     }
 396 
 397     /** The value for an annotation element of an enum type.
 398      */
 399     public static class Enum extends Attribute {
 400         public VarSymbol value;
 401         public Enum(Type type, VarSymbol value) {
 402             super(type);
 403             this.value = Assert.checkNonNull(value);
 404         }
 405         public void accept(Visitor v) { v.visitEnum(this); }
 406         @DefinedBy(Api.LANGUAGE_MODEL)
 407         public String toString() {
 408             return value.enclClass() + "." + value;     // qualified name
 409         }
 410         @DefinedBy(Api.LANGUAGE_MODEL)
 411         public VarSymbol getValue() {
 412             return value;
 413         }
 414         @DefinedBy(Api.LANGUAGE_MODEL)
 415         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 416             return v.visitEnumConstant(value, p);
 417         }
 418     }
 419 
 420     public static class Error extends Attribute {
 421         public Error(Type type) {
 422             super(type);
 423         }
 424         public void accept(Visitor v) { v.visitError(this); }
 425         @DefinedBy(Api.LANGUAGE_MODEL)
 426         public String toString() {
 427             return "<error>";
 428         }
 429         @DefinedBy(Api.LANGUAGE_MODEL)
 430         public String getValue() {
 431             return toString();
 432         }
 433         @DefinedBy(Api.LANGUAGE_MODEL)
 434         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 435             return v.visitString(toString(), p);
 436         }
 437     }
 438 
 439     public static class UnresolvedClass extends Error {
 440         public Type classType;
 441         public UnresolvedClass(Type type, Type classType) {
 442             super(type);
 443             this.classType = classType;
 444         }
 445     }
 446 
 447     /** A visitor type for dynamic dispatch on the kind of attribute value. */
 448     public static interface Visitor {
 449         void visitConstant(Attribute.Constant value);
 450         void visitClass(Attribute.Class clazz);
 451         void visitCompound(Attribute.Compound compound);
 452         void visitArray(Attribute.Array array);
 453         void visitEnum(Attribute.Enum e);
 454         void visitError(Attribute.Error e);
 455     }
 456 
 457     /** A mirror of java.lang.annotation.RetentionPolicy. */
 458     public static enum RetentionPolicy {
 459         SOURCE,
 460         CLASS,
 461         RUNTIME
 462     }
 463 }