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;
|
||||
}
|
||||
|
||||
// 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 */
|
||||
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.push_back(def);
|
||||
def = "";
|
||||
|
||||
for (std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)
|
||||
{
|
||||
if (*it == "0")
|
||||
|
@ -891,20 +927,24 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
|
|||
}
|
||||
|
||||
varList.sort();
|
||||
s = "";
|
||||
for (std::list<std::string>::iterator varIter = varList.begin(); varIter != varList.end(); ++varIter)
|
||||
{
|
||||
if (!s.empty())
|
||||
s += ";";
|
||||
|
||||
s += *varIter;
|
||||
}
|
||||
s = join(varList, ';');
|
||||
|
||||
if (!s.empty())
|
||||
*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..
|
||||
ret.sort();
|
||||
ret.unique();
|
||||
|
|
|
@ -178,6 +178,8 @@ private:
|
|||
// define and then ifdef
|
||||
TEST_CASE(define_ifdef);
|
||||
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()
|
||||
{
|
||||
const char filedata[] = "char a[] = \"#endfile\";\n"
|
||||
|
|
|
@ -105,6 +105,15 @@ static std::string writestr(const std::string &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)
|
||||
{
|
||||
if (expected != actual)
|
||||
|
|
|
@ -41,6 +41,8 @@ protected:
|
|||
|
||||
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);
|
||||
|
||||
// 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 ASSERT( CONDITION ) assert(__FILE__, __LINE__, CONDITION)
|
||||
#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 TODO_ASSERT_EQUALS( EXPECTED , ACTUAL ) todoAssertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||
|
|
Loading…
Reference in New Issue