comparison jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @ 22672:1bbd4a7c274b

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