Bug 56600 - -XnoWeave has no effect for aspects containing 'declare parents'
Summary: -XnoWeave has no effect for aspects containing 'declare parents'
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.1.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Andrew Clement CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 74061 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-03-29 11:40 EST by Andrew Clement CLA
Modified: 2005-01-07 08:56 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Clement CLA 2004-03-29 11:40:31 EST
'declare parents' statements are not honored by -XnoWeave.  Take this program:

public class WhatAmI {
	
  public static void main(String[] args) {
    System.err.println("I'm a main method:");
    WhatAmI instance = new WhatAmI();
		
    // Should *not* be serializable
    if (instance instanceof java.io.Serializable)
	throw new RuntimeException("I should not be serializable");
    }
}

aspect A {
	declare parents: WhatAmI implements java.io.Serializable;
}

ajc WhatAmI.java A.java -XnoWeave

java WhatAmI

returns:

java.lang.RuntimeException: I should not be serializable
	at WhatAmI.main(WhatAmI.java:9)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:39)

The problem is that the compilation stage applies the ITD and then generates 
code for it - meaning the weaver doesn't have to do it. (and so in the case 
of -noweave the weaver can't decide *not* to do it!).  This is unlike other 
ITDs where although they are 'applied' at compile time to satisfy type checks, 
the code generator at compile time does not produce code for them - this means 
the weaver applies them again at weave time and so it can choose not to do it 
in the case of -noweave.
Comment 1 Andrew Clement CLA 2004-03-30 11:39:15 EST
There are two situations to think about:

declare parents: Blah extends SuperBlah

declare parents: Blah implements IBlah

In trying to fix the first case I get (at weave time):

error can't use declare parents to change superclass of binary form 'WhatAmI' 
(implementation limitation)

which might be reasonable but was a surprise I wasnt expecting !

This compiler limitation doesnt apply for 'declare parents: implements' 
though.  However, if I can't fix it in both cases - should I fix it for just 
one?  Is it better if we just put out a warning message if using -XnoWeave 
with "declare parents:" that says these features aren't compatible.

The other reason I wanted to fix this was -Xreweavable.  The list of aspects 
that modify a type is collected at weave time - on a subsequent weave we 
verify this list of aspects is around.  In the case of using "declare 
parents:" reweavable doesn't record that an aspect affected a type because it 
was not done by the weaver.  However, even if I did propagate this knowledge 
from compile time->weave time so it could be recorded in the reweavable state, 
it wouldn't be useful because when attempting the reweaving and reverting to 
the 'unwoven' form of the class file, it would have already had the "declare 
parents:" declarations applied.  (Am I making sense here?).
Comment 2 Andrew Clement CLA 2004-04-01 11:47:05 EST
Should I just put out an error/warning message when we see this combination of 
inputs (declare parents/XnoWeave) ... ?
Comment 3 Jim Hugunin CLA 2004-04-04 21:31:42 EDT
declare parents interacts more strongly tightly with the compiler than any 
other construct in AspectJ.  I think that for 1.2 you might have to just make 
it an xlint warning to use it with XnoWeave or Xreweavable.  Not being able to 
use declare parents with interfaces and reweavable is a real bummer.

Here's a sketch of what it would take to support declare parents properly in 
the weaver.

1. The main reason it wasn't done originally is error checking.  There are a 
lot of checks to make sure that a class properly implements an interface or 
can extend a different class.  These checks are already implemented for the 
eclipse compiler, but they need to be duplicated on ResolvedTypeX's to make 
sure that declare parents is being used correctly in the weaver.

2. After making this change, you'd need to modify the compiler to emit 
classfiles with unmodified superclass and interfaces.  This could be tricky.  
The current implementation just adds interfaces and a new superclass to the 
eclipse SourceTypeBinding objects; however, it doesn't modify the underlying 
TypeDeclarations.  You'd need a hook to modify the Classfile constructor to 
use the original interfaces and superclass from the SourceTypeBinding.  This 
is doable, but I'm almost certain would require another patch to the jdt.core 
code.
Comment 4 Andrew Clement CLA 2004-08-26 03:17:50 EDT
I have done the first part of the solution which is to get the compiler to emit
class files that don't have the modified hierarchies.  This was relatively
straightforward, I just record the original superclass and interface set before
any declare parents are processed and when emitting the class file I use the
recorded information.

For declare parents 'implements' I think that is almost enough but declare
parents extends is much more messy.  I've so far found the following checks that
need to be implemented if allowing extends at weave time:

- if you inherit methods you cannot override them and reduce their visibility
- if you inherit methods you cannot have incompatible return types (java1.5 will
make this a little messier)
- if you inherit abstract methods and you are not abstract you need to provide
an implementation
- if you inherit abstract methods and don't provide implementations you have to
be abstract
- if you override an instance method you cannot make your overridden version static
- you cannot extend a final class
- the Object class cannot be subject to declare parents extends

I think that covers many cases - of course ITDs have to be taken into account.  

I've not looked at field inheritance yet.

I've also uncovered a problem to do with

declare parents: <SomeType>+ extends <SomeClass>

If we process a subtype of <SomeType> before we process <SomeType> then you get
an error (as SomeClass doesn't typically fit into the extends hierarchy).  If we
process <SomeType> first and it just extends from Object then we can usually put
<SomeClass> in as its parent, then there is no problem when processing the
subtype of <SomeType> because one of its parents already extends <SomeClass>. 
clear? :)
Comment 5 Andrew Clement CLA 2004-09-29 04:15:25 EDT
*** Bug 74061 has been marked as a duplicate of this bug. ***
Comment 6 Andrew Clement CLA 2005-01-07 08:56:17 EST
Fix available:

BUILD COMPLETE -  build.427
Date of build: 01/07/2005 09:52:56
Time to build: 107 minutes 25 seconds
Last changed: 01/07/2005 08:08:11
Latest good AspectJ jar available at:
download.eclipse.org/technology/ajdt/dev/aspectj-DEVELOPMENT.jar

Modifying super calls in the bytecode were the main bit of implementation - the
rest of the work is checks to ensure you aren't violating the rules, as outlined
in a previous comment in this bug report.  The checks might not currently be
perfect but they are good enough for a first release of the functionality.