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:
parent
f740277ce5
commit
7ec8e2396f
|
@ -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;
|
||||||
|
|
|
@ -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 = "";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue