[Spoon-discuss] Exception inserting code when if-statement body has no curly braces

Alex Epshteyn alexander.epshteyn at gmail.com
Mon Jan 5 01:25:04 CET 2009


Ah, I figured out that I have to add a clone of the return statement
to the block! (otherwise some sort of circularity seems unavoidable)
This code works:

  public void process(CtReturn ret) {
    if (!(ret.getParent() instanceof CtBlock)) {
      CoreFactory coreFactory = ret.getFactory().Core();
      CtBlock<Object> block = coreFactory.createBlock();
      block.insertEnd(coreFactory.clone(ret));
      ret.replace(block);
    }
  }


Alex

On Sun, Jan 4, 2009 at 7:11 PM, Alex Epshteyn
<alexander.epshteyn at gmail.com> wrote:
> If I do the replace before inserting the return into the block, I end
> up with an empty block.
>
> This code:
>
>  public void process(CtReturn ret) {
>    if (!(ret.getParent() instanceof CtBlock)) {
>      CtBlock<Object> block = Factory.getLauchingFactory().Core().createBlock();
>      ret.replace(block);
>      block.insertBegin(ret);
>    }
>
> Yields:
>
>        if (x < 0) {
>        }
>
>
> But this code:
>
>  public void process(CtReturn ret) {
>    if (!(ret.getParent() instanceof CtBlock)) {
>      CtBlock<Object> block = Factory.getLauchingFactory().Core().createBlock();
>      block.insertBegin(ret);
>      ret.replace(block);
>    }
>
> Yields:
>
>        if (x < 0)
>          return;
>
> Now if I can just figure out how to combine the two... :)
>
> - Alex
>
>
>
> On Sun, Jan 4, 2009 at 6:47 PM, 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
>>>
>>
>




More information about the Spoon-discuss mailing list