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)
 251                         buf.append(", ");
 252                     first = false;
 253 
 254                     Name name = value.fst.name;
 255                     if (len > 1 || name != name.table.names.value) {
 256                         buf.append(name);
 257                         buf.append('=');
 258                     }
 259                     buf.append(value.snd);
 260                 }
 261                 buf.append(')');
 262             }
 263             return buf.toString();
 264         }
 265 
 266         public Attribute member(Name member) {
 267             Pair<MethodSymbol,Attribute> res = getElemPair(member);
 268             return res == null ? null : res.snd;
 269         }
 270 
 271         private Pair<MethodSymbol, Attribute> getElemPair(Name member) {
 272             for (Pair<MethodSymbol,Attribute> pair : values)
 273                 if (pair.fst.name == member) return pair;
 274             return null;
 275         }
 276 
 277         @DefinedBy(Api.LANGUAGE_MODEL)
 278         public Attribute.Compound getValue() {
 279             return this;
 280         }
 281 
 282         @DefinedBy(Api.LANGUAGE_MODEL)
 283         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 284             return v.visitAnnotation(this, p);
 285         }
 286 
 287         @DefinedBy(Api.LANGUAGE_MODEL)
 288         public DeclaredType getAnnotationType() {
 289             return (DeclaredType) type;
 290         }
 291 
 292         @DefinedBy(Api.LANGUAGE_MODEL)
 293         public Map<MethodSymbol, Attribute> getElementValues() {
 294             Map<MethodSymbol, Attribute> valmap = new LinkedHashMap<>();
 295             for (Pair<MethodSymbol, Attribute> value : values)
 296                 valmap.put(value.fst, value.snd);
 297             return valmap;
 298         }
 299     }
 300 
 301     public static class TypeCompound extends Compound {
 302         public TypeCompound(Compound compound,
 303                              TypeAnnotationPosition position) {
 304             super(compound.type, compound.values, position);
 305         }
 306 
 307         public TypeCompound(Type type,
 308                              List<Pair<MethodSymbol,Attribute>> values,
 309                              TypeAnnotationPosition position) {
 310             super(type, values, position);
 311         }
 312     }
 313 
 314     /** The value for an annotation element of an array type.
 315      */
 316     public static class Array extends Attribute {
 317         public final Attribute[] values;
 318         public Array(Type type, Attribute[] values) {
 319             super(type);
 320             this.values = values;
 321         }
 322 
 323         public Array(Type type, List<Attribute> values) {
 324             super(type);
 325             this.values = values.toArray(new Attribute[values.size()]);
 326         }
 327 
 328         public void accept(Visitor v) { v.visitArray(this); }
 329         @DefinedBy(Api.LANGUAGE_MODEL)
 330         public String toString() {
 331             StringBuilder buf = new StringBuilder();
 332             buf.append('{');
 333             boolean first = true;
 334             for (Attribute value : values) {
 335                 if (!first)
 336                     buf.append(", ");
 337                 first = false;
 338                 buf.append(value);
 339             }
 340             buf.append('}');
 341             return buf.toString();
 342         }
 343         @DefinedBy(Api.LANGUAGE_MODEL)
 344         public List<Attribute> getValue() {
 345             return List.from(values);
 346         }
 347         @DefinedBy(Api.LANGUAGE_MODEL)
 348         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 349             return v.visitArray(getValue(), p);
 350         }
 351 
 352         @Override
 353         public TypeAnnotationPosition getPosition() {
 354             if (values.length != 0)
 355                 return values[0].getPosition();
 356             else
 357                 return null;
 358         }
 359     }
 360 
 361     /** The value for an annotation element of an enum type.
 362      */
 363     public static class Enum extends Attribute {
 364         public VarSymbol value;
 365         public Enum(Type type, VarSymbol value) {
 366             super(type);
 367             this.value = Assert.checkNonNull(value);
 368         }
 369         public void accept(Visitor v) { v.visitEnum(this); }
 370         @DefinedBy(Api.LANGUAGE_MODEL)
 371         public String toString() {
 372             return value.enclClass() + "." + value;     // qualified name
 373         }
 374         @DefinedBy(Api.LANGUAGE_MODEL)
 375         public VarSymbol getValue() {
 376             return value;
 377         }
 378         @DefinedBy(Api.LANGUAGE_MODEL)
 379         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 380             return v.visitEnumConstant(value, p);
 381         }
 382     }
 383 
 384     public static class Error extends Attribute {
 385         public Error(Type type) {
 386             super(type);
 387         }
 388         public void accept(Visitor v) { v.visitError(this); }
 389         @DefinedBy(Api.LANGUAGE_MODEL)
 390         public String toString() {
 391             return "<error>";
 392         }
 393         @DefinedBy(Api.LANGUAGE_MODEL)
 394         public String getValue() {
 395             return toString();
 396         }
 397         @DefinedBy(Api.LANGUAGE_MODEL)
 398         public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
 399             return v.visitString(toString(), p);
 400         }
 401     }
 402 
 403     public static class UnresolvedClass extends Error {
 404         public Type classType;
 405         public UnresolvedClass(Type type, Type classType) {
 406             super(type);
 407             this.classType = classType;
 408         }
 409     }
 410 
 411     /** A visitor type for dynamic dispatch on the kind of attribute value. */
 412     public static interface Visitor {
 413         void visitConstant(Attribute.Constant value);
 414         void visitClass(Attribute.Class clazz);
 415         void visitCompound(Attribute.Compound compound);
 416         void visitArray(Attribute.Array array);
 417         void visitEnum(Attribute.Enum e);
 418         void visitError(Attribute.Error e);
 419     }
 420 
 421     /** A mirror of java.lang.annotation.RetentionPolicy. */
 422     public static enum RetentionPolicy {
 423         SOURCE,
 424         CLASS,
 425         RUNTIME
 426     }
 427 }