1 /* 2 * Copyright (c) 2003, 2019, 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 Attribute(Type type)50 public Attribute(Type type) { 51 this.type = type; 52 } 53 accept(Visitor v)54 public abstract void accept(Visitor v); 55 56 @DefinedBy(Api.LANGUAGE_MODEL) getValue()57 public Object getValue() { 58 throw new UnsupportedOperationException(); 59 } 60 61 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)62 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 63 throw new UnsupportedOperationException(); 64 } 65 isSynthesized()66 public boolean isSynthesized() { 67 return false; 68 } 69 getPosition()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; accept(Visitor v)75 public void accept(Visitor v) { v.visitConstant(this); } Constant(Type type, Object value)76 public Constant(Type type, Object value) { 77 super(type); 78 this.value = value; 79 } 80 @DefinedBy(Api.LANGUAGE_MODEL) toString()81 public String toString() { 82 return Constants.format(value, type); 83 } 84 @DefinedBy(Api.LANGUAGE_MODEL) getValue()85 public Object getValue() { 86 return Constants.decode(value, type); 87 } 88 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)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; accept(Visitor v)116 public void accept(Visitor v) { v.visitClass(this); } Class(Types types, Type type)117 public Class(Types types, Type type) { 118 super(makeClassType(types, type)); 119 this.classType = type; 120 } makeClassType(Types types, Type type)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) toString()130 public String toString() { 131 return classType + ".class"; 132 } 133 @DefinedBy(Api.LANGUAGE_MODEL) getValue()134 public Type getValue() { 135 return classType; 136 } 137 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)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 isSynthesized()158 public boolean isSynthesized() { 159 return synthesized; 160 } 161 setSynthesized(boolean synthesized)162 public void setSynthesized(boolean synthesized) { 163 this.synthesized = synthesized; 164 } 165 Compound(Type type, List<Pair<MethodSymbol,Attribute>> values, TypeAnnotationPosition position)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 Compound(Type type, List<Pair<MethodSymbol,Attribute>> values)174 public Compound(Type type, 175 List<Pair<MethodSymbol,Attribute>> values) { 176 this(type, values, null); 177 } 178 179 @Override getPosition()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 isContainerTypeCompound()191 public boolean isContainerTypeCompound() { 192 if (isSynthesized() && values.size() == 1) 193 return getFirstEmbeddedTC() != null; 194 return false; 195 } 196 getFirstEmbeddedTC()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 tryFixPosition()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 hasUnknownPosition()224 public boolean hasUnknownPosition() { 225 return position.type == TargetType.UNKNOWN; 226 } 227 accept(Visitor v)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) toString()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 member(Name member)266 public Attribute member(Name member) { 267 Pair<MethodSymbol,Attribute> res = getElemPair(member); 268 return res == null ? null : res.snd; 269 } 270 getElemPair(Name member)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) getValue()278 public Attribute.Compound getValue() { 279 return this; 280 } 281 282 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)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) getAnnotationType()288 public DeclaredType getAnnotationType() { 289 return (DeclaredType) type; 290 } 291 292 @DefinedBy(Api.LANGUAGE_MODEL) getElementValues()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 { TypeCompound(Compound compound, TypeAnnotationPosition position)302 public TypeCompound(Compound compound, 303 TypeAnnotationPosition position) { 304 super(compound.type, compound.values, position); 305 } 306 TypeCompound(Type type, List<Pair<MethodSymbol,Attribute>> values, TypeAnnotationPosition position)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; Array(Type type, Attribute[] values)318 public Array(Type type, Attribute[] values) { 319 super(type); 320 this.values = values; 321 } 322 Array(Type type, List<Attribute> values)323 public Array(Type type, List<Attribute> values) { 324 super(type); 325 this.values = values.toArray(new Attribute[values.size()]); 326 } 327 accept(Visitor v)328 public void accept(Visitor v) { v.visitArray(this); } 329 @DefinedBy(Api.LANGUAGE_MODEL) toString()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) getValue()344 public List<Attribute> getValue() { 345 return List.from(values); 346 } 347 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)348 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 349 return v.visitArray(getValue(), p); 350 } 351 352 @Override getPosition()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; Enum(Type type, VarSymbol value)365 public Enum(Type type, VarSymbol value) { 366 super(type); 367 this.value = Assert.checkNonNull(value); 368 } accept(Visitor v)369 public void accept(Visitor v) { v.visitEnum(this); } 370 @DefinedBy(Api.LANGUAGE_MODEL) toString()371 public String toString() { 372 return value.toString(); 373 } 374 @DefinedBy(Api.LANGUAGE_MODEL) getValue()375 public VarSymbol getValue() { 376 return value; 377 } 378 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)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 { Error(Type type)385 public Error(Type type) { 386 super(type); 387 } accept(Visitor v)388 public void accept(Visitor v) { v.visitError(this); } 389 @DefinedBy(Api.LANGUAGE_MODEL) toString()390 public String toString() { 391 return "<error>"; 392 } 393 @DefinedBy(Api.LANGUAGE_MODEL) getValue()394 public String getValue() { 395 return toString(); 396 } 397 @DefinedBy(Api.LANGUAGE_MODEL) accept(AnnotationValueVisitor<R, P> v, P p)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; UnresolvedClass(Type type, 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 { visitConstant(Attribute.Constant value)413 void visitConstant(Attribute.Constant value); visitClass(Attribute.Class clazz)414 void visitClass(Attribute.Class clazz); visitCompound(Attribute.Compound compound)415 void visitCompound(Attribute.Compound compound); visitArray(Attribute.Array array)416 void visitArray(Attribute.Array array); visitEnum(Attribute.Enum e)417 void visitEnum(Attribute.Enum e); visitError(Attribute.Error 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 } 428