Bug 41888 - call PCD fails when given subtype of defining type
Summary: call PCD fails when given subtype of defining type
Status: RESOLVED WONTFIX
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.1.0   Edit
Hardware: PC Windows NT
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Jim Hugunin CLA
QA Contact:
URL:
Whiteboard:
Keywords: info
Depends on:
Blocks:
 
Reported: 2003-08-23 00:20 EDT by Wes Isberg CLA
Modified: 2004-01-14 11:03 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Wes Isberg CLA 2003-08-23 00:20:38 EDT
AspectJ 1.0 and 1.1 are behaving differently with respect to the qualifying type
in a method call PCD. See the test case

  tests/bugs/CallReference.java

AspectJ 1.1 is not picking out join points when a subtype of the defining type
is used.

I assume 1.0 is correct (but see [1]) because it tracks the programming guide
(and the JLS). Because this might involve questions about what's correct, I'll
include (my understanding of) the definition here in case the fix is to correct
my interpretation or the programming guide.

The programming guide says, 
----
At a method call join point, the signature is a method signature 
whose qualifying type is the static type used to access the method.
----
So given

  class Super { void run() {} }
  class Sub extends Super { }
  class SubSub extends Sub { }

Super is the declaring and defining type for run().  For the call

  new SubSub().run()

SubSub is the qualifying type because the reference type qualifies the call. 
(i.e., because method dispatch occurs at runtime, with a search up the hierarchy
if a method is not implemented directly in the class of the object.  i.e., the
guide intends to follow the definition of qualifying type for methods used in
JLS 13.1.)

Further, I understood from Erik that AspectJ accounts for polymorphism by having
the pointcut match if one specifies a supertype of the signature type, so long
as the method was defined in the specified supertype (or one of its supertypes). 
So to pick out all calls to that method, one should use the declaring type (in
this case, Super); to restrict the calls matched, use a subtype.  Indeed, for
this reason, the locution 

    target(Sub) && call(void run())

evolved to address the situation where the method was being invoked through a
supertype reference, e.g.,

   ((Super) new SubSub()).run()

which would only be picked out by

  call(void Super.run())

and not by
 
  call(void SubSub.run())

even when the method was implemented in SubSub.

This is the behavior of AspectJ 1.0.

By contrast, AspectJ 1.1, given 

  call(void Sub.run())

fails to pick out the invocations

   new Sub().run()
   new SubSub().run()

though it would pick out

   new Sub().run()

if the method were also defined in Sub, and not just in Super.

Side notes:
[1] In AspectJ 1.0, if I print the signature of the join point, it emits the
defining type of the method as the type, and does not change depending on the
static type used to access the method. That would seem to be a 1.0 (and 1.1?)
limitation of the JoinPoint signature.  

[2] This should not be related to the case where older compilers use the
declaring type of the method as the qualifying type, since this bug occurs when
all sources are presented to ajc. I.e., the programming guide already
incorporates the Java 1.0-1.1 change described in "Compilation of Symbolic
References":

 http://java.sun.com/docs/books/jls/clarify.html
 http://java.sun.com/docs/books/jls/public-symref-compilation-rules.html
Comment 1 Wes Isberg CLA 2003-08-23 00:31:16 EDT
Adding keyword "info" since, if true, this is a limitation of our implementation
of the language.
Raising priority to P2 mainly to get confirmation before the next release
whether the bug is valid or reflects my misinterpretation.
Comment 2 Jim Hugunin CLA 2003-08-25 12:48:44 EDT
This is a manifestation of your issue [2] below, and you can probably fix it by
compiling with -target 1.4.  You should use javap to look at the bytecode
generated by different compilers to see when the signature of the call is
Super.run and when it is Sub.run.

You're right in that we could fix this in the case where all of the sources are
presented to ajc.  We could do this in one of two ways:
1. Modify the compiler to always generate the "correct" declaring type even when
not in 1.4 mode.  I suspect that this would have unexpected consequences in
older JVMs that were not expecting this -- which is why it is only enabled in
1.4 mode.

2. Modify the compiler to add some attributes to the .class file indicating the
"correct" signatures for these method calls.  This would require substantial
work and isn't possible before 1.2.  If we do this, it could be part of a
general approach to passing information from the compiler to the weaver, such as
the source line for method declarations, or the end bytecode for an exception
handler.

As I stated in mail to users, I consider any call PCD that uses a declaring type
which isn't the top-most type for that signature to be potentially very
confusing to the programmer and something that should be discouraged except for
very specialized cases.
Comment 3 Jim Hugunin CLA 2004-01-14 11:03:46 EST
Since we switched the default mode of the compiler to -1.4, this is only an
issue for people who compile with -1.3.  We're never going to go back and
do a large amount of work to fix this situation for the 1.3 mode, so I'm 
resolving the bug now.