|
1 /* |
|
2 * Copyright (c) 2009, 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. |
|
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 package invokevirtual; |
|
26 |
|
27 import java.lang.reflect.Method; |
|
28 import java.lang.reflect.Modifier; |
|
29 |
|
30 |
|
31 public class Checker extends shared.Checker { |
|
32 public Checker(Class staticTargetClass, Class dynamicTargetClass) { |
|
33 super(staticTargetClass, dynamicTargetClass); |
|
34 } |
|
35 |
|
36 public String check (Class callerClass) { |
|
37 Method m; |
|
38 try { |
|
39 // May cause java.lang.VerifyError |
|
40 m = getOverriddenMethod(); |
|
41 } catch (Throwable e) { |
|
42 return e.getClass().getName(); |
|
43 } |
|
44 |
|
45 // Check method accessibility (it's a static property, according to JLS #6.6: Access Control) |
|
46 if (m != null) { |
|
47 Method staticTargetMethod = getDeclaredMethod(staticTargetClass); |
|
48 |
|
49 if (checkAccess(staticTargetMethod, callerClass)) { |
|
50 // Can't invoke abstract method |
|
51 if ( Modifier.isAbstract(m.getModifiers())) { |
|
52 return "java.lang.AbstractMethodError"; |
|
53 } |
|
54 |
|
55 return String.format("%s.%s" |
|
56 , m.getDeclaringClass().getSimpleName() |
|
57 , methodName |
|
58 ); |
|
59 } else { |
|
60 // if method isn't accessible, IllegalAccessError is thrown |
|
61 return "java.lang.IllegalAccessError"; |
|
62 } |
|
63 } else { |
|
64 // if method == null, NoSuchMethodError is thrown |
|
65 return "java.lang.NoSuchMethodError"; |
|
66 } |
|
67 } |
|
68 |
|
69 public Method getOverriddenMethod() { |
|
70 return getOverriddenMethod(staticTargetClass, dynamicTargetClass); |
|
71 } |
|
72 |
|
73 public Method getOverriddenMethod(Class staticTarget, Class dynamicTarget) { |
|
74 // Assertion #1. C is a subclass of A |
|
75 if (!staticTarget.isAssignableFrom(dynamicTarget)) { |
|
76 return null; |
|
77 } |
|
78 |
|
79 Method staticTargetMethod = getDeclaredMethod(staticTarget); |
|
80 Method dynamicTargetMethod = getDeclaredMethod(dynamicTarget); |
|
81 |
|
82 if (staticTarget.equals(dynamicTarget)) { |
|
83 return staticTargetMethod; |
|
84 } |
|
85 |
|
86 // TODO: ? need to find out the right behavior |
|
87 if (staticTargetMethod == null) { |
|
88 return null; |
|
89 } |
|
90 |
|
91 // Dynamic target doesn't have desired method, so check its superclass |
|
92 if (dynamicTargetMethod == null) { |
|
93 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); |
|
94 } else { |
|
95 // Private method can't override anything |
|
96 if (Modifier.isPrivate(dynamicTargetMethod.getModifiers())) { |
|
97 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); |
|
98 } |
|
99 } |
|
100 |
|
101 // TODO: abstract methods |
|
102 |
|
103 //Assertion #3.a: A.m2 is PUB || PROT || (PP && PKG(A) == PKG(C)) |
|
104 int staticTargetModifiers = staticTargetMethod.getModifiers(); |
|
105 { |
|
106 boolean isPublic = Modifier.isPublic(staticTargetModifiers); |
|
107 boolean isProtected = Modifier.isProtected(staticTargetModifiers); |
|
108 boolean isPrivate = Modifier.isPrivate(staticTargetModifiers) ; |
|
109 String staticTargetPkg = getClassPackageName(staticTarget); |
|
110 String dynamicTargetPkg = getClassPackageName(dynamicTarget); |
|
111 |
|
112 if (isPublic || isProtected |
|
113 || (!isPublic && !isProtected && !isPrivate |
|
114 && staticTargetPkg.equals(dynamicTargetPkg))) { |
|
115 return dynamicTargetMethod; |
|
116 } |
|
117 } |
|
118 // OR |
|
119 //Assertion #3.b: exists m3: C.m1 != B.m3, A.m2 != B.m3, B.m3 overrides A.m2, C.m1 overrides B.m3 |
|
120 Class ancestor = dynamicTarget.getSuperclass(); |
|
121 while (ancestor != staticTarget) { |
|
122 Method OverriddenM2 = getOverriddenMethod(staticTarget, ancestor); |
|
123 Method m3 = getDeclaredMethod(ancestor); |
|
124 Method m1 = getOverriddenMethod(ancestor, dynamicTarget); |
|
125 |
|
126 if (m1 != null && m3 != null) { |
|
127 if (m1.equals(dynamicTargetMethod) && m3.equals(OverriddenM2)) { |
|
128 return dynamicTargetMethod; |
|
129 } |
|
130 } else { |
|
131 if (m1 == null && dynamicTargetMethod == null |
|
132 && m3 == null && OverriddenM2 == null) |
|
133 { |
|
134 return null; |
|
135 } |
|
136 } |
|
137 |
|
138 ancestor = ancestor.getSuperclass(); |
|
139 } |
|
140 |
|
141 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); |
|
142 } |
|
143 } |