Bug 66687 - declare error for constructor falsely triggers on an unrelated assignment statement
Summary: declare error for constructor falsely triggers on an unrelated assignment sta...
Status: RESOLVED INVALID
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.2.1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-06-11 10:49 EDT by Michael Moser CLA
Modified: 2004-10-21 04:32 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Moser CLA 2004-06-11 10:49:22 EDT
I am also trying to decompose some of our code such, that we can easily supply 
two different versions of our code, one that supports "persistence", another 
one that does not provide that capability (but should thus also not be burdened 
with the involved code and memory overhead).


So I tried to advise the original class:
------------------------------------
...
public class Correlator {

	...
	private IEngine		engine = null;
	// private IEngine	engine;
	private IRuleParser	parser = null;

	public Correlator(IEngine engine, IRuleParser parser) {
		this.engine = engine;
		this.parser = parser;
	}

	...
------------------------------------

with this advice:

------------------------------------
	...
	// ------------------------------------------------------
	// we "extend" Correlator so that it also implements the
 	// PersistentCorrelator-interface:
	// ------------------------------------------------------
	declare parents: Correlator implements PersistentCorrelator;

	/** we define an additional attribute to hold the persistence-store: */
	private IPersistentStore Correlator.persistence = null;
	/**
	 * a new constructor for Correlator that accepts and memorizes
	 * the persistence store passed in:
	 */
   	public Correlator.new(IEngine engine, IRuleParser parser, 
   	                       IPersistentStore persistentStore) {
   		this(engine, parser); // calling the original constructor...
   		this.persistence = persistentStore;
   	}
   	// we also declare it an error if one uses the old constructor:
	declare error: 
		execution(Correlator.new(IEngine, IRuleParser))
		&& !adviceexecution() // except THIS aspect which must use it!
		: "use \"new Correlator(IEngine, IRuleParser, IPersistentStore)
\" instead!";
	...
	<more code that implements methods defined by the PersistentCorrelator 
interface here>
	...
------------------------------------

For some strange reason the declare error statement in the aspect yields me an 
error in the 1st

	private IEngine		engine = null; 
	
assignment. If I remove the "= null" assignment (since it's superfluous - the 
VM will initialize all fields to null anyway) as indicated by the

// private IEngine		engine;  

line I get the error instead in the

	this.engine = engine; 
	
assignment within the original constructor.

This can't be working as designed or is it? Why would any of these two 
assignment-statements trigger the declare error? They don't match the pointcut 
declared at all, or do they? Is there some hidden constructor-call in the code 
created by AspectJ somewhere???

The environment used was Eclipse 3.0RC1 using JSDK Sun 1.4.2-03.

Michael
Comment 1 Andrew Clement CLA 2004-08-02 03:38:36 EDT
Hi Michael,

I think several things are confusing the situation here.  Let me tackle them one
at a time.

1) When execution join points are 'reported' by the compiler - either by showing
advice against them or reporting declare error matches - the compiler reports
the first line of the method.  For example:

aspect A {
  public void foo() {
    System.err.println();
  }
  declare warning: execution(* foo(..)): "foo executing";
}

compiled, results in:
C:\ajbugs>ajc A.java
C:\ajbugs\A.java:3 warning foo executing
System.err.println();
^^^^^^^^^^^^^^^^^^^^^
        method-execution(void A.foo())
        see also: C:\ajbugs\A.java:6

1 warning


C:\ajbugs>

You can see the first line of the method has been reported.

This is due to the fact that the first line of the method contains the first
bytecode that we can 'get hold of' to report things against.

------

2) initializer statements are inlined in constructors.  If you write 
  "private IEngine engine = null";
  then that is implemented by inlining the code in each ctor. (making it 
  the first line!)

------

3) adviceexecution() matches the join point that represents execution of a piece
of advice, it does not match join points within that piece of advice (also ITDs
are not advice: only before(),after(),around() are advice).  If you want to talk
about all join points that occur whilst advice is executing, you typically use
cflow(adviceexecution()) which means execution of the advice and all join points
that occur whilst it is executing.

------

4) Finally, of course, inter type declaring your new constructor isnt removing
the original constructor, so Correlator.new(IEngine,IRuleParser) still exists in
the program and execution() of it still exists.

------

All this means that in the statement:
  declare error: 
    execution(Correlator.new(IEngine, IRuleParser))
    && !adviceexecution() // except THIS aspect which must use it!
		: "use \"new Correlator(IEngine, IRuleParser, IPersistentStore)

execution(Correlator.new(IEngine,IRuleParser)) matches and since
adviceexecution() would match only the execution join point for any defined
advice, !adviceexecution() matches everything else.  Hence you get an error -
and when it is reported, you see the first line of the constructor reported,
which happens to be the initializer that has been inlined into it.


The usual way to deal with this is:

declare error:
  call(Correlator.new(IEngine, IRuleParser)) && !within(MyPersistenceAspect)
  : "use new Correlator(IEngine, IRuleParser, IPersistentStore)";

let me know what you think.
Comment 2 Andrew Clement CLA 2004-08-09 09:37:17 EDT
Hi Michael,
I'm going to close this bug - Adrian and I are trying to make a dent in the 150
bugs and enhancements we have against AspectJ at the moment.  If you aren't
happy with my explanation of how it is working then feel free to reopen it :)
Comment 3 Adrian Colyer CLA 2004-10-21 04:32:05 EDT
Fix released as part of AspectJ 1.2.1