[Cocci] Adding a parameter to a whole call chain

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Mon Jun 8 13:49:11 CEST 2009


Apologies if I overlooked some example which already explains this. I'll
gladly use any pointer to docs or examples.

The flashrom application has some pretty deep call chains which drop one
parameter somewhere along the way. I want to add that parameter to all
functions missing it if these functions call other functions which need
the parameter. In other words, I want to pass down the parameter on an
as-needed basis.

Let me explain the problem at hand:
I want to change chip_readb(int addr) to chip_readb(struct flashchip
*flash, int addr). All of its callers have to fill in flash.
Same applies to chip_writeb(char val, int addr) to chip_writeb(struct
flashchip *flash, char val, int addr).
If a caller has a variable with matching type (either as local variable
or as parameter to the caller), that variable should be used for the
call to chip_readb. If the caller has no variable with matching type,
the caller signature should be extended to take such a variable as first
parameter.
The same applies to callers of the callers.
Functions which do not have to pass down flash should be left unchanged.

Example code before the conversion:
void write_jedec(struct flashchip *flash)
{
    erase_chip_jedec(flash);
    if (chip_readb(0))
        printf("nonzero");
    protect_jedec();
}
void erase_chip_jedec(struct flashchip *flash)
{
    char val;
    chip_writeb(0x90, 0x5555);
    val = readb(0);
    check_lowest_bit(val);
}
void protect_jedec(void)
{
    chip_writeb(0xA0, 0x5555);
}
void check_lowest_bit(char val)
{
    if (val & 0x1)
        exit(1);
}

Example code how it should look like after the conversion:
void write_jedec(struct flashchip *flash)
{
    erase_chip_jedec(flash);
    if (chip_readb(flash, 0))
        printf("nonzero");
    protect_jedec(flash);
}
void erase_chip_jedec(struct flashchip *flash)
{
    char val;
    chip_writeb(flash, 0x90, 0x5555);
    val = readb(flash, 0);
    check_lowest_bit(val);
}
void protect_jedec(struct flashchip *flash)
{
    chip_writeb(flash, 0xA0, 0x5555);
}
void check_lowest_bit(char val)
{
    if (val & 0x1)
        exit(1);
}

Note that check_lowest_bit does not get the struct flashchip * parameter
because it does not use or pass on that parameter.
write_jedec and erase_jedec already have a struct flashchip * parameter,
so their prototypes are unchanged.
protect_jedec gets a new struct flashchip * parameter because it has to
pass down that parameter to chip_writeb.
chip_readb and chip_writeb all get a new struct flashchip * parameter as
specified.

The reasons I'm not using a simple sed script are:
- Type checking
- Only adding the parameter as needed.
- Sometimes, the variables may have another name, not "flash".

Since the task is essentially recursive, a one-pass transformation may
be impossible. I have no problems running spatch repeatedly if that helps.
One way I thought of was to add "struct flashchip *as_needed" to all
functions, then eliminate those which are unneeded in a second pass.

Regards,
Carl-Daniel


More information about the Cocci mailing list