Oh, sorry about the confusion. Regarding macro expansion: for any macro, we have 1) the macro definition, and 2) the macro usage. Each of them can be of two kinds: 1) having parentheses (...), or 2) not having parentheses. So you can see there are totally 4 cases to handle. Then the macro can either be simple, or nested (needs recursive expansion). I will try to explain the different cases one by one.
Case 1: Both macro definition and macro usage do not have (). Eg,
#define FIVE 5
int a = FIVE;
We can call this a
variable-like macro define / usage.
Case 2: Both macro definition and macro usage have (). Eg,
#define MUL(_x) (_x * 5)
int a = MUL(1);
We can call this a
function-like macro define / usage.
Case 3: Macro definition does not have () but macro usage does have it. Eg,
#define MUL(_x) (_x * 5)
#define OPER MUL
// OPER(1) is an example of Case 3 macro usage
int a = OPER(1);
Here, OPER is
defined as a variable-macro, but
used as a function-macro. We should expand it like a variable-macro using plain ReplaceBufferText(). In my patch I have added support for this case (the test added at the beginning of GetMacroExpendedText()).
Case 4: Macro definition has the () but macro usage does not have it. Eg,
#define MUL(_x) (_x * 5)
// MUL is an example of Case 4 macro usage
#define OPER MUL // this line is valid (but CC should not expand MUL)
// these two lines are valid
int a = OPER(1);
int b = MUL(1);
int c = MUL; // this line is invalid (CC should not expand MUL)
Here, MUL is defined as a function-like macro. But in the line "
#define OPER MUL" it is used
without parentheses. This means our CC engine should treat it like an error and leave it alone (do not expand it). We can use this behavior to stop our recursive expansion at this point, and use the final result "MUL" for the calltips.
It looks like this code above is valid, and I just create a simple test code, and it build fine under MinGW G++
[...]
Yes, this is valid, but still we should not expand it (we need to stop there and use the MUL token for our calltips). Imagine if we expand it:
#define OPER MUL
// becomes
#define OPER (_x * 5) // invalid because OPER cannot accept any arguments!
So generally our macro expansion code should always treat Case 4 like an error and don't expand it...
That is the reason for this test added:
@@ -1954,16 +1962,26 @@ bool Tokenizer::GetMacroExpendedText(const Token* tk, wxString& expandedText)
[...]
+ // don't replace anything if the [actual (or usage)] arguments are missing
+ if (!SplitArguments(actualArgs))
return false;
I hope that is clear now.
I see that the only usage of the GetMacroExpendedText() is here: (BTW: typo here? should be "expanded text"?)
Yes, here is the only usage of this function. GetMacroExpendedText() should return "true" if we want ReplaceBufferText(), and "false" if we want to leave the macro alone and don't replace. But even if there is empty () in the
macro definition we have to handle it in GetMacroExpendedText() before returning true.
And yes, it should be "expanded text".

It looks like m_Args is used to distinguish whether a macro definition is variable-like or function-like, but if I realize that even function-like macro definitions are allowed to use empty formal argument list, so the condition is not true any more.
Yes, but m_Args is not empty even if there is empty parentheses. So we can safely check for m_Args->IsEmpty(). A function-macro like this: "
#define MACRO() ..." will have in m_Args: "()". Only for variable-macro the m_Args is really empty.
BTW: it looks like ReplaceFunctionLikeMacro() only runs one level replacement, if you have several replacement rules (A -> B ->C), call this function only make a (A->B), but I think (B->C) will be happens after some GetToken() call.
I think the comment is not correct right? Since ReplacefunctionLikeMacro just do text replacement once.
Well, yes, the actual recursive expansion happens in the
next GetToken() call, but I wanted to keep the comments simple and easy to read. Technically, ReplacefunctionLikeMacro() expands
one level, and turns on the flag for further expansion in the next GetToken() or PeekToken().
In my patch there is:
+ smallTokenizer.ReplaceFunctionLikeMacro(tk);
+ tk = tree->at(tree->TokenExists(smallTokenizer.GetToken(), ...
So, full recursive expansion occurs in the GetToken(), but when we hit Case 4, GetMacroExpendedText() will return
false, and it won't be expanded further. We use that result for the calltips.