comparison graal/com.oracle.graal.java.test/src/com/oracle/graal/java/test/TestResolvedJavaType.java @ 21555:d12eaef9af72

renamed com.oracle.graal.api.meta.test to com.oracle.graal.java.test since it is Graal specific (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Tue, 26 May 2015 23:45:05 +0200
parents graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java@78f0792aa890
children 48c1ebd24120
comparison
equal deleted inserted replaced
21554:b1530a6cce8c 21555:d12eaef9af72
1 /*
2 * Copyright (c) 2012, 2014, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.graal.java.test;
24
25 import static java.lang.reflect.Modifier.*;
26 import static org.junit.Assert.*;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.net.*;
31 import java.util.*;
32
33 import org.junit.*;
34
35 import sun.reflect.ConstantPool;
36
37 import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
38 import com.oracle.graal.api.meta.*;
39 import com.oracle.jvmci.common.*;
40
41 /**
42 * Tests for {@link ResolvedJavaType}.
43 */
44 public class TestResolvedJavaType extends TypeUniverse {
45
46 public TestResolvedJavaType() {
47 }
48
49 @Test
50 public void findInstanceFieldWithOffsetTest() {
51 for (Class<?> c : classes) {
52 ResolvedJavaType type = metaAccess.lookupJavaType(c);
53 Set<Field> reflectionFields = getInstanceFields(c, true);
54 for (Field f : reflectionFields) {
55 ResolvedJavaField rf = lookupField(type.getInstanceFields(true), f);
56 assertNotNull(rf);
57 long offset = isStatic(f.getModifiers()) ? unsafe.staticFieldOffset(f) : unsafe.objectFieldOffset(f);
58 ResolvedJavaField result = type.findInstanceFieldWithOffset(offset, rf.getKind());
59 assertNotNull(result);
60 assertTrue(fieldsEqual(f, result));
61 }
62 }
63 }
64
65 @Test
66 public void isInterfaceTest() {
67 for (Class<?> c : classes) {
68 ResolvedJavaType type = metaAccess.lookupJavaType(c);
69 boolean expected = c.isInterface();
70 boolean actual = type.isInterface();
71 assertEquals(expected, actual);
72 }
73 }
74
75 @Test
76 public void isInstanceClassTest() {
77 for (Class<?> c : classes) {
78 ResolvedJavaType type = metaAccess.lookupJavaType(c);
79 boolean expected = !c.isArray() && !c.isPrimitive() && !c.isInterface();
80 boolean actual = type.isInstanceClass();
81 assertEquals(expected, actual);
82 }
83 }
84
85 @Test
86 public void isArrayTest() {
87 for (Class<?> c : classes) {
88 ResolvedJavaType type = metaAccess.lookupJavaType(c);
89 boolean expected = c.isArray();
90 boolean actual = type.isArray();
91 assertEquals(expected, actual);
92 }
93 }
94
95 @Test
96 public void getModifiersTest() {
97 for (Class<?> c : classes) {
98 ResolvedJavaType type = metaAccess.lookupJavaType(c);
99 int expected = c.getModifiers();
100 int actual = type.getModifiers();
101 assertEquals(expected, actual);
102 }
103 }
104
105 @Test
106 public void isAssignableFromTest() {
107 Class<?>[] all = classes.toArray(new Class[classes.size()]);
108 for (int i = 0; i < all.length; i++) {
109 Class<?> c1 = all[i];
110 for (int j = i; j < all.length; j++) {
111 Class<?> c2 = all[j];
112 ResolvedJavaType t1 = metaAccess.lookupJavaType(c1);
113 ResolvedJavaType t2 = metaAccess.lookupJavaType(c2);
114 boolean expected = c1.isAssignableFrom(c2);
115 boolean actual = t1.isAssignableFrom(t2);
116 assertEquals(expected, actual);
117 if (expected && t1 != t2) {
118 assertFalse(t2.isAssignableFrom(t1));
119 }
120 }
121 }
122 }
123
124 @Test
125 public void isInstanceTest() {
126 for (JavaConstant c : constants) {
127 if (c.getKind() == Kind.Object && !c.isNull()) {
128 Object o = snippetReflection.asObject(Object.class, c);
129 Class<? extends Object> cls = o.getClass();
130 while (cls != null) {
131 ResolvedJavaType type = metaAccess.lookupJavaType(cls);
132 boolean expected = cls.isInstance(o);
133 boolean actual = type.isInstance(c);
134 assertEquals(expected, actual);
135 cls = cls.getSuperclass();
136 }
137 }
138 }
139 }
140
141 private static Class<?> asExactClass(Class<?> c) {
142 if (c.isArray()) {
143 if (asExactClass(c.getComponentType()) != null) {
144 return c;
145 }
146 } else {
147 if (c.isPrimitive() || Modifier.isFinal(c.getModifiers())) {
148 return c;
149 }
150 }
151 return null;
152 }
153
154 @Test
155 public void asExactTypeTest() {
156 for (Class<?> c : classes) {
157 ResolvedJavaType type = metaAccess.lookupJavaType(c);
158 ResolvedJavaType exactType = type.asExactType();
159 Class<?> expected = asExactClass(c);
160 if (expected == null) {
161 assertTrue("exact(" + c.getName() + ") != null", exactType == null);
162 } else {
163 assertNotNull(exactType);
164 assertTrue(exactType.equals(metaAccess.lookupJavaType(expected)));
165 }
166 }
167 }
168
169 @Test
170 public void getSuperclassTest() {
171 for (Class<?> c : classes) {
172 ResolvedJavaType type = metaAccess.lookupJavaType(c);
173 Class<?> expected = c.getSuperclass();
174 ResolvedJavaType actual = type.getSuperclass();
175 if (expected == null) {
176 assertTrue(actual == null);
177 } else {
178 assertNotNull(actual);
179 assertTrue(actual.equals(metaAccess.lookupJavaType(expected)));
180 }
181 }
182 }
183
184 @Test
185 public void getInterfacesTest() {
186 for (Class<?> c : classes) {
187 ResolvedJavaType type = metaAccess.lookupJavaType(c);
188 Class<?>[] expected = c.getInterfaces();
189 ResolvedJavaType[] actual = type.getInterfaces();
190 assertEquals(expected.length, actual.length);
191 for (int i = 0; i < expected.length; i++) {
192 assertTrue(actual[i].equals(metaAccess.lookupJavaType(expected[i])));
193 }
194 }
195 }
196
197 public Class<?> getSupertype(Class<?> c) {
198 assert !c.isPrimitive();
199 if (c.isArray()) {
200 Class<?> componentType = c.getComponentType();
201 if (componentType.isPrimitive() || componentType == Object.class) {
202 return Object.class;
203 }
204 return getArrayClass(getSupertype(componentType));
205 }
206 if (c.isInterface()) {
207 return Object.class;
208 }
209 return c.getSuperclass();
210 }
211
212 public Class<?> findLeastCommonAncestor(Class<?> c1Initial, Class<?> c2Initial) {
213 if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) {
214 return null;
215 } else {
216 Class<?> c1 = c1Initial;
217 Class<?> c2 = c2Initial;
218 while (true) {
219 if (c1.isAssignableFrom(c2)) {
220 return c1;
221 }
222 if (c2.isAssignableFrom(c1)) {
223 return c2;
224 }
225 c1 = getSupertype(c1);
226 c2 = getSupertype(c2);
227 }
228 }
229 }
230
231 @Test
232 public void findLeastCommonAncestorTest() {
233 Class<?>[] all = classes.toArray(new Class[classes.size()]);
234 for (int i = 0; i < all.length; i++) {
235 Class<?> c1 = all[i];
236 for (int j = i; j < all.length; j++) {
237 Class<?> c2 = all[j];
238 ResolvedJavaType t1 = metaAccess.lookupJavaType(c1);
239 ResolvedJavaType t2 = metaAccess.lookupJavaType(c2);
240 Class<?> expected = findLeastCommonAncestor(c1, c2);
241 ResolvedJavaType actual = t1.findLeastCommonAncestor(t2);
242 if (expected == null) {
243 assertTrue(actual == null);
244 } else {
245 assertNotNull(actual);
246 assertTrue(actual.equals(metaAccess.lookupJavaType(expected)));
247 }
248 }
249 }
250 }
251
252 private static class Base {
253 }
254
255 abstract static class Abstract1 extends Base {
256 }
257
258 interface Interface1 {
259 }
260
261 static class Concrete1 extends Abstract1 {
262 }
263
264 static class Concrete2 extends Abstract1 implements Interface1 {
265 }
266
267 static class Concrete3 extends Concrete2 {
268 }
269
270 static final class Final1 extends Abstract1 {
271 }
272
273 abstract static class Abstract4 extends Concrete3 {
274 }
275
276 void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) {
277 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
278 if (leafConcreteSubtype == null) {
279 // findLeafConcreteSubtype() is conservative
280 } else {
281 if (expected == null) {
282 assertNull(leafConcreteSubtype);
283 } else {
284 assertTrue(leafConcreteSubtype.getResult().equals(expected));
285 }
286 }
287
288 if (!type.isArray()) {
289 ResolvedJavaType arrayType = type.getArrayClass();
290 AssumptionResult<ResolvedJavaType> arraySubtype = arrayType.findLeafConcreteSubtype();
291 if (arraySubtype != null) {
292 assertEquals(arraySubtype.getResult(), arrayType);
293 } else {
294 // findLeafConcreteSubtype() method is conservative
295 }
296 }
297 }
298
299 @Test
300 public void findLeafConcreteSubtypeTest() {
301 ResolvedJavaType base = metaAccess.lookupJavaType(Base.class);
302 checkConcreteSubtype(base, base);
303
304 ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class);
305 ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class);
306
307 checkConcreteSubtype(base, null);
308 checkConcreteSubtype(a1, c1);
309 checkConcreteSubtype(c1, c1);
310
311 ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class);
312 ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class);
313
314 checkConcreteSubtype(base, null);
315 checkConcreteSubtype(a1, null);
316 checkConcreteSubtype(c1, c1);
317 checkConcreteSubtype(i1, c2);
318 checkConcreteSubtype(c2, c2);
319
320 ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class);
321 checkConcreteSubtype(c2, null);
322 checkConcreteSubtype(c3, c3);
323
324 ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class);
325 checkConcreteSubtype(c3, null);
326 checkConcreteSubtype(a4, null);
327
328 ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class);
329 checkConcreteSubtype(a1a, null);
330 ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class);
331 checkConcreteSubtype(c1a, null);
332 ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class);
333 checkConcreteSubtype(f1a, f1a);
334
335 ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class);
336 checkConcreteSubtype(obja, null);
337
338 ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class);
339 checkConcreteSubtype(inta, inta);
340 }
341
342 interface NoImplementor {
343 }
344
345 interface SingleImplementorInterface {
346 }
347
348 static class SingleConcreteImplementor implements SingleImplementorInterface {
349 }
350
351 interface SingleAbstractImplementorInterface {
352 }
353
354 abstract static class SingleAbstractImplementor implements SingleAbstractImplementorInterface {
355 }
356
357 interface MultiImplementorInterface {
358 }
359
360 static class ConcreteImplementor1 implements MultiImplementorInterface {
361 }
362
363 static class ConcreteImplementor2 implements MultiImplementorInterface {
364 }
365
366 interface MultipleAbstractImplementorInterface {
367 }
368
369 abstract static class MultiAbstractImplementor1 implements MultipleAbstractImplementorInterface {
370 }
371
372 abstract static class MultiAbstractImplementor2 implements MultipleAbstractImplementorInterface {
373 }
374
375 interface SingleAbstractImplementorInterface2 {
376 }
377
378 interface ExtendedSingleImplementorInterface {
379 }
380
381 abstract static class SingleAbstractImplementor2 implements SingleAbstractImplementorInterface2 {
382 }
383
384 static class ConcreteTransitiveImplementor1 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface {
385 }
386
387 static class ConcreteTransitiveImplementor2 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface {
388 }
389
390 @Test
391 public void getSingleImplementorTest() {
392 ResolvedJavaType iNi = metaAccess.lookupJavaType(NoImplementor.class);
393 assertNull(iNi.getSingleImplementor());
394
395 ResolvedJavaType iSi = metaAccess.lookupJavaType(SingleImplementorInterface.class);
396 ResolvedJavaType cSi = metaAccess.lookupJavaType(SingleConcreteImplementor.class);
397 assertEquals(cSi, iSi.getSingleImplementor());
398
399 ResolvedJavaType iSai = metaAccess.lookupJavaType(SingleAbstractImplementorInterface.class);
400 ResolvedJavaType aSai = metaAccess.lookupJavaType(SingleAbstractImplementor.class);
401 assertEquals(aSai, iSai.getSingleImplementor());
402
403 ResolvedJavaType iMi = metaAccess.lookupJavaType(MultiImplementorInterface.class);
404 metaAccess.lookupJavaType(ConcreteImplementor1.class);
405 metaAccess.lookupJavaType(ConcreteImplementor2.class);
406 assertEquals(iMi, iMi.getSingleImplementor());
407
408 ResolvedJavaType iMai = metaAccess.lookupJavaType(MultipleAbstractImplementorInterface.class);
409 metaAccess.lookupJavaType(MultiAbstractImplementor1.class);
410 metaAccess.lookupJavaType(MultiAbstractImplementor2.class);
411 assertEquals(iMai, iMai.getSingleImplementor());
412
413 ResolvedJavaType iSai2 = metaAccess.lookupJavaType(SingleAbstractImplementorInterface2.class);
414 ResolvedJavaType aSai2 = metaAccess.lookupJavaType(SingleAbstractImplementor2.class);
415 metaAccess.lookupJavaType(ConcreteTransitiveImplementor1.class);
416 metaAccess.lookupJavaType(ConcreteTransitiveImplementor2.class);
417 assertEquals(aSai2, iSai2.getSingleImplementor());
418 }
419
420 @Test(expected = JVMCIError.class)
421 public void getSingleImplementorTestClassReceiver() {
422 ResolvedJavaType base = metaAccess.lookupJavaType(Base.class);
423 base.getSingleImplementor();
424 }
425
426 @Test(expected = JVMCIError.class)
427 public void getSingleImplementorTestPrimitiveReceiver() {
428 ResolvedJavaType primitive = metaAccess.lookupJavaType(int.class);
429 primitive.getSingleImplementor();
430 }
431
432 @Test
433 public void getComponentTypeTest() {
434 for (Class<?> c : classes) {
435 ResolvedJavaType type = metaAccess.lookupJavaType(c);
436 Class<?> expected = c.getComponentType();
437 ResolvedJavaType actual = type.getComponentType();
438 if (expected == null) {
439 assertNull(actual);
440 } else {
441 assertTrue(actual.equals(metaAccess.lookupJavaType(expected)));
442 }
443 }
444 }
445
446 @Test
447 public void getArrayClassTest() {
448 for (Class<?> c : classes) {
449 if (c != void.class) {
450 ResolvedJavaType type = metaAccess.lookupJavaType(c);
451 Class<?> expected = getArrayClass(c);
452 ResolvedJavaType actual = type.getArrayClass();
453 assertTrue(actual.equals(metaAccess.lookupJavaType(expected)));
454 }
455 }
456 }
457
458 static class Declarations {
459
460 final Method implementation;
461 final Set<Method> declarations;
462
463 public Declarations(Method impl) {
464 this.implementation = impl;
465 declarations = new HashSet<>();
466 }
467 }
468
469 /**
470 * See <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.5">Method
471 * overriding</a>.
472 */
473 static boolean isOverriderOf(Method impl, Method m) {
474 if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) {
475 if (m.getName().equals(impl.getName())) {
476 if (m.getReturnType() == impl.getReturnType()) {
477 if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) {
478 if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) {
479 // m is public or protected
480 return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers());
481 } else {
482 // m is package-private
483 return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage();
484 }
485 }
486 }
487 }
488 }
489 return false;
490 }
491
492 static final Map<Class<?>, VTable> vtables = new HashMap<>();
493
494 static class VTable {
495
496 final Map<NameAndSignature, Method> methods = new HashMap<>();
497 }
498
499 static synchronized VTable getVTable(Class<?> c) {
500 VTable vtable = vtables.get(c);
501 if (vtable == null) {
502 vtable = new VTable();
503 if (c != Object.class) {
504 VTable superVtable = getVTable(c.getSuperclass());
505 vtable.methods.putAll(superVtable.methods);
506 }
507 for (Method m : c.getDeclaredMethods()) {
508 if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) {
509 if (isAbstract(m.getModifiers())) {
510 // A subclass makes a concrete method in a superclass abstract
511 vtable.methods.remove(new NameAndSignature(m));
512 } else {
513 vtable.methods.put(new NameAndSignature(m), m);
514 }
515 }
516 }
517 vtables.put(c, vtable);
518 }
519 return vtable;
520 }
521
522 static Set<Method> findDeclarations(Method impl, Class<?> c) {
523 Set<Method> declarations = new HashSet<>();
524 NameAndSignature implSig = new NameAndSignature(impl);
525 if (c != null) {
526 for (Method m : c.getDeclaredMethods()) {
527 if (new NameAndSignature(m).equals(implSig)) {
528 declarations.add(m);
529 break;
530 }
531 }
532 if (!c.isInterface()) {
533 declarations.addAll(findDeclarations(impl, c.getSuperclass()));
534 }
535 for (Class<?> i : c.getInterfaces()) {
536 declarations.addAll(findDeclarations(impl, i));
537 }
538 }
539 return declarations;
540 }
541
542 private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
543 ResolvedJavaMethod impl = type.resolveConcreteMethod(decl, context);
544 assertEquals(expected, impl);
545 }
546
547 @Test
548 public void resolveMethodTest() {
549 ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class);
550 for (Class<?> c : classes) {
551 if (c.isInterface() || c.isPrimitive()) {
552 ResolvedJavaType type = metaAccess.lookupJavaType(c);
553 for (Method m : c.getDeclaredMethods()) {
554 if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) {
555 ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m);
556 ResolvedJavaMethod impl = type.resolveMethod(resolved, context, true);
557 ResolvedJavaMethod expected = resolved.isDefault() || resolved.isAbstract() ? resolved : null;
558 assertEquals(m.toString(), expected, impl);
559 } else {
560 // As of JDK 8, interfaces can have static and private methods
561 }
562 }
563 } else {
564 ResolvedJavaType type = metaAccess.lookupJavaType(c);
565 VTable vtable = getVTable(c);
566 for (Method impl : vtable.methods.values()) {
567 Set<Method> decls = findDeclarations(impl, c);
568 for (Method decl : decls) {
569 ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
570 if (m.isPublic()) {
571 ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
572 checkResolveMethod(type, context, m, i);
573 }
574 }
575 }
576 }
577 }
578 }
579
580 @Test
581 public void resolveConcreteMethodTest() {
582 ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class);
583 for (Class<?> c : classes) {
584 if (c.isInterface() || c.isPrimitive()) {
585 ResolvedJavaType type = metaAccess.lookupJavaType(c);
586 for (Method m : c.getDeclaredMethods()) {
587 if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) {
588 ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m);
589 ResolvedJavaMethod impl = type.resolveConcreteMethod(resolved, context);
590 ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null;
591 assertEquals(m.toString(), expected, impl);
592 } else {
593 // As of JDK 8, interfaces can have static and private methods
594 }
595 }
596 } else {
597 ResolvedJavaType type = metaAccess.lookupJavaType(c);
598 VTable vtable = getVTable(c);
599 for (Method impl : vtable.methods.values()) {
600 Set<Method> decls = findDeclarations(impl, c);
601 for (Method decl : decls) {
602 ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
603 if (m.isPublic()) {
604 ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
605 checkResolveMethod(type, context, m, i);
606 }
607 }
608 }
609 for (Method m : c.getDeclaredMethods()) {
610 ResolvedJavaMethod impl = type.resolveConcreteMethod(metaAccess.lookupJavaMethod(m), context);
611 ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl;
612 assertEquals(type + " " + m.toString(), expected, impl);
613 }
614 }
615 }
616 }
617
618 @Test
619 public void findUniqueConcreteMethodTest() throws NoSuchMethodException {
620 ResolvedJavaMethod thisMethod = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest"));
621 ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod).getResult();
622 assertEquals(thisMethod, ucm);
623 }
624
625 public static Set<Field> getInstanceFields(Class<?> c, boolean includeSuperclasses) {
626 if (c.isArray() || c.isPrimitive() || c.isInterface()) {
627 return Collections.emptySet();
628 }
629 Set<Field> result = new HashSet<>();
630 for (Field f : c.getDeclaredFields()) {
631 if (!Modifier.isStatic(f.getModifiers())) {
632 result.add(f);
633 }
634 }
635 if (includeSuperclasses && c != Object.class) {
636 result.addAll(getInstanceFields(c.getSuperclass(), true));
637 }
638 return result;
639 }
640
641 public static Set<Field> getStaticFields(Class<?> c) {
642 Set<Field> result = new HashSet<>();
643 for (Field f : c.getDeclaredFields()) {
644 if (Modifier.isStatic(f.getModifiers())) {
645 result.add(f);
646 }
647 }
648 return result;
649 }
650
651 public boolean fieldsEqual(Field f, ResolvedJavaField rjf) {
652 return rjf.getDeclaringClass().equals(metaAccess.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) &&
653 rjf.getType().resolve(rjf.getDeclaringClass()).equals(metaAccess.lookupJavaType(f.getType()));
654 }
655
656 public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) {
657 for (ResolvedJavaField rf : fields) {
658 if (fieldsEqual(key, rf)) {
659 return rf;
660 }
661 }
662 return null;
663 }
664
665 public Field lookupField(Set<Field> fields, ResolvedJavaField key) {
666 for (Field f : fields) {
667 if (fieldsEqual(f, key)) {
668 return f;
669 }
670 }
671 return null;
672 }
673
674 private boolean isHiddenFromReflection(ResolvedJavaField f) {
675 if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Throwable.class)) && f.getName().equals("backtrace")) {
676 return true;
677 }
678 if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(ConstantPool.class)) && f.getName().equals("constantPoolOop")) {
679 return true;
680 }
681 if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class)) && f.getName().equals("classLoader")) {
682 return true;
683 }
684 return false;
685 }
686
687 @Test
688 public void getInstanceFieldsTest() {
689 for (Class<?> c : classes) {
690 ResolvedJavaType type = metaAccess.lookupJavaType(c);
691 for (boolean includeSuperclasses : new boolean[]{true, false}) {
692 Set<Field> expected = getInstanceFields(c, includeSuperclasses);
693 ResolvedJavaField[] actual = type.getInstanceFields(includeSuperclasses);
694 for (Field f : expected) {
695 assertNotNull(lookupField(actual, f));
696 }
697 for (ResolvedJavaField rf : actual) {
698 if (!isHiddenFromReflection(rf)) {
699 assertEquals(rf.toString(), lookupField(expected, rf) != null, !rf.isInternal());
700 }
701 }
702
703 // Test stability of getInstanceFields
704 ResolvedJavaField[] actual2 = type.getInstanceFields(includeSuperclasses);
705 assertArrayEquals(actual, actual2);
706 }
707 }
708 }
709
710 @Test
711 public void getStaticFieldsTest() {
712 for (Class<?> c : classes) {
713 ResolvedJavaType type = metaAccess.lookupJavaType(c);
714 Set<Field> expected = getStaticFields(c);
715 ResolvedJavaField[] actual = type.getStaticFields();
716 for (Field f : expected) {
717 assertNotNull(lookupField(actual, f));
718 }
719 for (ResolvedJavaField rf : actual) {
720 if (!isHiddenFromReflection(rf)) {
721 assertEquals(lookupField(expected, rf) != null, !rf.isInternal());
722 }
723 }
724
725 // Test stability of getStaticFields
726 ResolvedJavaField[] actual2 = type.getStaticFields();
727 assertArrayEquals(actual, actual2);
728 }
729 }
730
731 @Test
732 public void getDeclaredMethodsTest() {
733 for (Class<?> c : classes) {
734 ResolvedJavaType type = metaAccess.lookupJavaType(c);
735 Method[] raw = c.getDeclaredMethods();
736 Set<ResolvedJavaMethod> expected = new HashSet<>();
737 for (Method m : raw) {
738 ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(m);
739 assertNotNull(resolvedMethod);
740 expected.add(resolvedMethod);
741 }
742 Set<ResolvedJavaMethod> actual = new HashSet<>(Arrays.asList(type.getDeclaredMethods()));
743 assertEquals(expected, actual);
744 }
745 }
746
747 static class A {
748 static String name = "foo";
749 }
750
751 static class B extends A {
752 }
753
754 static class C {
755 }
756
757 static class D {
758 void foo() {
759 // use of assertions causes the class to have a <clinit>
760 assert getClass() != null;
761 }
762 }
763
764 @Test
765 public void getClassInitializerTest() {
766 assertNotNull(metaAccess.lookupJavaType(A.class).getClassInitializer());
767 assertNotNull(metaAccess.lookupJavaType(D.class).getClassInitializer());
768 assertNull(metaAccess.lookupJavaType(B.class).getClassInitializer());
769 assertNull(metaAccess.lookupJavaType(C.class).getClassInitializer());
770 assertNull(metaAccess.lookupJavaType(int.class).getClassInitializer());
771 assertNull(metaAccess.lookupJavaType(void.class).getClassInitializer());
772 }
773
774 @Test
775 public void getAnnotationTest() {
776 for (Class<?> c : classes) {
777 ResolvedJavaType type = metaAccess.lookupJavaType(c);
778 for (Annotation a : c.getAnnotations()) {
779 assertEquals(a, type.getAnnotation(a.annotationType()));
780 }
781 }
782 }
783
784 @Test
785 public void memberClassesTest() {
786 for (Class<?> c : classes) {
787 ResolvedJavaType type = metaAccess.lookupJavaType(c);
788 assertEquals(c.isLocalClass(), type.isLocal());
789 assertEquals(c.isMemberClass(), type.isMember());
790 Class<?> enclc = c.getEnclosingClass();
791 ResolvedJavaType enclt = type.getEnclosingType();
792 assertFalse(enclc == null ^ enclt == null);
793 if (enclc != null) {
794 assertEquals(enclt, metaAccess.lookupJavaType(enclc));
795 }
796 }
797 }
798
799 @Test
800 public void classFilePathTest() {
801 for (Class<?> c : classes) {
802 ResolvedJavaType type = metaAccess.lookupJavaType(c);
803 URL path = type.getClassFilePath();
804 if (type.isPrimitive() || type.isArray()) {
805 assertEquals(null, path);
806 } else {
807 assertNotNull(path);
808 String pathString = path.getPath();
809 if (type.isLocal() || type.isMember()) {
810 assertTrue(pathString.indexOf('$') > 0);
811 }
812 }
813 }
814 }
815
816 @Test
817 public void isTrustedInterfaceTypeTest() {
818 for (Class<?> c : classes) {
819 ResolvedJavaType type = metaAccess.lookupJavaType(c);
820 if (TrustedInterface.class.isAssignableFrom(c)) {
821 assertTrue(type.isTrustedInterfaceType());
822 }
823 }
824 }
825
826 private Method findTestMethod(Method apiMethod) {
827 String testName = apiMethod.getName() + "Test";
828 for (Method m : getClass().getDeclaredMethods()) {
829 if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) {
830 return m;
831 }
832 }
833 return null;
834 }
835
836 // @formatter:off
837 private static final String[] untestedApiMethods = {
838 "initialize",
839 "isPrimitive",
840 "newArray",
841 "getDeclaredConstructors",
842 "isInitialized",
843 "isLinked",
844 "getJavaClass",
845 "getObjectHub",
846 "hasFinalizableSubclass",
847 "hasFinalizer",
848 "getSourceFileName",
849 "getClassFilePath",
850 "isLocal",
851 "isJavaLangObject",
852 "isMember",
853 "getElementalType",
854 "getEnclosingType",
855 "$jacocoInit"
856 };
857 // @formatter:on
858
859 /**
860 * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written
861 * for them or are added to {@link #untestedApiMethods}.
862 */
863 @Test
864 public void testCoverage() {
865 Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods));
866 for (Method m : ResolvedJavaType.class.getDeclaredMethods()) {
867 if (findTestMethod(m) == null) {
868 assertTrue("test missing for " + m, known.contains(m.getName()));
869 } else {
870 assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName()));
871 }
872 }
873 }
874 }