[aspectc-user] Any way to 'Declare error'
mike-mortensen at comcast.net
mike-mortensen at comcast.net
Fri Jan 6 22:31:50 CET 2006
After my last question (aspects advising aspects), the fact that I'm asking for something which does
exist in AspectJ may sound like I'm going through the AspectJ manual and comparing features...
but this question came from 2 AOP-based refactorings I've worked in with legacy code.
I report on one of these in a paper that will be in the AOSD'06 industry track -- not a shameless
plug, but full disclosure that any help here helps me address the feedback of a reviewer who
asked if this problem (below) can be addressed.
I have cases where orthogonal, cross-cutting code is factored out... A 'Timer' that was manually
used in some functions (by hand in C++) to do something like this:
void FOO() {
Timer t;
t.startTimer();
/* do stuff */
t.endTimer();
AppLogger("Function FOO", t.getTime() );
}
and then the AppLogger function writes the function name, other info, and the results of t.getTime()
to the screen, also to a log file, and so forth. This is part of a large, batch-oriented CAD program
that can run for hours. Users like to check on the log file and see where the program is at, how long each step is taking, and so forth.
Taking out the use of Timer objects is done manually. Then, I either modify the function name to match a pointcut regex (e.g. use 'tmr%' as the pointcut and rename it tmrFOO) or you use || to include 'FOO' the pointcut list.
It would be helpful if the aspect that uses around advice to create a Timer object and call the AppLogger for the functions that should be timed and logged could have a second piece of advice that could stipulate:
For any joinpoint outside this aspect that mathces Timer::startTimer, declare an error.
That way, if you forgot to factor some of them out, the weaving process would flag them (of course, this assumes you want all factored out).
I tried, using the C++ #error directive in the advice body to do this, but of course then the weaver hits that and (correctly) bails out, emiting the message... And, following the directive, this happens regardless of whether the pointcut actually matches anything.
I also tried another C++ trick, you can declare a template with a name that indicates the issue:
template <bool> struct DirectCallOf__StartTimer;
template <> struct DirectCallOf__StartTimer<true> {};
and then instantiate it in the advice body with the unspecialized (unimplemented) flavor:
DirectCallOf__StartTimer<false>;
But this doesn't work either, because then the instantiation of DirectCallOf__StartTimer<false> is
in the Aspect body in the generated C++ code, and the template instantiation fails (as expected), but it fails regardless of whether or not the any code uses the join point since the aspect itself is (correctly) created in the generated code regardless of whether or not its advise is actually 'called' from anywhere that matches the joinpoint.
One could use a low tech solution (use 'grep' to look at all the source code for instances of Timers) but this breaks down for more complex patterns.
Since AspectC++ does a full parse of the C++ code, the weaver 'knows' if any code matches a joinpoint.
I have been using XML file produced by AspectC++ (I use -r AOP.xml when weaving), and so I could
look for the occurrence of the joinpoint of interest in there (since if won't be in that file if it doesn't match anything). I have used this file to implement simple assertions in the C++ code that are checked by a small 'static checker' app. Code can indicate that advice IS or IS NOT expected for a certain line (and even the name of the aspect that should or should not advise it). I also implemented a check for advice that is never used since that usually (for me) means I messed up the join point and I like to be told before compiling the woven code that nothing matched some advice I've written. So I'm comfortable doing this, and could implement it without too many lines of code since I'm already using an XML parser on that file, but I hate to build too much around the weaver and be too dependent on the XML file, especially since an AspectJ-like declare error may be possible to do directly.
Does anyone know of a AspectC++/C++ idiom to enforce that triggers a static compilation error if and only if any base code actually matches a certain join point?
In this case (Timing/Logging) it isn't a big deal, but on a more complex example where around advice does some cleanup, a miscue between the base code and advice results on 'delete' being called twice on the same object.
More information about the aspectc-user
mailing list