ReflectionVisitor.java revision 3170:dc017a37aac5
1/* 2 * Copyright (c) 2013, 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 24import java.io.*; 25import java.lang.reflect.*; 26 27/** 28 * Test MethodParameter attributs by reflection API 29 */ 30public class ReflectionVisitor extends Tester.Visitor { 31 32 public ReflectionVisitor(Tester tester) { 33 super(tester); 34 } 35 36 public void error(String msg) { 37 super.error("reflection: " + msg); 38 } 39 40 public void warn(String msg) { 41 super.warn("reflection: " + msg); 42 } 43 44 boolean isEnum; 45 boolean isInterface; 46 boolean isAnon; 47 boolean isLocal; 48 boolean isMember; 49 boolean isStatic; 50 boolean isPublic; 51 boolean isFinal; 52 Class clazz; 53 StringBuilder sb; 54 55 /** 56 * Read class using {@code ClassFile}, and generate a list of methods 57 * with parameter names as available in the MethodParameters attribute. 58 */ 59 void visitClass(final String cl, final File cfile, final StringBuilder sb) 60 throws Exception { 61 62 this.sb = sb; 63 clazz = Class.forName(cl); 64 isEnum = clazz.isEnum(); 65 isInterface = clazz.isInterface(); 66 isAnon = clazz.isAnonymousClass(); 67 isLocal = clazz.isLocalClass(); 68 isMember = clazz.isMemberClass(); 69 isStatic = ((clazz.getModifiers() & Modifier.STATIC) != 0); 70 isPublic = ((clazz.getModifiers() & Modifier.PUBLIC) != 0); 71 72 sb.append(isStatic ? "static " : "") 73 .append(isPublic ? "public " : "") 74 .append(isEnum ? "enum " : isInterface ? "interface " : "class ") 75 .append(cl).append(" -- ") 76 .append(isMember? "inner" : "" ) 77 .append(isLocal? "inner" : "" ) 78 .append(isAnon ? "anon" : "") 79 .append("\n"); 80 81 for (Constructor c : clazz.getDeclaredConstructors()) { 82 testConstructor(c); 83 } 84 85 for (Method m :clazz.getDeclaredMethods()) { 86 testMethod(m); 87 } 88 } 89 90 void testConstructor(Constructor c) { 91 92 String prefix = clazz.getName() + "." + c.getName() + "() - "; 93 94 // Parameters must match parameter types 95 Parameter params[] = c.getParameters(); 96 int paramTypes = c.getParameterTypes().length; 97 if (paramTypes != params.length) { 98 error(prefix + "number of parameter types (" + paramTypes 99 + ") != number of parameters (" + params.length + ")"); 100 return; 101 } 102 103 sb.append(clazz.getName()).append(".").append("<init>").append("("); 104 String sep = ""; 105 106 // Some paramters are expected 107 if (params.length < 2 && isEnum) { 108 error(prefix + "enum constuctor, two arguments expected"); 109 } else if (params.length < 1 && (isAnon || isLocal || 110 (isMember && !isStatic ))) { 111 error(prefix + "class constuctor,expected implicit argument"); 112 } 113 114 int i = -1; 115 String param = null; 116 for (Parameter p : c.getParameters()) { 117 i++; 118 String pname = p.getName(); 119 int pmodifier = p.getModifiers(); 120 isFinal = false; 121 if (Modifier.isFinal(pmodifier)) { 122 isFinal = true; 123 pname = "final " + pname; 124 } 125 sb.append(sep).append(pname); 126 if (p.isImplicit()) sb.append("/*implicit*/"); 127 if (p.isSynthetic()) sb.append("/*synthetic*/"); 128 sep = ", "; 129 130 // Set expectations 131 String expect = null; 132 boolean allowImplicit = false; 133 boolean allowSynthetic = false; 134 if (isEnum) { 135 if (i == 0) { 136 expect = "\\$enum\\$name"; 137 allowSynthetic = true; 138 } else if(i == 1) { 139 expect = "\\$enum\\$ordinal"; 140 allowSynthetic = true; 141 } 142 } else if (i == 0) { 143 if (isAnon) { 144 expect = "this\\$[0-9]+"; 145 allowImplicit = true; 146 if (isFinal) 147 expect = "final this\\$[0-9]+"; 148 } else if (isLocal) { 149 expect = "this\\$[0-9]+"; 150 allowImplicit = true; 151 if (isFinal) 152 expect = "final this\\$[0-9]+"; 153 } else if ((isMember && !isStatic)) { 154 expect = "this\\$[0-9]+"; 155 allowImplicit = true; 156 if (!isPublic) { 157 // some but not all non-public inner classes 158 // have synthetic argument. For now we give 159 // the test a bit of slack and allow either. 160 allowSynthetic = true; 161 } 162 if (isFinal) 163 expect = "final this\\$[0-9]+"; 164 } 165 } 166 167 if (p.isSynthetic() && !p.isImplicit() && !allowSynthetic) { 168 //patch treatment for local captures 169 if (isAnon || ((isLocal || isAnon) & !isStatic)) { 170 expect = "val\\$.*"; 171 allowSynthetic = true; 172 if (isFinal) { 173 expect = "final val\\$.*"; 174 } 175 } 176 } 177 178 // Check expected flags 179 if (p.isSynthetic() && p.isImplicit()) { 180 error(prefix + "param[" + i + "]='" + pname + 181 "' both isImplicit() and isSynthetic()"); 182 break; 183 } 184 if (allowImplicit && allowSynthetic && 185 !(p.isSynthetic() || p.isImplicit())) { 186 error(prefix + "param[" + i + "]='" + pname + 187 "' isImplicit() or isSynthetic() expected"); 188 break; 189 } 190 191 if (allowImplicit && !allowSynthetic && !p.isImplicit()) { 192 error(prefix + "param[" + i + "]='" + pname + 193 "' isImplicit() expected"); 194 break; 195 } 196 if (!allowImplicit && allowSynthetic && !p.isSynthetic()) { 197 error(prefix + "param[" + i + "]='" + pname + 198 "' isSynthetic() expected"); 199 break; 200 } 201 202 if (!allowImplicit && p.isImplicit()) { 203 error(prefix + "param[" + i + "]='" + pname + 204 "' isImplicit() unexpected"); 205 break; 206 } 207 208 if (!allowSynthetic && p.isSynthetic()) { 209 error(prefix + "param[" + i + "]='" + pname + 210 "' isSynthetic() unexpected"); 211 break; 212 } 213 214 // Check expected names 215 if (expect != null) { 216 if (pname.matches(expect)) continue; 217 error(prefix + "param[" + i + "]='" + pname + 218 "' expected '" + expect + "'"); 219 break; 220 } 221 222 // Test naming convention for explicit parameters. 223 boolean fidelity = !isAnon; 224 if (param != null && fidelity) { 225 char ch = param.charAt(0); 226 expect = (++ch) + param; 227 } 228 if (isFinal && expect != null) { 229 expect = "final " + expect; 230 } 231 if (pname != null && fidelity) { 232 if (isFinal) { 233 param = pname.substring(6); 234 } else { 235 param = pname; 236 } 237 } 238 if (expect != null && !expect.equals(pname)) { 239 error(prefix + "param[" + i + "]='" + pname + 240 "' expected '" + expect + "'"); 241 break; 242 } 243 } 244 if (c.isSynthetic()) { 245 sb.append(")/*synthetic*/\n"); 246 } else { 247 sb.append(")\n"); 248 } 249 } 250 251 void testMethod(Method m) { 252 253 String prefix = clazz.getName() + "." + m.getName() + "() - "; 254 255 // Parameters must match parameter types 256 int paramTypes = m.getParameterTypes().length; 257 int params = m.getParameters().length; 258 if (paramTypes != params) { 259 error(prefix + "number of parameter types (" + paramTypes 260 + ") != number of parameters (" + params + ")"); 261 return; 262 } 263 264 sb.append(clazz.getName()).append(".").append(m.getName()).append("("); 265 String sep = ""; 266 String param = null; 267 int i = -1; 268 // For methods we expect all parameters to follow 269 // the test-case design pattern, except synthetic methods. 270 for (Parameter p : m.getParameters()) { 271 i++; 272 isFinal = false; 273 int pmodifier = p.getModifiers(); 274 if (param == null) { 275 param = p.getName(); 276 if (Modifier.isFinal(pmodifier)) { 277 isFinal = true; 278 param = "final " + param; 279 } 280 sb.append(sep).append(param); 281 } else { 282 char c = param.charAt(0); 283 String expect = m.isSynthetic() ? ("arg" + i) : ((++c) + param); 284 param = p.getName(); 285 if (Modifier.isFinal(pmodifier)) { 286 isFinal = true; 287 expect = "final " + expect; 288 param = "final " + param; 289 } 290 sb.append(sep).append(param); 291 if (!m.isBridge() && !expect.equals(param)) { 292 error(prefix + "param[" + i + "]='" 293 + param + "' expected '" + expect + "'"); 294 break; 295 } 296 } 297 if(isFinal) 298 param = param.substring(6); 299 if (p.isImplicit()) { 300 sb.append("/*implicit*/"); 301 } 302 if (p.isSynthetic()) { 303 sb.append("/*synthetic*/"); 304 } 305 sep = ", "; 306 } 307 if (m.isSynthetic()) { 308 sb.append(")/*synthetic*/\n"); 309 } else { 310 sb.append(")\n"); 311 } 312 } 313} 314