Bug 197719 - Multiple Package class hierarchy causes exceptions
Summary: Multiple Package class hierarchy causes exceptions
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.3   Edit
Hardware: PC Windows NT
: P3 major (vote)
Target Milestone: 1.6.1   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-07-24 17:55 EDT by William Headrick CLA
Modified: 2008-06-11 15:40 EDT (History)
1 user (show)

See Also:


Attachments
Test Project (2.41 KB, application/x-zip-compressed)
2007-07-24 17:56 EDT, William Headrick CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description William Headrick CLA 2007-07-24 17:55:22 EDT
Build ID: I20070625-1500

Steps To Reproduce:
I a using aspectj 1.5.4.200705211336 with Eclipse 3.3 (and AJDT).

If I have a class in test.aspects package (C1) with a method with an @AspectJ annotation and extend that class in another package, I get several Exceptions (which are caught by Eclipse) when compiling:

1)
org.aspectj.weaver.BCException
at org.aspectj.weaver.bcel.BcelShadow.createMethodGen(BcelShadow.java:3479)
at org.aspectj.weaver.bcel.BcelShadow.extractMethod(BcelShadow.java:3332)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundClosure(BcelShadow.java:2993)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundInline(BcelShadow.java:2306)
at org.aspectj.weaver.bcel.BcelAdvice.implementOn(BcelAdvice.java:272)
at org.aspectj.weaver.Shadow.i ...                 ACONST_NULL
                    ARETURN
  end public Object run(Object[])
end public class test.aspects.C3$InnerClass$AjcClosure1


2)
org.aspectj.weaver.BCException
at org.aspectj.weaver.bcel.BcelShadow.createMethodGen(BcelShadow.java:3479)
at org.aspectj.weaver.bcel.BcelShadow.extractMethod(BcelShadow.java:3332)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundClosure(BcelShadow.java:2993)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundInline(BcelShadow.java:2306)
at org.aspectj.weaver.bcel.BcelAdvice.implementOn(BcelAdvice.java:272)
at org.aspectj.weaver.Shadow.i ... nt;)V
                    ACONST_NULL
                    ARETURN
  end public Object run(Object[])
end public class test.aspects.C3$AjcClosure1

3)
java.lang.IllegalStateException
at org.aspectj.weaver.Shadow.getThisType(Shadow.java:94)
at org.aspectj.weaver.bcel.BcelShadow.createMethodGen(BcelShadow.java:3478)
at org.aspectj.weaver.bcel.BcelShadow.extractMethod(BcelShadow.java:3332)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundClosure(BcelShadow.java:2993)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundInline(BcelShadow.java:2306)
at org.aspectj.weaver.bcel.BcelAdvice.imple ... t;)V
                    ACONST_NULL
                    ARETURN
  end public Object run(Object[])
end public class test.aspects2.C2$AjcClosure3


I will attach a test project that shows the exception

More information:
Comment 1 William Headrick CLA 2007-07-24 17:56:34 EDT
Created attachment 74511 [details]
Test Project

The files inside of this Jar file should show the problem.
Comment 2 Andrew Clement CLA 2007-10-09 12:34:17 EDT
Thanks for the example code.

The problem occurs because of a generated accessor.  Here is a simpler failing case:

-- a/A.java --
package a;

public class A {
  protected void m() {}
}

-- b/B.java --
package B;

public class B extends a.A {
  protected class Inner {
    public void foo() {
      m();
    }
  }
}

-- X.aj --
public aspect X {
  void around(): call(* m()) {}
}
--

ajc -sourceroots .

java.lang.IllegalStateException:
        at org.aspectj.weaver.Shadow.getThisType(Shadow.java:94)
        at org.aspectj.weaver.bcel.BcelShadow.createMethodGen(BcelShadow.java:3478)
        at org.aspectj.weaver.bcel.BcelShadow.extractMethod(BcelShadow.java:3332)
        at org.aspectj.weaver.bcel.BcelShadow.weaveAroundInline(BcelShadow.java:2351)
        at org.aspectj.weaver.bcel.BcelAdvice.implementOn(BcelAdvice.java:272)

An accessor is generated in type B so that the call from the inner class can be made on the protected method in A.  The call to m() from the inner class calls the accessor.  It is the advising of the call made by the accessor method that causes the problem.  The method getThisType() goes bang because the accessor is static and so where the call to method m() is made, there is no 'this'.

There is a related situation for other kinds of advice, however they don't manifest as a crash like this, they simply don't match the method call joinpoint when you think they perhaps ought to.  For example:

before(): within(B.Inner) && call(* m())

will match if m() is public or not match if m() is protected - since in the protected case the call to m() has been converted to a call to the accessor method that is created in the outer class and the call to m() from the accessor is then *not* within(B.Inner).  From inside the accessor we have no idea who really made the call - so we cannot 'recover' the fact that it was a redirect from the inner type.

So... I can prevent the crash, that is easy. What to do about the wider issue is more difficult...
Comment 3 Andrew Clement CLA 2007-10-26 08:17:16 EDT
fix the crash for 1.5.4 - think about the other problem for 1.6.0
Comment 4 Andrew Clement CLA 2008-06-11 14:25:16 EDT
fix committed. avoided the crash and recognized call was from an accessor - in which case use the parameter type to the accessor as the target type (that is what the method will be called upon).

test passes.
Comment 5 Andrew Clement CLA 2008-06-11 14:29:56 EDT
when I said test passes, I meant mine passes - looking at the attached one now!
Comment 6 Andrew Clement CLA 2008-06-11 15:40:46 EDT
ok - crashes fixed in the supplied application too.  However, I am not going to correct the problem of the advice marker lines not being correct.  The generated accessor used to call through the outer class (when aMethod is called from an inner class) does not have the right line number information attached, so the line defaults to 1.  The accessor cannot have the right line number information included because it can be used from anywhere in the class.

This affects just one of the cases in the supplied test program, in C2.java the call on line 18 is redirected through an accessor and so the call comes out as occurring on line 1 (all the other advice markers are OK).  The important thing for now is that the compiler doesn't crash and the woven code runs.

If this becomes a big problem in the future I might look at asking the compiler to produce multiple accessor methods - one for each location that needs to call out to the protected method - then each could have correct line number information.