| /* |
| * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| import java.io.*; |
| import java.lang.reflect.*; |
| |
| /** |
| * Test MethodParameter attributs by reflection API |
| */ |
| public class ReflectionVisitor extends MethodParametersTester.Visitor { |
| |
| public ReflectionVisitor(MethodParametersTester tester) { |
| super(tester); |
| } |
| |
| public void error(String msg) { |
| super.error("reflection: " + msg); |
| } |
| |
| public void warn(String msg) { |
| super.warn("reflection: " + msg); |
| } |
| |
| boolean isEnum; |
| boolean isInterface; |
| boolean isAnon; |
| boolean isLocal; |
| boolean isMember; |
| boolean isStatic; |
| boolean isPublic; |
| boolean isFinal; |
| Class clazz; |
| StringBuilder sb; |
| |
| /** |
| * Read class using {@code ClassFile}, and generate a list of methods |
| * with parameter names as available in the MethodParameters attribute. |
| */ |
| void visitClass(final String cl, final File cfile, final StringBuilder sb) |
| throws Exception { |
| |
| this.sb = sb; |
| clazz = Class.forName(cl); |
| isEnum = clazz.isEnum(); |
| isInterface = clazz.isInterface(); |
| isAnon = clazz.isAnonymousClass(); |
| isLocal = clazz.isLocalClass(); |
| isMember = clazz.isMemberClass(); |
| isStatic = ((clazz.getModifiers() & Modifier.STATIC) != 0); |
| isPublic = ((clazz.getModifiers() & Modifier.PUBLIC) != 0); |
| |
| sb.append(isStatic ? "static " : "") |
| .append(isPublic ? "public " : "") |
| .append(isEnum ? "enum " : isInterface ? "interface " : "class ") |
| .append(cl).append(" -- ") |
| .append(isMember? "inner" : "" ) |
| .append(isLocal? "inner" : "" ) |
| .append(isAnon ? "anon" : "") |
| .append("\n"); |
| |
| for (Constructor c : clazz.getDeclaredConstructors()) { |
| testConstructor(c); |
| } |
| |
| for (Method m :clazz.getDeclaredMethods()) { |
| testMethod(m); |
| } |
| } |
| |
| void testConstructor(Constructor c) { |
| |
| String prefix = clazz.getName() + "." + c.getName() + "() - "; |
| |
| // Parameters must match parameter types |
| Parameter params[] = c.getParameters(); |
| int paramTypes = c.getParameterTypes().length; |
| if (paramTypes != params.length) { |
| error(prefix + "number of parameter types (" + paramTypes |
| + ") != number of parameters (" + params.length + ")"); |
| return; |
| } |
| |
| sb.append(clazz.getName()).append(".").append("<init>").append("("); |
| String sep = ""; |
| |
| // Some paramters are expected |
| if (params.length < 2 && isEnum) { |
| error(prefix + "enum constuctor, two arguments expected"); |
| } else if (params.length < 1 && (isAnon || isLocal || |
| (isMember && !isStatic ))) { |
| error(prefix + "class constuctor,expected implicit argument"); |
| } |
| |
| int i = -1; |
| String param = null; |
| for (Parameter p : c.getParameters()) { |
| i++; |
| String pname = p.getName(); |
| int pmodifier = p.getModifiers(); |
| isFinal = false; |
| if (Modifier.isFinal(pmodifier)) { |
| isFinal = true; |
| pname = "final " + pname; |
| } |
| sb.append(sep).append(pname); |
| if (p.isImplicit()) sb.append("/*implicit*/"); |
| if (p.isSynthetic()) sb.append("/*synthetic*/"); |
| sep = ", "; |
| |
| // Set expectations |
| String expect = null; |
| boolean allowImplicit = false; |
| boolean allowSynthetic = false; |
| if (isEnum) { |
| if (i == 0) { |
| expect = "\\$enum\\$name"; |
| allowSynthetic = true; |
| } else if(i == 1) { |
| expect = "\\$enum\\$ordinal"; |
| allowSynthetic = true; |
| } |
| } else if (i == 0) { |
| if (isAnon) { |
| expect = "this\\$[0-9]+"; |
| allowImplicit = true; |
| if (isFinal) |
| expect = "final this\\$[0-9]+"; |
| } else if (isLocal) { |
| expect = "this\\$[0-9]+"; |
| allowImplicit = true; |
| if (isFinal) |
| expect = "final this\\$[0-9]+"; |
| } else if ((isMember && !isStatic)) { |
| expect = "this\\$[0-9]+"; |
| allowImplicit = true; |
| if (!isPublic) { |
| // some but not all non-public inner classes |
| // have synthetic argument. For now we give |
| // the test a bit of slack and allow either. |
| allowSynthetic = true; |
| } |
| if (isFinal) |
| expect = "final this\\$[0-9]+"; |
| } |
| } |
| |
| if (p.isSynthetic() && !p.isImplicit() && !allowSynthetic) { |
| //patch treatment for local captures |
| if (isAnon || ((isLocal || isAnon) & !isStatic)) { |
| expect = "val\\$.*"; |
| allowSynthetic = true; |
| if (isFinal) { |
| expect = "final val\\$.*"; |
| } |
| } |
| } |
| |
| // Check expected flags |
| if (p.isSynthetic() && p.isImplicit()) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' both isImplicit() and isSynthetic()"); |
| break; |
| } |
| if (allowImplicit && allowSynthetic && |
| !(p.isSynthetic() || p.isImplicit())) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' isImplicit() or isSynthetic() expected"); |
| break; |
| } |
| |
| if (allowImplicit && !allowSynthetic && !p.isImplicit()) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' isImplicit() expected"); |
| break; |
| } |
| if (!allowImplicit && allowSynthetic && !p.isSynthetic()) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' isSynthetic() expected"); |
| break; |
| } |
| |
| if (!allowImplicit && p.isImplicit()) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' isImplicit() unexpected"); |
| break; |
| } |
| |
| if (!allowSynthetic && p.isSynthetic()) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' isSynthetic() unexpected"); |
| break; |
| } |
| |
| // Check expected names |
| if (expect != null) { |
| if (pname.matches(expect)) continue; |
| error(prefix + "param[" + i + "]='" + pname + |
| "' expected '" + expect + "'"); |
| break; |
| } |
| |
| // Test naming convention for explicit parameters. |
| boolean fidelity = !isAnon; |
| if (param != null && fidelity) { |
| char ch = param.charAt(0); |
| expect = (++ch) + param; |
| } |
| if (isFinal && expect != null) { |
| expect = "final " + expect; |
| } |
| if (pname != null && fidelity) { |
| if (isFinal) { |
| param = pname.substring(6); |
| } else { |
| param = pname; |
| } |
| } |
| if (expect != null && !expect.equals(pname)) { |
| error(prefix + "param[" + i + "]='" + pname + |
| "' expected '" + expect + "'"); |
| break; |
| } |
| } |
| if (c.isSynthetic()) { |
| sb.append(")/*synthetic*/\n"); |
| } else { |
| sb.append(")\n"); |
| } |
| } |
| |
| void testMethod(Method m) { |
| |
| String prefix = clazz.getName() + "." + m.getName() + "() - "; |
| |
| // Parameters must match parameter types |
| int paramTypes = m.getParameterTypes().length; |
| int params = m.getParameters().length; |
| if (paramTypes != params) { |
| error(prefix + "number of parameter types (" + paramTypes |
| + ") != number of parameters (" + params + ")"); |
| return; |
| } |
| |
| sb.append(clazz.getName()).append(".").append(m.getName()).append("("); |
| String sep = ""; |
| String param = null; |
| int i = -1; |
| // For methods we expect all parameters to follow |
| // the test-case design pattern, except synthetic methods. |
| for (Parameter p : m.getParameters()) { |
| i++; |
| isFinal = false; |
| int pmodifier = p.getModifiers(); |
| if (param == null) { |
| param = p.getName(); |
| if (Modifier.isFinal(pmodifier)) { |
| isFinal = true; |
| param = "final " + param; |
| } |
| sb.append(sep).append(param); |
| } else { |
| char c = param.charAt(0); |
| String expect = m.isSynthetic() ? ("arg" + i) : ((++c) + param); |
| param = p.getName(); |
| if (Modifier.isFinal(pmodifier)) { |
| isFinal = true; |
| expect = "final " + expect; |
| param = "final " + param; |
| } |
| sb.append(sep).append(param); |
| if (!m.isBridge() && !expect.equals(param)) { |
| error(prefix + "param[" + i + "]='" |
| + param + "' expected '" + expect + "'"); |
| break; |
| } |
| } |
| if(isFinal) |
| param = param.substring(6); |
| if (p.isImplicit()) { |
| sb.append("/*implicit*/"); |
| } |
| if (p.isSynthetic()) { |
| sb.append("/*synthetic*/"); |
| } |
| sep = ", "; |
| } |
| if (m.isSynthetic()) { |
| sb.append(")/*synthetic*/\n"); |
| } else { |
| sb.append(")\n"); |
| } |
| } |
| } |