Fixed #1526 (Cppcheck checks redundant configurations)
This commit is contained in:
parent
d2bb4964d0
commit
2e276576a4
|
@ -69,6 +69,41 @@ static unsigned char readChar(std::istream &istr)
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Splits a string that contains the specified separator into substrings
|
||||||
|
static std::list<std::string> split(const std::string &s, char separator)
|
||||||
|
{
|
||||||
|
std::list<std::string> parts;
|
||||||
|
|
||||||
|
std::string::size_type prevPos = 0;
|
||||||
|
for (std::string::size_type pos = 0; pos < s.length(); ++pos)
|
||||||
|
{
|
||||||
|
if (s[pos] == separator)
|
||||||
|
{
|
||||||
|
if (pos > prevPos)
|
||||||
|
parts.push_back(s.substr(prevPos, pos - prevPos));
|
||||||
|
prevPos = pos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prevPos < s.length())
|
||||||
|
parts.push_back(s.substr(prevPos));
|
||||||
|
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenates a list of strings, inserting a separator between parts
|
||||||
|
static std::string join(const std::list<std::string> &list, char separator)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
for (std::list<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||||
|
{
|
||||||
|
if (!s.empty())
|
||||||
|
s += separator;
|
||||||
|
|
||||||
|
s += *it;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/** Just read the code into a string. Perform simple cleanup of the code */
|
/** Just read the code into a string. Perform simple cleanup of the code */
|
||||||
std::string Preprocessor::read(std::istream &istr, const std::string &filename, Settings *settings)
|
std::string Preprocessor::read(std::istream &istr, const std::string &filename, Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -743,6 +778,7 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
|
||||||
deflist.pop_back();
|
deflist.pop_back();
|
||||||
deflist.push_back(def);
|
deflist.push_back(def);
|
||||||
def = "";
|
def = "";
|
||||||
|
|
||||||
for (std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
|
for (std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
|
||||||
{
|
{
|
||||||
if (*it == "0")
|
if (*it == "0")
|
||||||
|
@ -891,20 +927,24 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
|
||||||
}
|
}
|
||||||
|
|
||||||
varList.sort();
|
varList.sort();
|
||||||
s = "";
|
s = join(varList, ';');
|
||||||
for (std::list<std::string>::iterator varIter = varList.begin(); varIter != varList.end(); ++varIter)
|
|
||||||
{
|
|
||||||
if (!s.empty())
|
|
||||||
s += ";";
|
|
||||||
|
|
||||||
s += *varIter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
*it = s;
|
*it = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert configurations into a canonical form: B;C;A or C;A;B => A;B;C
|
||||||
|
for (std::list<std::string>::iterator it = ret.begin(); it != ret.end(); ++it)
|
||||||
|
{
|
||||||
|
// Split the configuration into a list of defines
|
||||||
|
std::list<std::string> defs = split(*it, ';');
|
||||||
|
|
||||||
|
// Re-constitute the configuration after sorting the defines
|
||||||
|
defs.sort();
|
||||||
|
*it = join(defs, ';');
|
||||||
|
}
|
||||||
|
|
||||||
// Remove duplicates from the ret list..
|
// Remove duplicates from the ret list..
|
||||||
ret.sort();
|
ret.sort();
|
||||||
ret.unique();
|
ret.unique();
|
||||||
|
|
|
@ -178,6 +178,8 @@ private:
|
||||||
// define and then ifdef
|
// define and then ifdef
|
||||||
TEST_CASE(define_ifdef);
|
TEST_CASE(define_ifdef);
|
||||||
TEST_CASE(endfile);
|
TEST_CASE(endfile);
|
||||||
|
|
||||||
|
TEST_CASE(redundant_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2068,6 +2070,38 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void redundant_config()
|
||||||
|
{
|
||||||
|
const char filedata[] = "int main() {\n"
|
||||||
|
"#ifdef FOO\n"
|
||||||
|
"#ifdef BAR\n"
|
||||||
|
" std::cout << 1;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"#endif\n"
|
||||||
|
"\n"
|
||||||
|
"#ifdef BAR\n"
|
||||||
|
"#ifdef FOO\n"
|
||||||
|
" std::cout << 2;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"#endif\n"
|
||||||
|
"}\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(4U, actual.size());
|
||||||
|
ASSERT(actual.find("") != actual.end());
|
||||||
|
ASSERT(actual.find("BAR") != actual.end());
|
||||||
|
ASSERT(actual.find("FOO") != actual.end());
|
||||||
|
ASSERT(actual.find("BAR;FOO") != actual.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void endfile()
|
void endfile()
|
||||||
{
|
{
|
||||||
const char filedata[] = "char a[] = \"#endfile\";\n"
|
const char filedata[] = "char a[] = \"#endfile\";\n"
|
||||||
|
|
|
@ -105,6 +105,15 @@ static std::string writestr(const std::string &str)
|
||||||
return ostr.str();
|
return ostr.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestFixture::assert(const char *filename, int linenr, bool condition)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
{
|
||||||
|
++fails_counter;
|
||||||
|
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
void TestFixture::assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual)
|
||||||
{
|
{
|
||||||
if (expected != actual)
|
if (expected != actual)
|
||||||
|
|
|
@ -41,6 +41,8 @@ protected:
|
||||||
|
|
||||||
bool runTest(const char testname[]);
|
bool runTest(const char testname[]);
|
||||||
|
|
||||||
|
void assert(const char *filename, int linenr, bool condition);
|
||||||
|
|
||||||
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
|
||||||
|
|
||||||
// the vars expected and actual need to be of type double, in order to avoid overflow of unsigned int
|
// the vars expected and actual need to be of type double, in order to avoid overflow of unsigned int
|
||||||
|
@ -66,6 +68,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
|
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
|
||||||
|
#define ASSERT( CONDITION ) assert(__FILE__, __LINE__, CONDITION)
|
||||||
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||||
#define ASSERT_THROW( CMD, EXCEPTION ) try { CMD ; assertThrowFail(__FILE__, __LINE__); } catch (EXCEPTION &) { } catch (...) { assertThrowFail(__FILE__, __LINE__); }
|
#define ASSERT_THROW( CMD, EXCEPTION ) try { CMD ; assertThrowFail(__FILE__, __LINE__); } catch (EXCEPTION &) { } catch (...) { assertThrowFail(__FILE__, __LINE__); }
|
||||||
#define TODO_ASSERT_EQUALS( EXPECTED , ACTUAL ) todoAssertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
#define TODO_ASSERT_EQUALS( EXPECTED , ACTUAL ) todoAssertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||||
|
|
Loading…
Reference in New Issue