Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/docs/manual/dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -1099,8 +1099,8 @@ <h3 id="creating_sequence">Creating sequences</h3>

<pre class="code">
TypedOperation newOb = TypedOperation.createPrimitiveInitialization(ConcreteTypes.STRING_TYPE, "hi!");
TypedOperation addFirst = TypedOperation.forMethod(LinkedList.class.getMethod("addFirst", Object.class), AccessibilityPredicate.IS_PUBLIC).substitute(substLL);
TypedOperation size = TypedOperation.forMethod(LinkedList.class.getMethod("size"), AccessibilityPredicate.IS_PUBLIC).substitute(substLL);
TypedOperation addFirst = TypedOperation.forMethod(LinkedList.class.getMethod("addFirst", Object.class)).substitute(substLL);
TypedOperation size = TypedOperation.forMethod(LinkedList.class.getMethod("size")).substitute(substLL);
</pre>

<p>
Expand All @@ -1123,7 +1123,7 @@ <h3 id="creating_sequence">Creating sequences</h3>
</p>

<pre class="code">
TypedOperation syncA = TypedOperation.forMethod(Collections.class.getMethod("synchronizedSet", Set.class), AccessibilityPredicate.IS_PUBLIC);
TypedOperation syncA = TypedOperation.forMethod(Collections.class.getMethod("synchronizedSet", Set.class));
Substitution&lt;ReferenceType&gt; substA = new Substitution(syncA.getTypeParameters(), (ReferenceType)ConcreteTypes.STRING_TYPE);
TypedOperation syncS = syncA.substitute(substA);
</pre>
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/randoop/contract/CheckRepContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import randoop.main.RandoopBug;
import randoop.operation.TypedClassOperation;
import randoop.operation.TypedOperation;
import randoop.reflection.AccessibilityPredicate;
import randoop.types.JavaTypes;
import randoop.types.TypeTuple;

Expand Down Expand Up @@ -53,8 +52,7 @@ public CheckRepContract(Method checkRepMethod) {
assert Modifier.isPublic(modifiers);
assert !Modifier.isStatic(modifiers);
assert checkRepMethod.getParameterTypes().length == 0;
// accessibility predicate shouldn't matter for generating output type
this.operation = TypedOperation.forMethod(checkRepMethod, AccessibilityPredicate.IS_ANY);
this.operation = TypedOperation.forMethod(checkRepMethod);
if (operation.getOutputType().equals(JavaTypes.BOOLEAN_TYPE)) {
this.returnsBoolean = true;
} else if (operation.getOutputType().equals(JavaTypes.VOID_TYPE)) {
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/randoop/generation/HelperSequenceCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,7 @@ private static TypedOperation getEnumSetCreation(ParameterizedType creationType)
} catch (NoSuchMethodException e) {
throw new RandoopBug("Can't find \"noneOf\" method for EnumSet: ", e);
}
// accessibility predicate shouldn't matter for accessible method
MethodCall op = new MethodCall(method, true);
MethodCall op = new MethodCall(method);
List<Type> paramTypes = Collections.singletonList(JavaTypes.CLASS_TYPE);
return new TypedClassOperation(op, creationType, new TypeTuple(paramTypes), creationType);
}
Expand All @@ -437,8 +436,7 @@ private static TypedOperation getAddOperation(
} catch (NoSuchMethodException e) {
throw new RandoopBug("Can't find add() method for " + collectionType, e);
}
// accessibility predicate shouldn't matter
MethodCall op = new MethodCall(addMethod, true);
MethodCall op = new MethodCall(addMethod);
List<Type> arguments = new ArrayList<>(2);
arguments.add(collectionType);
arguments.add(elementType);
Expand All @@ -464,8 +462,7 @@ private static TypedOperation getCollectionAddAllOperation(ReferenceType element
} catch (NoSuchMethodException e) {
throw new RandoopBug("Can't find Collections.addAll method", e);
}
// accessibility predicate shouldn't matter
MethodCall op = new MethodCall(method, true);
MethodCall op = new MethodCall(method);
assert method.getTypeParameters().length == 1 : "method should have one type parameter";
List<Type> paramTypes = new ArrayList<>(2);
ParameterizedType collectionType = JDKTypes.COLLECTION_TYPE.instantiate(elementType);
Expand Down
87 changes: 48 additions & 39 deletions src/main/java/randoop/operation/MethodCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import randoop.ExecutionOutcome;
import randoop.Globals;
import randoop.NormalExecution;
import randoop.reflection.AccessibilityPredicate;
import randoop.reflection.ReflectionPredicate;
import randoop.sequence.Variable;
import randoop.types.Type;
Expand Down Expand Up @@ -46,13 +45,14 @@ public final class MethodCall extends CallableOperation {
private final boolean isStatic;

/**
* True if the method is accessible. If {@code --only-test-public-members} is set to true, a
* method is considered accessible iff it's public. Additionally, if {@code --junit-package-name}
* is null, a method is considered accessible iff it's public. Otherwise, a method is considered
* True if the method should be called reflectively. (This is generally because the method is not
* accessible from the JUnit code.) If {@code --only-test-public-members} is set to true, a method
* is considered accessible iff it's public. Additionally, if {@code --junit-package-name} is
* null, a method is considered accessible iff it's public. Otherwise, a method is considered
* accessible if it is either public or accessible relative to the given package name specified by
* {@code --junit-package-name}
* {@code --junit-package-name}.
*/
private boolean isAccessible;
private boolean callReflectively;

/**
* getMethod returns Method object of this MethodCall.
Expand All @@ -66,17 +66,28 @@ public Method getMethod() {
/**
* Creates an object corresponding to a call to the given method.
*
* <p>In generated tests, the method will be called normally, not reflectively.
*
* @param method the reflective method object
* @param isAccessible boolean indicating if the method is accessible
*/
public MethodCall(Method method, boolean isAccessible) {
public MethodCall(Method method) {
this(method, false);
}

/**
* Creates an object corresponding to a call to the given method.
*
* @param method the reflective method object
* @param callReflectively if true, the method should be called reflectively
*/
public MethodCall(Method method, boolean callReflectively) {
if (method == null) {
throw new IllegalArgumentException("method should not be null.");
}

this.method = method;
this.isStatic = Modifier.isStatic(method.getModifiers() & Modifier.methodModifiers());
this.isAccessible = isAccessible;
this.callReflectively = callReflectively;
}

/**
Expand Down Expand Up @@ -110,7 +121,30 @@ public void appendCode(
// The name of a variable (in the test that Randoop outputs) that holds the Method object.
String methodVar = getVariableNameForMethodObject();

if (!isAccessible) {
if (!callReflectively) {
if (isStatic()) {
// In the generated Java code, the "receiver" (before the method name) for a static method
// call is the class name.
sb.append(declaringType.getCanonicalName().replace('$', '.'));
} else {
// In the generated Java code, the receiver is an expression.
String receiverVar = isStatic() ? null : inputVars.get(0).getName();
Type receiverFormalType = inputTypes.get(0);
if (receiverFormalType.isPrimitive()) {
sb.append("((")
.append(receiverFormalType.getFqName())
.append(")")
.append(receiverVar)
.append(")");
} else {
sb.append(receiverVar);
}
}

sb.append(".");
sb.append(methodName);
} else {
// TODO: For brevity here, perhaps abstract this `if` statement into a separate method.
if (!Globals.makeAccessibleCode.containsKey(methodVar)) {
StringBuilder makeMethodAccessibleBuilder = new StringBuilder();
makeMethodAccessibleBuilder
Expand All @@ -133,32 +167,7 @@ public void appendCode(
.append(System.lineSeparator());
Globals.makeAccessibleCode.put(methodVar, makeMethodAccessibleBuilder.toString());
}
}

String receiverVar = isStatic() ? null : inputVars.get(0).getName();
if (isAccessible) {
if (isStatic()) {
// In the generated Java code, the "receiver" (before the method name) for a static method
// call is the class name.
sb.append(declaringType.getCanonicalName().replace('$', '.'));
} else {
// In this branch, isAcessible == false.
// In the generated Java code, the receiver is an expression.
Type receiverFormalType = inputTypes.get(0);
if (receiverFormalType.isPrimitive()) {
sb.append("((")
.append(receiverFormalType.getFqName())
.append(")")
.append(receiverVar)
.append(")");
} else {
sb.append(receiverVar);
}
}

sb.append(".");
sb.append(methodName);
} else {
if (!outputType.isVoid()) {
// Cast because the return type of `invoke()` is Object.
sb.append("(").append(outputType.getFqName()).append(") ");
Expand All @@ -168,9 +177,9 @@ public void appendCode(

StringJoiner arguments = new StringJoiner(", ", "(", ")");
// In a reflective call, a receiver is always passed (even if it's null).
int startIndex = !isAccessible || isStatic() ? 0 : 1;
int startIndex = callReflectively || isStatic() ? 0 : 1;
for (int i = startIndex; i < inputVars.size(); i++) {
if (i == 0 && !isAccessible && isStatic()) {
if (i == 0 && callReflectively && isStatic()) {
// There is no harm to passing inputVars.get(0), but pass
// null to emphasize that the first (receiver) argument is ignored.
sb.append("null");
Expand Down Expand Up @@ -356,8 +365,8 @@ public static TypedClassOperation parse(String signature) throws OperationParseE
throw new OperationParseException(msg);
}
}
// accessibility predicate shouldn't matter for generating output type
return TypedClassOperation.forMethod(m, AccessibilityPredicate.IS_ANY);

return TypedClassOperation.forMethod(m);
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/randoop/operation/TypedOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,16 @@ public static TypedClassOperation forConstructor(Constructor<?> constructor) {
return new TypedClassOperation(op, declaringType, inputTypes, declaringType);
}

/**
* Constructs a {@link TypedOperation} for a method object.
*
* @param method the reflective method object
* @return the typed operation for the given method
*/
public static TypedClassOperation forMethod(Method method) {
return forMethod(method, AccessibilityPredicate.IS_ANY);
}

/**
* Constructs a {@link TypedOperation} for a method object.
*
Expand All @@ -482,7 +492,7 @@ public static TypedClassOperation forMethod(
}

List<Type> paramTypes = new ArrayList<>(methodParamTypes.size() + 1);
MethodCall op = new MethodCall(method, accessibilityPredicate.isAccessible(method));
MethodCall op = new MethodCall(method, !accessibilityPredicate.isAccessible(method));
ClassOrInterfaceType declaringType = ClassOrInterfaceType.forClass(method.getDeclaringClass());
if (!op.isStatic()) {
paramTypes.add(declaringType);
Expand Down Expand Up @@ -526,7 +536,7 @@ private static TypedClassOperation getAnonEnumOperation(
continue;
}
List<Type> paramTypes = new ArrayList<>(mGenericParamTypes.length + 1);
MethodCall op = new MethodCall(publicMethod, true);
MethodCall op = new MethodCall(publicMethod);
if (!op.isStatic()) {
paramTypes.add(enumType);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/randoop/reflection/OperationModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,8 @@ private void addClassTypes(
succeeded++;
} catch (Throwable e) {
System.out.printf(
"Cannot get methods for %s specified via --testclass or --classlist"
+ " due to exception:%n%s%n",
"Cannot get methods for %s specified via "
+ "--testclass or --classlist due to exception:%n%s%n",
c.getName(), UtilPlume.stackTraceToString(e));
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/randoop/reflection/ReflectionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ public void apply(ClassVisitor visitor, Class<?> c) {
m.setAccessible(true);
applyTo(visitor, m);
} catch (Exception e) {
// Method cannot be reflectively called
// Method cannot be reflectively called.
// TODO: some kind of error should be thrown here (or at least logging?).
}
} else if (isAccessible(m)) {
if (classIsAccessible || Modifier.isStatic(m.getModifiers())) {
Expand Down
21 changes: 8 additions & 13 deletions src/main/java/randoop/test/ExpectedExceptionCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
public class ExpectedExceptionCheck extends ExceptionCheck {

/** A boolean indicating the accessibility of the method. */
private boolean isAccessible;
private boolean callReflectively;

/**
* Creates check that enforces expectation that an exception is thrown by the statement at the
Expand All @@ -32,9 +32,9 @@ public class ExpectedExceptionCheck extends ExceptionCheck {
* @param catchClassName the name of exception to be caught
*/
public ExpectedExceptionCheck(
Throwable exception, int statementIndex, String catchClassName, boolean isAccessible) {
Throwable exception, int statementIndex, String catchClassName, boolean callReflectively) {
super(exception, statementIndex, catchClassName);
this.isAccessible = isAccessible;
this.callReflectively = callReflectively;
}

/**
Expand All @@ -45,7 +45,9 @@ public ExpectedExceptionCheck(
@Override
protected void appendTryBehavior(StringBuilder b) {
String assertionMessage;
{
if (callReflectively) {
assertionMessage = "Expected exception of type java.lang.reflect.InvocationTargetException";
} else {
String message;
if (exception.getClass().isAnonymousClass()) {
message = "Expected anonymous exception";
Expand All @@ -58,14 +60,7 @@ protected void appendTryBehavior(StringBuilder b) {
}
message = "Expected exception of type " + getExceptionName() + exceptionMessage;
}
if (isAccessible) {
assertionMessage = "org.junit.Assert.fail(\"" + StringsPlume.escapeJava(message) + "\")";
} else {
assertionMessage =
"org.junit.Assert.fail(\""
+ "Expected exception of type java.lang.reflect.InvocationTargetException"
+ "\")";
}
assertionMessage = "org.junit.Assert.fail(\"" + StringsPlume.escapeJava(message) + "\")";
}
b.append(Globals.lineSep)
.append(" org.junit.Assert.fail(\"")
Expand Down Expand Up @@ -95,7 +90,7 @@ protected void appendTryBehavior(StringBuilder b) {
*/
@Override
protected void appendCatchBehavior(StringBuilder b, String catchClassName) {
if (!isAccessible) {
if (callReflectively) {
b.append("catch (")
.append("java.lang.reflect.InvocationTargetException")
.append(" e) {")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import randoop.condition.specification.ThrowsCondition;
import randoop.operation.TypedClassOperation;
import randoop.operation.TypedOperation;
import randoop.reflection.AccessibilityPredicate;
import randoop.sequence.ExecutableSequence;
import randoop.sequence.Sequence;
import randoop.sequence.Variable;
Expand Down Expand Up @@ -193,8 +192,7 @@ private ExecutableSequence createCategorySequence(int value) throws NoSuchMethod
Constructor<?> reflectionConstructor = c.getConstructor(int.class);
TypedClassOperation constructorOp = TypedOperation.forConstructor(reflectionConstructor);
Method method = c.getDeclaredMethod("category", int.class);
TypedClassOperation methodOp =
TypedOperation.forMethod(method, AccessibilityPredicate.IS_PUBLIC);
TypedClassOperation methodOp = TypedOperation.forMethod(method);
methodOp.setExecutableSpecification(getMethodSpecification(method));

Sequence sequence = new Sequence();
Expand All @@ -212,8 +210,7 @@ private ExecutableSequence createCategorySequence(int value) throws NoSuchMethod
private ExecutableSequence createBadnessSequence() throws NoSuchMethodException {
Class<?> c = ClassWithConditions.class;
Method method = c.getDeclaredMethod("badness", ClassWithConditions.Range.class, int.class);
TypedClassOperation methodOp =
TypedOperation.forMethod(method, AccessibilityPredicate.IS_PUBLIC);
TypedClassOperation methodOp = TypedOperation.forMethod(method);
methodOp.setExecutableSpecification(getBadnessConditions(method));

Sequence sequence = new Sequence();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import randoop.condition.specification.OperationSpecification;
import randoop.operation.TypedClassOperation;
import randoop.operation.TypedOperation;
import randoop.reflection.AccessibilityPredicate;
import randoop.sequence.ExecutableSequence;
import randoop.sequence.Sequence;
import randoop.sequence.Variable;
Expand Down Expand Up @@ -62,9 +61,7 @@ public void testPrintWriterAppend() {
assertEquals("x2.equals(x0)", Util.replaceWords("result.equals(receiver)", replacements));

String conditionText = "result.equals(receiver)";
Sequence sequence =
createPrintWriterSequence(
TypedOperation.forMethod(method, AccessibilityPredicate.IS_PUBLIC));
Sequence sequence = createPrintWriterSequence(TypedOperation.forMethod(method));

List<ExecutableBooleanExpression> postConditions = new ArrayList<>();
Method conditionMethod =
Expand Down Expand Up @@ -163,8 +160,7 @@ public void testSignatureFromFile() {

SpecificationCollection collection = SpecificationCollection.create(specList);
ExecutableSpecification execSpec = collection.getExecutableSpecification(method);
TypedClassOperation appendOp =
TypedOperation.forMethod(method, AccessibilityPredicate.IS_PUBLIC);
TypedClassOperation appendOp = TypedOperation.forMethod(method);
appendOp.setExecutableSpecification(execSpec);
Sequence sequence = createPrintWriterSequence(appendOp);
ExecutableSequence eseq = new ExecutableSequence(sequence);
Expand Down
Loading