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