test/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java

Tue, 12 Mar 2013 17:39:34 +0100

author
jfranck
date
Tue, 12 Mar 2013 17:39:34 +0100
changeset 1629
f427043f8c65
parent 1534
bec996065c45
child 1755
ddb4a2bfcd82
permissions
-rw-r--r--

7196531: Duplicate error messages on repeating annotations
Reviewed-by: jjg

jjg@1521 1 /*
darcy@1534 2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
jjg@1521 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@1521 4 *
jjg@1521 5 * This code is free software; you can redistribute it and/or modify it
jjg@1521 6 * under the terms of the GNU General Public License version 2 only, as
jjg@1521 7 * published by the Free Software Foundation.
jjg@1521 8 *
jjg@1521 9 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@1521 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@1521 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@1521 12 * version 2 for more details (a copy is included in the LICENSE file that
jjg@1521 13 * accompanied this code).
jjg@1521 14 *
jjg@1521 15 * You should have received a copy of the GNU General Public License version
jjg@1521 16 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@1521 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@1521 18 *
jjg@1521 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@1521 20 * or visit www.oracle.com if you need additional information or have any
jjg@1521 21 * questions.
jjg@1521 22 */
jjg@1521 23
jjg@1521 24 import java.util.ArrayList;
jjg@1521 25 import java.util.Arrays;
jjg@1521 26 import java.util.List;
jjg@1521 27 import java.util.Map;
jjg@1521 28
jjg@1521 29 import com.sun.tools.classfile.Attribute;
jjg@1521 30 import com.sun.tools.classfile.ClassFile;
jjg@1521 31 import com.sun.tools.classfile.TypeAnnotation;
jjg@1521 32 import com.sun.tools.classfile.Field;
jjg@1521 33 import com.sun.tools.classfile.Method;
jjg@1521 34 import com.sun.tools.classfile.RuntimeTypeAnnotations_attribute;
jjg@1521 35 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
jjg@1521 36 import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
jjg@1521 37
jjg@1521 38 public class ReferenceInfoUtil {
jjg@1521 39
jjg@1521 40 public static final int IGNORE_VALUE = -321;
jjg@1521 41
jjg@1521 42 public static List<TypeAnnotation> extendedAnnotationsOf(ClassFile cf) {
jjg@1521 43 List<TypeAnnotation> annos = new ArrayList<TypeAnnotation>();
jjg@1521 44 findAnnotations(cf, annos);
jjg@1521 45 return annos;
jjg@1521 46 }
jjg@1521 47
jjg@1521 48 /////////////////// Extract type annotations //////////////////
jjg@1521 49 private static void findAnnotations(ClassFile cf, List<TypeAnnotation> annos) {
jjg@1521 50 findAnnotations(cf, Attribute.RuntimeVisibleTypeAnnotations, annos);
jjg@1521 51 findAnnotations(cf, Attribute.RuntimeInvisibleTypeAnnotations, annos);
jjg@1521 52
jjg@1521 53 for (Field f : cf.fields) {
jjg@1521 54 findAnnotations(cf, f, annos);
jjg@1521 55 }
jjg@1521 56 for (Method m: cf.methods) {
jjg@1521 57 findAnnotations(cf, m, annos);
jjg@1521 58 }
jjg@1521 59 }
jjg@1521 60
jjg@1521 61 private static void findAnnotations(ClassFile cf, Method m, List<TypeAnnotation> annos) {
jjg@1521 62 findAnnotations(cf, m, Attribute.RuntimeVisibleTypeAnnotations, annos);
jjg@1521 63 findAnnotations(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, annos);
jjg@1521 64 }
jjg@1521 65
jjg@1521 66 private static void findAnnotations(ClassFile cf, Field m, List<TypeAnnotation> annos) {
jjg@1521 67 findAnnotations(cf, m, Attribute.RuntimeVisibleTypeAnnotations, annos);
jjg@1521 68 findAnnotations(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, annos);
jjg@1521 69 }
jjg@1521 70
jjg@1521 71 // test the result of Attributes.getIndex according to expectations
jjg@1521 72 // encoded in the method's name
jjg@1521 73 private static void findAnnotations(ClassFile cf, String name, List<TypeAnnotation> annos) {
jjg@1521 74 int index = cf.attributes.getIndex(cf.constant_pool, name);
jjg@1521 75 if (index != -1) {
jjg@1521 76 Attribute attr = cf.attributes.get(index);
jjg@1521 77 assert attr instanceof RuntimeTypeAnnotations_attribute;
jjg@1521 78 RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
jjg@1521 79 annos.addAll(Arrays.asList(tAttr.annotations));
jjg@1521 80 }
jjg@1521 81 }
jjg@1521 82
jjg@1521 83 // test the result of Attributes.getIndex according to expectations
jjg@1521 84 // encoded in the method's name
jjg@1521 85 private static void findAnnotations(ClassFile cf, Method m, String name, List<TypeAnnotation> annos) {
jjg@1521 86 int index = m.attributes.getIndex(cf.constant_pool, name);
jjg@1521 87 if (index != -1) {
jjg@1521 88 Attribute attr = m.attributes.get(index);
jjg@1521 89 assert attr instanceof RuntimeTypeAnnotations_attribute;
jjg@1521 90 RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
jjg@1521 91 annos.addAll(Arrays.asList(tAttr.annotations));
jjg@1521 92 }
jjg@1521 93 }
jjg@1521 94
jjg@1521 95 // test the result of Attributes.getIndex according to expectations
jjg@1521 96 // encoded in the method's name
jjg@1521 97 private static void findAnnotations(ClassFile cf, Field m, String name, List<TypeAnnotation> annos) {
jjg@1521 98 int index = m.attributes.getIndex(cf.constant_pool, name);
jjg@1521 99 if (index != -1) {
jjg@1521 100 Attribute attr = m.attributes.get(index);
jjg@1521 101 assert attr instanceof RuntimeTypeAnnotations_attribute;
jjg@1521 102 RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
jjg@1521 103 annos.addAll(Arrays.asList(tAttr.annotations));
jjg@1521 104 }
jjg@1521 105 }
jjg@1521 106
jjg@1521 107 /////////////////// TA Position Builder ///////////////////////
jjg@1521 108 /* TODO: comment out this dead code. Was this unfinished code that was
jjg@1521 109 * supposed to be used somewhere? The tests pass without this.
jjg@1521 110 private static class TAPositionBuilder {
jjg@1521 111 private TypeAnnotation.Position pos = new TypeAnnotation.Position();
jjg@1521 112
jjg@1521 113 private TAPositionBuilder() { }
jjg@1521 114
jjg@1521 115 public TypeAnnotation.Position build() { return pos; }
jjg@1521 116
jjg@1521 117 public static TAPositionBuilder ofType(TypeAnnotation.TargetType type) {
jjg@1521 118 TAPositionBuilder builder = new TAPositionBuilder();
jjg@1521 119 builder.pos.type = type;
jjg@1521 120 return builder;
jjg@1521 121 }
jjg@1521 122
jjg@1521 123 public TAPositionBuilder atOffset(int offset) {
jjg@1521 124 switch (pos.type) {
jjg@1521 125 // type cast
jjg@1521 126 case TYPECAST:
jjg@1521 127 // instanceof
jjg@1521 128 case INSTANCEOF:
jjg@1521 129 // new expression
jjg@1521 130 case NEW:
jjg@1521 131 pos.offset = offset;
jjg@1521 132 break;
jjg@1521 133 default:
jjg@1521 134 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 135 }
jjg@1521 136 return this;
jjg@1521 137 }
jjg@1521 138
jjg@1521 139 public TAPositionBuilder atLocalPosition(int offset, int length, int index) {
jjg@1521 140 switch (pos.type) {
jjg@1521 141 // local variable
jjg@1521 142 case LOCAL_VARIABLE:
jjg@1521 143 pos.lvarOffset = new int[] { offset };
jjg@1521 144 pos.lvarLength = new int[] { length };
jjg@1521 145 pos.lvarIndex = new int[] { index };
jjg@1521 146 break;
jjg@1521 147 default:
jjg@1521 148 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 149 }
jjg@1521 150 return this;
jjg@1521 151 }
jjg@1521 152
jjg@1521 153 public TAPositionBuilder atParameterIndex(int index) {
jjg@1521 154 switch (pos.type) {
jjg@1521 155 // type parameters
jjg@1521 156 case CLASS_TYPE_PARAMETER:
jjg@1521 157 case METHOD_TYPE_PARAMETER:
jjg@1521 158 // method parameter
jjg@1521 159 case METHOD_FORMAL_PARAMETER:
jjg@1521 160 pos.parameter_index = index;
jjg@1521 161 break;
jjg@1521 162 default:
jjg@1521 163 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 164 }
jjg@1521 165 return this;
jjg@1521 166 }
jjg@1521 167
jjg@1521 168 public TAPositionBuilder atParamBound(int param, int bound) {
jjg@1521 169 switch (pos.type) {
jjg@1521 170 // type parameters bounds
jjg@1521 171 case CLASS_TYPE_PARAMETER_BOUND:
jjg@1521 172 case METHOD_TYPE_PARAMETER_BOUND:
jjg@1521 173 pos.parameter_index = param;
jjg@1521 174 pos.bound_index = bound;
jjg@1521 175 break;
jjg@1521 176 default:
jjg@1521 177 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 178 }
jjg@1521 179 return this;
jjg@1521 180 }
jjg@1521 181
jjg@1521 182 public TAPositionBuilder atWildcardPosition(TypeAnnotation.Position pos) {
jjg@1521 183 switch (pos.type) {
jjg@1521 184 // wildcards
jjg@1521 185 case WILDCARD_BOUND:
jjg@1521 186 pos.wildcard_position = pos;
jjg@1521 187 break;
jjg@1521 188 default:
jjg@1521 189 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 190 }
jjg@1521 191 return this;
jjg@1521 192 }
jjg@1521 193
jjg@1521 194 public TAPositionBuilder atTypeIndex(int index) {
jjg@1521 195 switch (pos.type) {
jjg@1521 196 // class extends or implements clauses
jjg@1521 197 case CLASS_EXTENDS:
jjg@1521 198 // throws
jjg@1521 199 case THROWS:
jjg@1521 200 pos.type_index = index;
jjg@1521 201 break;
jjg@1521 202 default:
jjg@1521 203 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 204 }
jjg@1521 205 return this;
jjg@1521 206 }
jjg@1521 207
jjg@1521 208 public TAPositionBuilder atOffsetWithIndex(int offset, int index) {
jjg@1521 209 switch (pos.type) {
jjg@1521 210 // method type argument: wasn't specified
jjg@1521 211 case NEW_TYPE_ARGUMENT:
jjg@1521 212 case METHOD_TYPE_ARGUMENT:
jjg@1521 213 pos.offset = offset;
jjg@1521 214 pos.type_index = index;
jjg@1521 215 break;
jjg@1521 216 default:
jjg@1521 217 throw new IllegalArgumentException("invalid field for given type: " + pos.type);
jjg@1521 218 }
jjg@1521 219 return this;
jjg@1521 220 }
jjg@1521 221
jjg@1521 222 public TAPositionBuilder atGenericLocation(Integer ...loc) {
jjg@1521 223 pos.location = Arrays.asList(loc);
jjg@1521 224 pos.type = pos.type.getGenericComplement();
jjg@1521 225 return this;
jjg@1521 226 }
jjg@1521 227 }*/
jjg@1521 228
jjg@1521 229 /////////////////////// Equality testing /////////////////////
jjg@1521 230 private static boolean areEquals(int a, int b) {
jjg@1521 231 return a == b || a == IGNORE_VALUE || b == IGNORE_VALUE;
jjg@1521 232 }
jjg@1521 233
jjg@1521 234 private static boolean areEquals(int[] a, int[] a2) {
jjg@1521 235 if (a==a2)
jjg@1521 236 return true;
jjg@1521 237 if (a==null || a2==null)
jjg@1521 238 return false;
jjg@1521 239
jjg@1521 240 int length = a.length;
jjg@1521 241 if (a2.length != length)
jjg@1521 242 return false;
jjg@1521 243
jjg@1521 244 for (int i=0; i<length; i++)
jjg@1521 245 if (a[i] != a2[i] && a[i] != IGNORE_VALUE && a2[i] != IGNORE_VALUE)
jjg@1521 246 return false;
jjg@1521 247
jjg@1521 248 return true;
jjg@1521 249 }
jjg@1521 250
jjg@1521 251 public static boolean areEquals(TypeAnnotation.Position p1, TypeAnnotation.Position p2) {
jjg@1521 252 if (p1 == p2)
jjg@1521 253 return true;
jjg@1521 254 if (p1 == null || p2 == null)
jjg@1521 255 return false;
jjg@1521 256
jjg@1521 257 return ((p1.type == p2.type)
jjg@1521 258 && (p1.location.equals(p2.location))
jjg@1521 259 && areEquals(p1.offset, p2.offset)
jjg@1521 260 && areEquals(p1.lvarOffset, p2.lvarOffset)
jjg@1521 261 && areEquals(p1.lvarLength, p2.lvarLength)
jjg@1521 262 && areEquals(p1.lvarIndex, p2.lvarIndex)
jjg@1521 263 && areEquals(p1.bound_index, p2.bound_index)
jjg@1521 264 && areEquals(p1.parameter_index, p2.parameter_index)
jjg@1521 265 && areEquals(p1.type_index, p2.type_index)
jjg@1521 266 && areEquals(p1.exception_index, p2.exception_index));
jjg@1521 267 }
jjg@1521 268
jjg@1521 269 private static TypeAnnotation findAnnotation(String name, List<TypeAnnotation> annotations, ClassFile cf) throws InvalidIndex, UnexpectedEntry {
jjg@1521 270 String properName = "L" + name + ";";
jjg@1521 271 for (TypeAnnotation anno : annotations) {
jjg@1521 272 String actualName = cf.constant_pool.getUTF8Value(anno.annotation.type_index);
jjg@1521 273 if (properName.equals(actualName))
jjg@1521 274 return anno;
jjg@1521 275 }
jjg@1521 276 return null;
jjg@1521 277 }
jjg@1521 278
jjg@1521 279 public static boolean compare(Map<String, TypeAnnotation.Position> expectedAnnos,
jjg@1521 280 List<TypeAnnotation> actualAnnos, ClassFile cf) throws InvalidIndex, UnexpectedEntry {
jjg@1521 281 if (actualAnnos.size() != expectedAnnos.size()) {
jjg@1521 282 throw new ComparisionException("Wrong number of annotations",
jjg@1521 283 expectedAnnos,
jjg@1521 284 actualAnnos);
jjg@1521 285 }
jjg@1521 286
jjg@1521 287 for (Map.Entry<String, TypeAnnotation.Position> e : expectedAnnos.entrySet()) {
jjg@1521 288 String aName = e.getKey();
jjg@1521 289 TypeAnnotation.Position expected = e.getValue();
jjg@1521 290 TypeAnnotation actual = findAnnotation(aName, actualAnnos, cf);
jjg@1521 291 if (actual == null)
jjg@1521 292 throw new ComparisionException("Expected annotation not found: " + aName);
jjg@1521 293
jjg@1521 294 // TODO: you currently get an exception if the test case does not use all necessary
jjg@1521 295 // annotation attributes, e.g. forgetting the offset for a local variable.
jjg@1521 296 // It would be nicer to give an understandable warning instead.
jjg@1521 297 if (!areEquals(expected, actual.position)) {
jjg@1521 298 throw new ComparisionException("Unexpected position for annotation : " + aName +
jjg@1521 299 "\n Expected: " + expected.toString() +
jjg@1521 300 "\n Found: " + actual.position.toString());
jjg@1521 301 }
jjg@1521 302 }
jjg@1521 303 return true;
jjg@1521 304 }
jjg@1521 305 }
jjg@1521 306
jjg@1521 307 class ComparisionException extends RuntimeException {
jjg@1521 308 private static final long serialVersionUID = -3930499712333815821L;
jjg@1521 309
jjg@1521 310 public final Map<String, TypeAnnotation.Position> expected;
jjg@1521 311 public final List<TypeAnnotation> found;
jjg@1521 312
jjg@1521 313 public ComparisionException(String message) {
jjg@1521 314 this(message, null, null);
jjg@1521 315 }
jjg@1521 316
jjg@1521 317 public ComparisionException(String message, Map<String, TypeAnnotation.Position> expected, List<TypeAnnotation> found) {
jjg@1521 318 super(message);
jjg@1521 319 this.expected = expected;
jjg@1521 320 this.found = found;
jjg@1521 321 }
jjg@1521 322
jjg@1521 323 public String toString() {
jjg@1521 324 String str = super.toString();
jjg@1521 325 if (expected != null && found != null) {
jjg@1521 326 str += "\n\tExpected: " + expected.size() + " annotations; but found: " + found.size() + " annotations\n" +
jjg@1521 327 " Expected: " + expected +
jjg@1521 328 "\n Found: " + found;
jjg@1521 329 }
jjg@1521 330 return str;
jjg@1521 331 }
jjg@1521 332 }

mercurial