Fix #667 (Preprocessor does not handle macro inside macro correctly)

http://sourceforge.net/apps/trac/cppcheck/ticket/667
This commit is contained in:
Reijo Tomperi 2009-09-20 00:09:05 +03:00
parent 661e4504cb
commit 003e27c10e
2 changed files with 78 additions and 5 deletions

View File

@ -1221,13 +1221,18 @@ private:
std::string _name;
std::string _macro;
bool _variadic;
const std::string _prefix;
/** The macro has parantheses but no parameters.. "AAA()" */
bool _nopar;
public:
/**
* @param macro The code after #define, until end of line,
* e.g. "A(x) foo(x);"
*/
PreprocessorMacro(const std::string &macro)
: _macro(macro)
: _macro(macro), _prefix("__cppcheck__")
{
// Tokenize the macro to make it easier to handle
std::istringstream istr(macro.c_str());
@ -1267,6 +1272,41 @@ public:
}
}
/**
* To avoid name collisions, we will rename macro variables by
* adding _prefix in front of the name of each variable.
* Returns the macro with converted names
* @return e.g. "A(__cppcheck__x) foo(__cppcheck__x);"
*/
std::string renameMacroVariables()
{
// No variables
if (_params.size() == 0)
return _macro;
// Already renamed
if (_params[0].compare(0, _prefix.length(), _prefix) == 0)
return _macro;
std::string result;
result.append(_name);
result.append("(");
std::vector<std::string> values;
for (unsigned int i = 0; i < _params.size(); ++i)
{
if (i > 0)
result.append(",");
values.push_back(_prefix + _params[i]);
result.append(values.back());
}
result.append(") ");
std::string temp;
this->code(values, temp);
result.append(temp);
return result;
}
const Token *tokens() const
{
return tokenizer.tokens();
@ -1424,12 +1464,12 @@ public:
std::string Preprocessor::expandMacros(std::string code, const std::string &filename, ErrorLogger *errorLogger)
{
// Search for macros and expand them..
std::string::size_type defpos = std::string::npos;
while ((defpos > 0) && ((defpos = code.rfind("#define ", defpos)) != std::string::npos))
std::string::size_type defpos = 0;
while ((defpos = code.find("#define ", defpos)) != std::string::npos)
{
if (defpos > 0 && code[defpos-1] != '\n')
{
defpos--;
defpos++;
continue;
}
@ -1541,6 +1581,25 @@ std::string Preprocessor::expandMacros(std::string code, const std::string &file
if (macro.params().size() && pos2 >= code.length())
continue;
// Check are we in #define
std::string::size_type startOfLine = code.rfind("\n", pos1);
++startOfLine;
if (code.substr(startOfLine, 8) == "#define ")
{
// We are inside a define, make sure we don't have name collision
// by e.g. replacing the following code:
// #define B(a) A(a)
// With this:
// #define B(2a) A(2a)
std::string::size_type endOfLine = code.find("\n", pos1);
startOfLine += 8;
PreprocessorMacro tempMacro(code.substr(startOfLine, endOfLine - startOfLine));
code.erase(startOfLine, endOfLine - startOfLine);
code.insert(startOfLine, tempMacro.renameMacroVariables());
}
unsigned int numberOfNewlines = 0;
if (macro.variadic() || macro.nopar() || macro.params().size())

View File

@ -888,7 +888,21 @@ private:
const char filedata[] = "#define A B\n"
"#define B 3\n"
"A";
TODO_ASSERT_EQUALS("\n\n3", OurPreprocessor::expandMacros(filedata));
ASSERT_EQUALS("\n\n3", OurPreprocessor::expandMacros(filedata));
}
{
const char filedata[] = "#define DBG(fmt, args...) printf(fmt, ## args)\n"
"#define D(fmt, args...) DBG(fmt, ## args)\n"
"DBG(\"hello\");";
ASSERT_EQUALS("\n\nprintf(\"hello\");", OurPreprocessor::expandMacros(filedata));
}
{
const char filedata[] = "#define DBG(fmt, args...) printf(fmt, ## args)\n"
"#define D(fmt, args...) DBG(fmt, ## args)\n"
"DBG(\"hello: %d\",3);";
ASSERT_EQUALS("\n\nprintf(\"hello: %d\",3);", OurPreprocessor::expandMacros(filedata));
}
}