CDT/C editor enhancements/Source/header synchronization
This is a problem page. Please treat it as a discussion page and feel free to insert your comments anywhere. My open questions are in bold--Tomasz Wesołowski 18:03, 6 May 2010 (UTC)
Probably the biggest redundancy of C++ is the duplication of code between headers and modules. The most common situation is function and method signatures. A change in a header must be followed by a similar change in corresponding module. A signature of a new method also has to be created in two places (with slightly different syntax). The IDE definitely should assist the programmer here.
5/5 --Tomasz Wesołowski 18:03, 6 May 2010 (UTC)
3/5 --Sergey Prigogin 07:21, 18 May 2010 (UTC)
3/5 --Tobias Hahn 09:36, 18 May 2010 (UTC)
3/5 --Jens Elmenthaler
4/5 --Kirstin Weber 08:39, 10 June 2010 (UTC)
Please append your opinion here.
There is an existing command Source->Implement method. It allows to generate a method stub in the corresponding module for a given method definition written in the header.
This solution has several drawbacks:
- It does not assist performing any changes in method signatures
- It only works in one way (header->module)
- It is implemented in imperfect way in terms of ergonomy (i.e. needs a dialog box, takes noticable time and does not jump to the generated code immediately, despite that it's usually the programmer's intent to implement this method right after generating the stub), therefore distracting.
- It is buggy (see for example https://bugs.eclipse.org/bugs/show_bug.cgi?id=312172)
An idea is to use the Codan framework and Quick Assist for this purpose. Two different (but related) activities can be involved.
Maintaining synchronization between header and module
There are 2 options. I have labeled them as "Active" or "Passive", depending on whether the IDE would try to suggest the feature for the user in a given context or not.
Which do you prefer? Why? Please describe.
Active: via Codan and Quick Fixes
For every function or method defined in a module, check if a function or method of such name is declared in this module or in its header (if present). If there is a declaration of a function or method of the same name (and class, in case of methods), then assume that this is meant to the same function. In this case, compare the signatures (arguments, return type, constness, throw declaration) and issue a warning if the declarations don't match.
The warning would be visible both in the header and the module. It would be assisted with a Quick Fix to change the other signature in order to match the current one.
Expected workflow to change a method signature in both places would look like this:
- Find the declaration function to be altered
- Change its signature (anything besides name) - creates a warning
- Use a quick fix called "Change definition to match declaration".
Or the other way round: altering the definition and fixing the declaration with a quick fix.
A potential problem with ambiguity: What would then be the expected course of action when a header would declare
void somefunc(void) (which would be defined externally) and a module would define an overload
void somefunc(int, int) (which would be meant to be a function local to the module, without any information on the header? In this case, the warning message would be a false positive.
This situation is probably an example of bad programming style, but the IDE should behave correctly in such situations. The user is able to disable a specific warning in Codan, but this would make him
An interesting option would be to allow to surpress a specific Codan warning (e.g. with a comment) - the programmer would then be able to identify and validate those rare cases individually. Is this a feasible option here?
Passive via Quick Assist
Another, simpler approach to this task would be to simply provide a Quick Assist solution on:
- each function definition for which a declaration can be found,
- each function declaration for which a definition can be found.
The workflow would be to:
- Select a declaration or a definition of a function / method
- Run the Quick Assist (Ctrl+1), select Change signature
- Type new signature (preferably using Refactoring Boxes)
- Confirm with Enter - triggers the change in implementation if present.
This solution has the advantage of being simple, general and easy to understand, and probably also quicker to implement. A disadvantage is that it wouldn't be so obvious to find and use as the previous - it isn't directly suggested and needs to be called manually. The user would have to be aware that such a function exists.
In JDT Change Method Signature also updates all calling points. It's the most useful refactoring after Rename in my opinion (Sergey Prigogin).
Jens Elmenthaler The passive sounds better if no additional dialog is required. Otherwise I prefer typing in the code, and then let quick fix do the rest.
Implementing new functions and methods
The implementation of "active" approach would be problematic here because a function declaration without a definition may as well be an external declaration. The situation should be more obvious for class methods, but specifying a different approach for methods and functions would be inconsistent.
Therefore, a Quick Assist solution would probably be a better idea.
An expected workflow:
- Quick Assist is invoked on a symbol,
- If a symbol is a function and class method without an implementation, provide an option "Implement function/method",
- Upon selection, a method stub should be created without distactions.
The stub should be created in correct place, respecting the order of definitions. The stub shall be focused in the editor after creation to allow coding immediately; alt+left shall allow to go back to previous place.
What to do if there is no corresponding module? Ask whether to create inline method, create new file or cancel?
Jens Elmenthaler I would prefer to create the implementation file. Cancel is the fallback if time doesn't fit. I guess the option to create an inline method meant to create it in the header file, but outside the class body. If we inline, we put the code into the class body (well, partly because it's so cumbersome to do it manually;-). Possibly subject to a preference. Or have two quick fix items.
Slightly modify the existing Extract Function Refactoring
Right now I type int x; on a line by itself, select it, and then select the Refactor->Extract Function refactoring. This does just what is needed. It could be improved if I didn't have to type int x; and select it. If I could just Extract Function on a blank line no other change would be needed. Just a thought.
Bug 292851 suggests that the current "Implement method" solution is too slow
Bug 175209 asks for two-way declaration/definition generation