3789983e89
Reviewed-by: darcy, ihse
314 lines
11 KiB
Java
314 lines
11 KiB
Java
/*
|
|
* 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");
|
|
}
|
|
}
|
|
}
|