tags:

views:

552

answers:

7

Hi,

I'm working on a refactoring tool for C with preprocessor support... I don't know the kind of refactoring involved in large C projects and I would like to know what people actually do when refactoring C code (and preprocessor directives)

I'd like to know also if some features that would be really interesting are not present in any tool and so the refactoring has to be done completely manually... I've seen for instance that Xref could not refactor macros that are used as iterators (don't know exactly what that means though)...

thanks

A: 

For C:

  • Parameters to struct
  • Extract function / Extract Macro

For C++:

  • Generating a class template from a class and type(s) would be nice.

Good luck. Refactoring C/C++ sounds painful.

jfclavette
what do you mean by extract ...take a block of code and define a macro from that...Thanks, it is actually painful...but life is pain..
LB
A: 

I will tell you honestly that there are no good tools for refactoring C++ like there are for Java. Most of it will be painful search and replace, but this depends on the actual task. Look at Netbeans and Eclipse C++ plugins.

I've seen for instance that Xref could not refactor macros that are used as iterators (don't know exactly what that means though)

To be honest, you might be in over your head - consider if you are the right person for this task.

Shane C. Mason
+2  A: 

Huge topic!

  • The stuff I need to clean up is contorted nests of #ifdefs. A refactoring tool would understand when conditional stuff appears in argument lists (function declaration or definitions), and improve that.

  • If it was really good, it would recognize that

    #if defined(SysA) || defined(SysB) || ... || defined(SysJ)
    

    was really equivalent to:

    #if !defined(SysK) && !defined(SysL)
    

    If you managed that, I'd be amazed.

  • It would allow me to specify 'this macro is now defined - which code is visible' (meaning, visible to the compiler); it would also allow me to choose to see the code that is invisible.

  • It would handle a system spread across over 100 top-level directories, with varying levels of sub-directories under those. It would handle tens of thousands of files, with lengths of 20K lines in places.

  • It would identify where macro definitions come from makefiles instead of header files (aargh!).

Jonathan Leffler
that's a huge topic i know...command line macros are awful...:-)...The mutual exclusion between macros is impossible to obtain I think because you don't know what is the set of options you have...I've been looking at the Kconfig language in the linux kernel...with this kind of thing could do the trick...thanks
LB
See the <a href="http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html">DMS Software Reengineering Toolkit</a>. One of the many tasks it has been used for is to simplify preprocessor conditionals; see paper on this topic at the same website. Your example is hard to do (where's would it get the knowledge that there are only L mutually exclusive switches?) without adding extra rules, but in fact you could add exactly that rule. It does everything you requested, and has been proven by applying to systems of 35 million lines of C code.
Ira Baxter
@Ira Baxter: thanks for the information. Note that comments don't accept HTML anchor notation - so the link appears bust when clicked because the web site doesn't recognize the '`">DMS`' at the end.
Jonathan Leffler
+1  A: 

Macros can often get quite complex, so I wouldn't try supporting much more than simple renaming.

splicer
no pain no gain...cpp is quite blunt but you have to support it and find a way to handle it...that's my job...:-)
LB
Well, best of luck!
splicer
A: 

If you can handle reliable renaming of various types, variables and macros over a big project with an arbitrarily complex directory hierarchy, I want to use your product.

obecalp
Have you ever tried Coccinelle? It works well on Linux for that purpose! Except maybe for macros...
Nico
+2  A: 

Well, since it is part of the preprocessor... #include refactoring is a huge huge topic and I'm not aware of any tools that do it really well.

Trivial problems a tool could tackle:

  • Enforcing consistent case and backslash usage in #includes
  • Enforce a consistent header guarding convention, automatically add redundant external guards, etc.

Harder problems a tool could tackle:

  • Finding and removing spurious includes.
  • Suggest the use of predeclarations wherever practical.

For macros... perhaps some sort of scoping would be interesting, where if you #define a macro inside a block, the tool would automatically #undef it at the end of a block. Other quick things I can think of:

  • A quick analysis on macro safety could be helpful as a lot of people still don't know to use do { } while (0) and other techniques.
  • Alternately, find and flag spots where expressions with side-effects are passed as macro arguments. This could possibly be really helpful for things like... asserts with unintentional side-effects.
Dan Olson
I am aware of this #include problem...I'm already working on that...what do you mean by predeclaration ?I was thinking of this do while analysis (also if there's a ';' at the end of a macro definition...)...side effects that's tough... thx...
LB
Predeclaration, I mean... people often #include headers to get a struct definition when they could predeclare it with just "struct MyStruct;". Finding and flagging those sorts of situations could be really helpful, and easy. It'd go something like "is struct used in file? Is it used as a pointer or reference in every case? is it defined in the file? No? Then it could be predeclared and an include could potentially be removed."
Dan Olson
+2  A: 

Anybody interested in this (specific to C), might want to take a look at the coccinelle tool:

Coccinelle is a program matching and transformation engine which provides the language SmPL (Semantic Patch Language) for specifying desired matches and transformations in C code. Coccinelle was initially targeted towards performing collateral evolutions in Linux. Such evolutions comprise the changes that are needed in client code in response to evolutions in library APIs, and may include modifications such as renaming a function, adding a function argument whose value is somehow context-dependent, and reorganizing a data structure. Beyond collateral evolutions, Coccinelle is successfully used (by us and others) for finding and fixing bugs in systems code.

none
+1: just for the tool, know it very well, love it.
LB