[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