Browse Source

Work on Bugzilla 42668: effect of an after returning type incompatible with a join point return type

 * fix to semantics document to describe correct semantics
 * checkin of failing coverage test case for correct semantics
tags/mostlyLastEclipse2xTree_20040112
ehilsdal 20 years ago
parent
commit
393f65bdec

+ 29
- 15
docs/progGuideDB/semantics.xml View File

@@ -1456,25 +1456,39 @@
</programlisting>

<para>
It is an error to try to put after returning advice on a join point that
does not return the correct type. For example,
If after returning does expose its returned object, then the
type of the parameter is considered to be an
<literal>instanceof</literal>-like constraint on the advice: it
will run only when the return value is of the appropriate type.
</para>

<programlisting>
after() returning (byte b): call(int String.length()) {
// this is an error
}
</programlisting>
<para>
A value is of the appropriate type if it would be assignable to
a variable of that type, in the Java sense.
<literal>byte</literal>, <literal>short</literal>,
<literal>char</literal> and <literal>int</literal> are
assignable to each other, an <literal>int</literal> is
assignable to a <literal>float</literal> parameter,
<literal>boolean</literal> values are only assignable to
<literal>boolean</literal> parameters, and reference types work
by instanceof.
</para>

<para>
There are two special cases: If the exposed value is typed to
<literal>Object</literal>, then the advice is not constrained by
that type: the actual return value is converted to an object
type for the body of the advice: <literal>int</literal> values
are represented as <literal>java.lang.Integer</literal> objects,
etc, and no value (from void methods, for example) is
represented as <literal>null</literal>.
</para>

<para>
is not allowed. But if no return value is exposed, or the exposed return
value is typed to <literal>Object</literal>, then it may be applied to
any join point. If the exposed value is typed to
<literal>Object</literal>, then the actual return value is converted to
an object type for the body of the advice: <literal>int</literal> values
are represented as <literal>java.lang.Integer</literal> objects, etc, and
no value (from void methods, for example) is represented as
<literal>null</literal>.
Secondly, the <literal>null</literal> value is assignable to a
parameter <literal>T</literal> if the join point
<emphasis>could</emphasis> return something of type
<literal>T</literal>.
</para>

<para>

+ 8
- 10
tests/ajcTestsFailing.xml View File

@@ -23,16 +23,6 @@
<run class="packageProtected.concern.BaseTarget"/>
</ajc-test>
<ajc-test dir="bugs"
title="after returning type incompatible with join point return type"
pr="42668"
>
<compile files="IncompatibleAfterReturningTypeCE.java">
<message kind="error" line="20"/>
<message kind="error" line="22"/>
</compile>
</ajc-test>
<ajc-test dir="bugs"
pr="41888"
title="call PCD fails when given subtype of defining type">
@@ -143,5 +133,13 @@
files="Main.java"/>
<run class="Main"/>
</ajc-test>
<ajc-test dir="new"
pr="42668"
title="after returning with parameter: matching rules">
<compile files="AfterReturningParamMatching.java" />
<run class="AfterReturningParamMatching"/>
</ajc-test>


</suite>

+ 0
- 21
tests/bugs/IncompatibleAfterReturningTypeCE.java View File

@@ -1,21 +0,0 @@

public class IncompatibleAfterReturningTypeCE {
public static void main(String[] args) {
System.setProperty("foo", ""+"".length());
}
}

class C {
Integer getInteger() {
return null;
}
}

/** @testcase PR#42668 after returning type incompatible with join point return type */
aspect A {

after () returning (Boolean b) : execution(Integer C.getInteger()) { } // CE 20 incompatible return type from join point

after () returning (byte b) : call(int String.length()) {} // CE 22 incompatible return type

}

+ 10
- 0
tests/ehTests.xml View File

@@ -0,0 +1,10 @@

<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">

<suite>
<ajc-test dir="new" pr="42668"
title="after returning with parameter: matching rules">
<compile files="AfterReturningParamMatching.java" />
<run class="AfterReturningParamMatching"/>
</ajc-test>
</suite>

+ 72
- 0
tests/new/AfterReturningParamMatching.java View File

@@ -0,0 +1,72 @@
import org.aspectj.testing.Tester;

// this test verifies the matching behaivor for after returning with a typed parameter.

public class AfterReturningParamMatching {
public static void main(String[] args) {
goBoolean(false);
Tester.checkAndClearEvents(new String[] { "Object" });

goByte(1);
Tester.checkAndClearEvents(new String[] { "byte", "int", "long", "Object"});
goInt(2);
Tester.checkAndClearEvents(new String[] { "byte", "int", "long", "Object" });

goLong(3);
Tester.checkAndClearEvents(new String[] { "byte", "int", "long", "Object" });
goObject(new Object());
Tester.checkAndClearEvents(new String[] { "Object" });
goObject(new Integer(4));
Tester.checkAndClearEvents(new String[] { "Object", "Number", "Integer" });
goObject(null);
Tester.checkAndClearEvents(new String[] { "Object" });
goNumber(new Long(5));
Tester.checkAndClearEvents(new String[] { "Object", "Number" });
goNumber(new Integer(6));
Tester.checkAndClearEvents(new String[] { "Object", "Number", "Integer" });

goNumber(null);
Tester.checkAndClearEvents(new String[] { "Object", "Number" });

goInteger(new Integer(7));
Tester.checkAndClearEvents(new String[] { "Object", "Number", "Integer" });

goInteger(null);
Tester.checkAndClearEvents(new String[] { "Object", "Number", "Integer" });

}
static boolean goBoolean(boolean b) { return b; }
static byte goByte(int i) { return (byte) i; }
static int goInt(int i) { return i; }
static long goLong(int i) { return (long) i; }
static Object goObject(Object o) { return o; }
static Number goNumber(Number o) { return o; }
static Integer goInteger(Integer o) { return o; }
}

aspect A {
pointcut methodsInQuestion():
call(* goBoolean(*)) ||
call(* goByte(*)) ||
call(* goInt(*)) ||
call(* goLong(*)) ||
call(* goObject(*)) ||
call(* goNumber(*)) ||
call(* goInteger(*));
after() returning(byte b): methodsInQuestion() { Tester.event("byte"); }
after() returning(int b): methodsInQuestion() { Tester.event("int"); }
after() returning(long b): methodsInQuestion() { Tester.event("long"); }
after() returning(Object b): methodsInQuestion() { Tester.event("Object"); }
after() returning(Number b): methodsInQuestion() { Tester.event("Number"); }
after() returning(Integer b): methodsInQuestion() { Tester.event("Integer"); }

}

Loading…
Cancel
Save