ReflectionVisitor.java revision 2787:441711fd360d
1/* 2 * Copyright (c) 2013, 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 // Check expected flags 168 if (p.isSynthetic() && p.isImplicit()) { 169 error(prefix + "param[" + i + "]='" + pname + 170 "' both isImplicit() and isSynthetic()"); 171 break; 172 } 173 if (allowImplicit && allowSynthetic && 174 !(p.isSynthetic() || p.isImplicit())) { 175 error(prefix + "param[" + i + "]='" + pname + 176 "' isImplicit() or isSynthetic() expected"); 177 break; 178 } 179 180 if (allowImplicit && !allowSynthetic && !p.isImplicit()) { 181 error(prefix + "param[" + i + "]='" + pname + 182 "' isImplicit() expected"); 183 break; 184 } 185 if (!allowImplicit && allowSynthetic && !p.isSynthetic()) { 186 error(prefix + "param[" + i + "]='" + pname + 187 "' isSynthetic() expected"); 188 break; 189 } 190 191 if (!allowImplicit && p.isImplicit()) { 192 error(prefix + "param[" + i + "]='" + pname + 193 "' isImplicit() unexpected"); 194 break; 195 } 196 197 if (!allowSynthetic && p.isSynthetic()) { 198 error(prefix + "param[" + i + "]='" + pname + 199 "' isSynthetic() unexpected"); 200 break; 201 } 202 203 // Check expected names 204 if (expect != null) { 205 if (pname.matches(expect)) continue; 206 error(prefix + "param[" + i + "]='" + pname + 207 "' expected '" + expect + "'"); 208 break; 209 } 210 211 // Test naming convention for explicit parameters. 212 boolean fidelity = !isAnon; 213 if (param != null && fidelity) { 214 char ch = param.charAt(0); 215 expect = (++ch) + param; 216 } 217 if (isFinal && expect != null) { 218 expect = "final " + expect; 219 } 220 if (pname != null && fidelity) { 221 if (isFinal) { 222 param = pname.substring(6); 223 } else { 224 param = pname; 225 } 226 } 227 if (expect != null && !expect.equals(pname)) { 228 error(prefix + "param[" + i + "]='" + pname + 229 "' expected '" + expect + "'"); 230 break; 231 } 232 } 233 if (c.isSynthetic()) { 234 sb.append(")/*synthetic*/\n"); 235 } else { 236 sb.append(")\n"); 237 } 238 } 239 240 void testMethod(Method m) { 241 242 String prefix = clazz.getName() + "." + m.getName() + "() - "; 243 244 // Parameters must match parameter types 245 int paramTypes = m.getParameterTypes().length; 246 int params = m.getParameters().length; 247 if (paramTypes != params) { 248 error(prefix + "number of parameter types (" + paramTypes 249 + ") != number of parameters (" + params + ")"); 250 return; 251 } 252 253 sb.append(clazz.getName()).append(".").append(m.getName()).append("("); 254 String sep = ""; 255 String param = null; 256 int i = -1; 257 // For methods we expect all parameters to follow 258 // the test-case design pattern, except synthetic methods. 259 for (Parameter p : m.getParameters()) { 260 i++; 261 isFinal = false; 262 int pmodifier = p.getModifiers(); 263 if (param == null) { 264 param = p.getName(); 265 if (Modifier.isFinal(pmodifier)) { 266 isFinal = true; 267 param = "final " + param; 268 } 269 sb.append(sep).append(param); 270 } else { 271 char c = param.charAt(0); 272 String expect = m.isSynthetic() ? ("arg" + i) : ((++c) + param); 273 param = p.getName(); 274 if (Modifier.isFinal(pmodifier)) { 275 isFinal = true; 276 expect = "final " + expect; 277 param = "final " + param; 278 } 279 sb.append(sep).append(param); 280 if (!m.isBridge() && !m.getName().startsWith("lambda$") && !expect.equals(param)) { 281 error(prefix + "param[" + i + "]='" 282 + param + "' expected '" + expect + "'"); 283 break; 284 } 285 } 286 if(isFinal) 287 param = param.substring(6); 288 if (p.isImplicit()) { 289 sb.append("/*implicit*/"); 290 } 291 if (p.isSynthetic()) { 292 sb.append("/*synthetic*/"); 293 } 294 sep = ", "; 295 } 296 if (m.isSynthetic()) { 297 sb.append(")/*synthetic*/\n"); 298 } else { 299 sb.append(")\n"); 300 } 301 } 302} 303