Fixed #1526 (Cppcheck checks redundant configurations)

This commit is contained in:
Zachary Blair 2010-04-15 18:37:51 +02:00 committed by Daniel Marjamäki
parent d2bb4964d0
commit 2e276576a4
4 changed files with 94 additions and 8 deletions

View File

@ -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();

View File

@ -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"

View File

@ -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)

View File

@ -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)