Fix ticket #267 (Glued define and define name in output text)

The handling of ifdef configurations where rewritten. Either a
configuration is handled properly or it is not handled at all.
This commit is contained in:
Daniel Marjamäki 2009-06-26 13:19:55 +02:00
parent f740277ce5
commit 7ec8e2396f
5 changed files with 151 additions and 9 deletions

View File

@ -8,3 +8,4 @@ run_cmd=
[files] [files]
current_page=0 current_page=0
FILE_NAME_0=18014;1;0;16;1;1;0;/home/danmar/cppcheck/test/testpreprocessor.cpp;

View File

@ -331,7 +331,7 @@ unsigned int CppCheck::check()
try try
{ {
Preprocessor preprocessor; Preprocessor preprocessor(_settings._debug);
std::list<std::string> configurations; std::list<std::string> configurations;
std::string filedata = ""; std::string filedata = "";

View File

@ -32,6 +32,11 @@
#include <cstring> #include <cstring>
#include <vector> #include <vector>
Preprocessor::Preprocessor(bool debug) : _debug(debug)
{
}
void Preprocessor::writeError(const std::string &fileName, const std::string &code, size_t endPos, ErrorLogger *errorLogger, const std::string &errorType, const std::string &errorText) void Preprocessor::writeError(const std::string &fileName, const std::string &code, size_t endPos, ErrorLogger *errorLogger, const std::string &errorType, const std::string &errorText)
{ {
if (!errorLogger) if (!errorLogger)
@ -218,11 +223,6 @@ void Preprocessor::writeError(const std::string &fileName, const std::string &co
errorType)); errorType));
} }
Preprocessor::Preprocessor()
{
}
static char readChar(std::istream &istr) static char readChar(std::istream &istr)
{ {
char ch = (char)istr.get(); char ch = (char)istr.get();
@ -621,13 +621,102 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata)
deflist.pop_back(); deflist.pop_back();
} }
// convert configurations: "defined(A) && defined(B)" => "A;B"
for (std::list<std::string>::iterator it = ret.begin(); it != ret.end(); ++it)
{
std::string s(*it);
if (s.find("&&") != std::string::npos)
{
Tokenizer tokenizer;
std::istringstream istr(s.c_str());
tokenizer.tokenize(istr, "");
s = "";
const Token *tok = tokenizer.tokens();
while (tok)
{
if (Token::Match(tok, "defined ( %var% )"))
{
s = s + tok->strAt(2);
tok = tok->tokAt(4);
if (tok && tok->str() == "&&")
{
s += ";";
tok = tok->next();
}
}
else if (Token::Match(tok, "%var% ;"))
{
s += tok->str() + ";";
tok = tok->tokAt(2);
}
else
{
s = "";
break;
}
}
if (!s.empty())
*it = s;
}
}
// cleanup unhandled configurations..
for (std::list<std::string>::iterator it = ret.begin(); it != ret.end();)
{
const std::string &s(*it);
if (s.find("&&") != std::string::npos || s.find("||") != std::string::npos)
{
// unhandled ifdef configuration..
if (_debug)
std::cout << "unhandled configuration: " << s << std::endl;
ret.erase(it++);
}
else
++it;
}
return ret; return ret;
} }
bool Preprocessor::match_cfg_def(std::string cfg, const std::string &def) bool Preprocessor::match_cfg_def(std::string cfg, std::string def)
{ {
//std::cout << "cfg: \"" << cfg << "\" ";
//std::cout << "def: \"" << def << "\"";
for (std::string::size_type pos = def.find("defined("); pos != std::string::npos; pos = def.find("defined(", pos + 1))
{
// The character before "defined" must not be '_' or alphanumeric
unsigned char chPrev = (pos > 0) ? def[pos-1] : ' ';
if (chPrev == '_' || std::isalnum(chPrev))
continue;
// Extract the parameter..
std::string::size_type pos2 = def.find(")", pos);
if (pos2 == std::string::npos)
continue;
std::string::size_type pos1 = pos + 8;
const std::string par(def.substr(pos1, pos2 - pos1));
// TODO: better checking if parameter is defined
const bool isdefined(cfg.find(par) != std::string::npos);
def.erase(pos, pos2 + 1 - pos);
def.insert(pos, isdefined ? "1" : "0");
}
while (def.find("1&&") != std::string::npos)
{
def.erase(def.find("1&&"), 3);
}
//std::cout << " => \"" << def << "\"" << std::endl;
if (def == "0") if (def == "0")
return false; return false;

View File

@ -31,7 +31,7 @@
class Preprocessor class Preprocessor
{ {
public: public:
Preprocessor(); Preprocessor(bool debug = false);
/** /**
* Extract the code for each configuration * Extract the code for each configuration
@ -105,6 +105,9 @@ protected:
static int getHeaderFileName(std::string &str); static int getHeaderFileName(std::string &str);
private: private:
/** Show debug information when bailing out */
const bool _debug;
/** /**
* Remove space that has new line character on left or right side of it. * Remove space that has new line character on left or right side of it.
* *
@ -120,7 +123,7 @@ private:
static std::string getdef(std::string line, bool def); static std::string getdef(std::string line, bool def);
static bool match_cfg_def(std::string cfg, const std::string &def); static bool match_cfg_def(std::string cfg, std::string def);
/** /**
* Search includes from code and append code from the included * Search includes from code and append code from the included

View File

@ -86,6 +86,8 @@ private:
TEST_CASE(elif); TEST_CASE(elif);
TEST_CASE(if_cond1); TEST_CASE(if_cond1);
TEST_CASE(if_cond2);
TEST_CASE(if_cond3);
TEST_CASE(multiline1); TEST_CASE(multiline1);
TEST_CASE(multiline2); TEST_CASE(multiline2);
@ -532,6 +534,53 @@ private:
ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size())); ASSERT_EQUALS(2, static_cast<unsigned int>(actual.size()));
} }
void if_cond2()
{
const char filedata[] = "#ifdef A\n"
"a\n"
"#endif\n"
"#if defined(A) && defined(B)\n"
"ab\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]);
ASSERT_EQUALS("\na\n\n\n\n\n", actual["A"]);
ASSERT_EQUALS("\na\n\n\nab\n\n", actual["A;B"]);
}
void if_cond3()
{
const char filedata[] = "#ifdef A\n"
"a\n"
"#if defined(B) && defined(C)\n"
"abc\n"
"#endif\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Preprocessor preprocessor;
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(3, static_cast<unsigned int>(actual.size()));
ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]);
ASSERT_EQUALS("\na\n\n\n\n\n", actual["A"]);
ASSERT_EQUALS("\na\n\nabc\n\n\n", actual["A;B;C"]);
}
void multiline1() void multiline1()
{ {