diff options
-rw-r--r-- | docs/progGuideDB/semantics.xml | 44 | ||||
-rw-r--r-- | tests/ajcTestsFailing.xml | 18 | ||||
-rw-r--r-- | tests/bugs/IncompatibleAfterReturningTypeCE.java | 21 | ||||
-rw-r--r-- | tests/ehTests.xml | 10 | ||||
-rw-r--r-- | tests/new/AfterReturningParamMatching.java | 72 |
5 files changed, 119 insertions, 46 deletions
diff --git a/docs/progGuideDB/semantics.xml b/docs/progGuideDB/semantics.xml index 6e8f8f649..639ddeb9b 100644 --- a/docs/progGuideDB/semantics.xml +++ b/docs/progGuideDB/semantics.xml @@ -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> diff --git a/tests/ajcTestsFailing.xml b/tests/ajcTestsFailing.xml index c021e9451..fe3fdc664 100644 --- a/tests/ajcTestsFailing.xml +++ b/tests/ajcTestsFailing.xml @@ -24,16 +24,6 @@ </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"> <compile files="CallReference.java"/> @@ -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> diff --git a/tests/bugs/IncompatibleAfterReturningTypeCE.java b/tests/bugs/IncompatibleAfterReturningTypeCE.java deleted file mode 100644 index d935d344f..000000000 --- a/tests/bugs/IncompatibleAfterReturningTypeCE.java +++ /dev/null @@ -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 - -}
\ No newline at end of file diff --git a/tests/ehTests.xml b/tests/ehTests.xml new file mode 100644 index 000000000..da5ae284e --- /dev/null +++ b/tests/ehTests.xml @@ -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>
\ No newline at end of file diff --git a/tests/new/AfterReturningParamMatching.java b/tests/new/AfterReturningParamMatching.java new file mode 100644 index 000000000..062bfa541 --- /dev/null +++ b/tests/new/AfterReturningParamMatching.java @@ -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"); } + +}
\ No newline at end of file |