</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>
<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">
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>
+++ /dev/null
-
-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
-
-}
\ No newline at end of file
--- /dev/null
+
+<!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>
\ No newline at end of file
--- /dev/null
+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"); }
+
+}
\ No newline at end of file