[Spoon-discuss] Exception inserting code when if-statement body has no curly braces
Renaud Pawlak
renaud.pawlak at gmail.com
Tue Jan 6 08:49:01 CET 2009
When I said "concurrently", I did not mean in parallel, I meant
"during the same phase". Indeed, during a given phase, a unique
visitor scans the AST and upcalls all the processors. So if a
processor modifies the AST it kind of need to be aware of how the
visitor works in order to avoid confusing other processors (one of the
typical effect being the problem you ran into).
On Mon, Jan 5, 2009 at 9:14 PM, Alex Epshteyn
<alexander.epshteyn at gmail.com> wrote:
> Thanks for letting me know about the Query interface!
>
> I'm running Spoon in standalone mode, and it seems that the processors
> are invoked strictly in the order they are specified on the command
> line, not in parallel.
>
> Alex
>
> On Sun, Jan 4, 2009 at 7:31 PM, Renaud Pawlak <renaud.pawlak at gmail.com> wrote:
>> Hi Alex,
>>
>> What you do seems ok, however, it is probably not a good idea to work
>> in different processors because they actually modify the same part of
>> the AST. Because they concurently modify the same AST parts, Spoon
>> will probably get confused, which probably will explain the strange
>> result. In that case, you have two solutions:
>>
>> 1. you entirely process the program with the first processor during a
>> first pass, and then process again with your other processor during a
>> second pass. I am not sure of the details anymore to do it, but there
>> is a way to do it by overloading the processingDone method of your
>> first processor and manually add the other processor to the
>> ProcessingManager (Processor.getEnvironnement().getProcessingManager)
>> [I think that there is a simpler way but I cant remember it after a
>> quick look to the API].
>>
>> 2. Use http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/Query.html
>> to iterate on the returns and do the job all in the same method
>> processor.
>>
>> So, I strongly suggest the second solution...
>>
>> BTW, I have just recieved your email and seen that you made it work
>> with 2 processors (bravo, cloning was a good idea). Solution 2 is
>> still valid with one processor and probably safer in the long run.
>>
>> Cheers,
>> /Renaud
>>
>> On Mon, Jan 5, 2009 at 12:47 AM, Alex Epshteyn
>> <alexander.epshteyn at gmail.com> wrote:
>>> Hi Renaud,
>>>
>>> I had the same intuition, and I tried writing a separate pre-processor
>>> for this, but did not succeed:
>>>
>>> public class ReturnStmtProcessor extends AbstractProcessor<CtReturn> {
>>> public void process(CtReturn ret) {
>>> if (!(ret.getParent() instanceof CtBlock)) {
>>> CtBlock block = Factory.getLauchingFactory().Core().createBlock();
>>> block.insertEnd(ret);
>>> ret.replace(block);
>>> }
>>> }
>>> }
>>>
>>> Running this processor before my method processor seems to just take
>>> the return statement out of the AST somehow. The result is that the
>>> method processor (from my previous) email seems to ignore this return
>>> statement.
>>>
>>> Code output:
>>>
>>> public void foo(int x, float y) {
>>> {
>>> com.stackspooner.main.client.VirtualCallStack.enterMethod("0"
>>> ,x ,y);
>>> }
>>> if (x < 0)
>>> return ;
>>>
>>> if (x == 0)
>>> zero();
>>> else
>>> positive();
>>> {
>>> com.stackspooner.main.client.VirtualCallStack.leaveMethod("0");
>>> }
>>> }
>>>
>>>
>>> Expected output:
>>>
>>> public void foo(int x, float y) {
>>> {
>>> com.stackspooner.main.client.VirtualCallStack.enterMethod("0"
>>> ,x ,y);
>>> }
>>> if (x < 0) {
>>> com.stackspooner.main.client.VirtualCallStack.leaveMethod("0");
>>> return ;
>>> }
>>> if (x == 0)
>>> zero();
>>> else
>>> positive();
>>> {
>>> com.stackspooner.main.client.VirtualCallStack.leaveMethod("0");
>>> }
>>> }
>>>
>>> I think I'm doing exactly what you suggested but in a separate processor.
>>>
>>>> Iterate on the CtReturn list returned by the filter
>>>
>>> I'm not sure how to do this with spoon. I only see methods like
>>> insertBefore and insertAfter, and replace, that accept the filter as
>>> an argument, but I don't see a method like block.search(filter)...
>>> Either way, replacing the return statement with a block containing it
>>> doesn't seem to work...
>>>
>>> Thanks for your help!
>>> Alex
>>>
>>> P.S.
>>>
>>> In case you're wondering about my project - I'm trying to instrument
>>> Java code, which will be compiled to Javascript using the GWT
>>> compiler, to retain stack traces corresponding to the original Java
>>> code, not javascript, in case of an exception. So I'm instrumenting
>>> the entry point and all return statements (but purposely not throw
>>> statements) of each method to push/pop items to/from a simulated call
>>> stack.
>>>
>>> I heard about Spoon a few years ago when working with Eliot Moss and
>>> Emery Berger at the University of Massachusetts, and happy to finally
>>> have a chance to try it out!
>>>
>>>
>>>
>>>
>>> On Sun, Jan 4, 2009 at 10:56 AM, Renaud Pawlak <renaud.pawlak at gmail.com> wrote:
>>>> Hi Alex,
>>>>
>>>> The only way is to add the block (curly brackets) when it is not
>>>> there. Iterate on the CtReturn list returned by the filter, then for
>>>> each CtReturn, check that the parent (CtElement.getParent) is a
>>>> CtBlock. If it is, proceed like you did before. If it not, create a
>>>> new empty CtBlock with the factory and add the return and the
>>>> endMethod statements. Then call the CtElement.replace(CtElement)
>>>> method on the return statement with your new block as a parameter.
>>>>
>>>> Note that the insertBefore method could do this operation
>>>> transparently but it could be a little bit too invasive to modify the
>>>> AST that much... insertBefore assumes that the target statement is
>>>> within a block...
>>>>
>>>> Cheers,
>>>> /Renaud
>>>>
>>>> On Sun, Jan 4, 2009 at 12:28 AM, Alex Epshteyn
>>>> <alexander.epshteyn at gmail.com> wrote:
>>>>> I'm trying to insert some code before every return statement in each
>>>>> method. There is a problem when a return statement occurs inside a
>>>>> block with no curly braces like this:
>>>>>
>>>>>
>>>>> /** Spoon throws an exception when trying to instrument a block with
>>>>> no curlies around it */
>>>>> public void foo(int x) {
>>>>> if (x < 0)
>>>>> return; // will fail here
>>>>> if (x == 0) {
>>>>> return; // this is OK because curly braces present
>>>>> }
>>>>> else
>>>>> positive(xStr);
>>>>> }
>>>>>
>>>>> Spoon throws:
>>>>>
>>>>> java.lang.ClassCastException: spoon.support.reflect.code.CtIfImpl
>>>>> cannot be cast to spoon.reflect.code.CtBlock
>>>>> at spoon.support.reflect.code.CtStatementImpl.insertBefore(CtStatementImpl.java:78)
>>>>>
>>>>>
>>>>> Here is my Processor code:
>>>>>
>>>>> public void process(CtMethod method) {
>>>>> ...
>>>>> // instrument all return statements
>>>>> // TODO: if statements without curly braces will throw an
>>>>> exception: java.lang.ClassCastException:
>>>>> spoon.support.reflect.code.CtIfImpl cannot be cast to
>>>>> spoon.reflect.code.CtBlock
>>>>>
>>>>> method.getBody().insertBefore(
>>>>> new TypeFilter<CtReturn>(CtReturn.class),
>>>>> Substitution.substituteMethodBody(
>>>>> (CtClass) method.getDeclaringType(),
>>>>> createTemplate(methodId, paramNames), "endMethod"));
>>>>> }
>>>>>
>>>>>
>>>>> I'm using Spoon 1.4. Would appreciate your assistance in finding a
>>>>> workaround to this problem.
>>>>>
>>>>> Thanks,
>>>>> Alex
>>>>>
>>>>> _______________________________________________
>>>>> Spoon-discuss mailing list
>>>>> Spoon-discuss at lists.gforge.inria.fr
>>>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/spoon-discuss
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Renaud Pawlak, Professor
>>>> ISEP - 21 rue d'Assas 75006 Paris, France
>>>> Head of the Computer Engineering Department
>>>> Head of ISEP Research and Consulting for Computer Engineering
>>>> Phone: +33 149 54 52 78
>>>> Cell #1: +33 6 37 29 12 15
>>>> Cell #2: +33 6 36 47 06 01
>>>> Fax: +33 1 49 54 52 51
>>>> http://renaudpawlak.wikidot.com
>>>>
>>>> _______________________________________________
>>>> Spoon-discuss mailing list
>>>> Spoon-discuss at lists.gforge.inria.fr
>>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/spoon-discuss
>>>>
>>>
>>> _______________________________________________
>>> Spoon-discuss mailing list
>>> Spoon-discuss at lists.gforge.inria.fr
>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/spoon-discuss
>>>
>>
>>
>>
>> --
>> Renaud Pawlak, Professor
>> ISEP - 21 rue d'Assas 75006 Paris, France
>> Head of the Computer Engineering Department
>> Head of ISEP Research and Consulting for Computer Engineering
>> Phone: +33 149 54 52 78
>> Cell #1: +33 6 37 29 12 15
>> Cell #2: +33 6 36 47 06 01
>> Fax: +33 1 49 54 52 51
>> http://renaudpawlak.wikidot.com
>>
>> _______________________________________________
>> Spoon-discuss mailing list
>> Spoon-discuss at lists.gforge.inria.fr
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/spoon-discuss
>>
>
> _______________________________________________
> Spoon-discuss mailing list
> Spoon-discuss at lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/spoon-discuss
>
--
Renaud Pawlak, Professor
ISEP - 21 rue d'Assas 75006 Paris, France
Head of the Computer Engineering Department
Head of ISEP Research and Consulting for Computer Engineering
Phone: +33 149 54 52 78
Cell #1: +33 6 37 29 12 15
Cell #2: +33 6 36 47 06 01
Fax: +33 1 49 54 52 51
http://renaudpawlak.wikidot.com
More information about the Spoon-discuss
mailing list