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]
|
||||
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
|
||||
{
|
||||
Preprocessor preprocessor;
|
||||
Preprocessor preprocessor(_settings._debug);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata = "";
|
||||
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
#include <cstring>
|
||||
#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)
|
||||
{
|
||||
if (!errorLogger)
|
||||
|
@ -218,11 +223,6 @@ void Preprocessor::writeError(const std::string &fileName, const std::string &co
|
|||
errorType));
|
||||
}
|
||||
|
||||
Preprocessor::Preprocessor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static char readChar(std::istream &istr)
|
||||
{
|
||||
char ch = (char)istr.get();
|
||||
|
@ -621,13 +621,102 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata)
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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")
|
||||
return false;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
class Preprocessor
|
||||
{
|
||||
public:
|
||||
Preprocessor();
|
||||
Preprocessor(bool debug = false);
|
||||
|
||||
/**
|
||||
* Extract the code for each configuration
|
||||
|
@ -105,6 +105,9 @@ protected:
|
|||
static int getHeaderFileName(std::string &str);
|
||||
private:
|
||||
|
||||
/** Show debug information when bailing out */
|
||||
const bool _debug;
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
|
|
|
@ -86,6 +86,8 @@ private:
|
|||
TEST_CASE(elif);
|
||||
|
||||
TEST_CASE(if_cond1);
|
||||
TEST_CASE(if_cond2);
|
||||
TEST_CASE(if_cond3);
|
||||
|
||||
TEST_CASE(multiline1);
|
||||
TEST_CASE(multiline2);
|
||||
|
@ -532,6 +534,53 @@ private:
|
|||
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()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue