Solution for ticket #3353 'Allow explicit undef's for configuration'

Signed-off-by: makulik <g-makulik@t-online.de>
This commit is contained in:
makulik 2011-11-30 20:24:01 +01:00
parent 414e0ecc3c
commit 1e8fc71f8e
6 changed files with 274 additions and 4 deletions

View File

@ -324,6 +324,32 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
_settings->userDefines += ";";
_settings->userDefines += define;
}
// User undef
else if (strncmp(argv[i], "-U", 2) == 0)
{
std::string undef;
// "-U undef"
if (strcmp(argv[i], "-U") == 0)
{
++i;
if (i >= argc || strncmp(argv[i], "-", 1) == 0 ||
strncmp(argv[i], "--", 2) == 0)
{
PrintMessage("cppcheck: argument to '-U' is missing.");
return false;
}
undef = argv[i];
}
// "-Uundef"
else
{
undef = 2 + argv[i];
}
_settings->userUndefs.insert(undef);
}
// Include paths
else if (strncmp(argv[i], "-I", 2) == 0) {
@ -676,6 +702,10 @@ void CmdLineParser::PrintHelp()
" Use '-D' to limit the checking. When '-D' is used the\n"
" checking is limited to the given configuration.\n"
" Example: '-DDEBUG=1 -D__cplusplus'.\n"
" -U<ID> By default Cppcheck checks all configurations.\n"
" Use '-U' to explicitely hide certain #ifdef <ID> code\n"
" paths from checking.\n"
" Example: '-UDEBUG'\n"
" --enable=<id> Enable additional checks. The available ids are:\n"
" * all\n"
" Enable all checks\n"

View File

@ -739,8 +739,10 @@ void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::str
std::list<std::string> configs;
std::string data;
preprocess(istr, data, configs, filename, includePaths);
for (std::list<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)
result[ *it ] = Preprocessor::getcode(data, *it, filename, _settings, _errorLogger);
for (std::list<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it) {
if (_settings && (_settings->userUndefs.find(*it) == _settings->userUndefs.end()))
result[ *it ] = Preprocessor::getcode(data, *it, filename, _settings, _errorLogger);
}
}
std::string Preprocessor::removeSpaceNearNL(const std::string &str)
@ -1539,6 +1541,24 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
if (line.compare(0, 8, "#define ") == 0) {
match = true;
if (settings) {
typedef std::set<std::string>::iterator It;
for (It it = settings->userUndefs.begin(); it != settings->userUndefs.end(); ++it) {
std::string::size_type pos = line.find_first_not_of(' ',8);
if (pos != std::string::npos) {
std::string::size_type pos2 = line.find(*it,pos);
if ((pos2 != std::string::npos) &&
((line.size() == pos2 + (*it).size()) ||
(line[pos2 + (*it).size()] == ' ') ||
(line[pos2 + (*it).size()] == '('))) {
match = false;
break;
}
}
}
}
for (std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it)
match &= bool(*it);

View File

@ -150,6 +150,9 @@ public:
/** @brief defines given by the user */
std::string userDefines;
/** @brief undefines given by the user */
std::set<std::string> userUndefs;
/** @brief Experimental 2 pass checking of files */
bool test_2_pass;

View File

@ -105,6 +105,7 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
<arg choice="opt"><option>--append=&lt;file&gt;</option></arg>
<arg choice="opt"><option>--check-config</option></arg>
<arg choice="opt"><option>-D&lt;id&gt;</option></arg>
<arg choice="opt"><option>-U&lt;id&gt;</option></arg>
<arg choice="opt"><option>--enable=&lt;id&gt;</option></arg>
<arg choice="opt"><option>--error-exitcode=&lt;n&gt;</option></arg>
<arg choice="opt"><option>--errorlist</option></arg>
@ -170,8 +171,15 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
<para>By default Cppcheck checks all configurations. Use -D to limit the checking. When -D is used the checking is limited to the given configuration.
Example: -DDEBUG=1 -D__cplusplus</para>
</listitem>
</varlistentry>
<varlistentry>
</varlistentry>
<varlistentry>
<term><option>-U&lt;id&gt;</option></term>
<listitem>
<para>By default Cppcheck checks all configurations. Use '-U' to explicitely hide certain #ifdef &lt;id&gt; code paths from checking.
Example: '-UDEBUG'</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--enable=&lt;id&gt;</option></term>
<listitem>
<para>Enable additional checks. The available ids are:

View File

@ -120,6 +120,12 @@ private:
TEST_CASE(checkconfig);
TEST_CASE(unknownParam);
TEST_CASE(undefs_noarg);
TEST_CASE(undefs_noarg2);
TEST_CASE(undefs_noarg3);
TEST_CASE(undefs);
TEST_CASE(undefs2);
}
@ -923,6 +929,54 @@ private:
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(3, argv));
}
void undefs() {
REDIRECT;
const char *argv[] = {"cppcheck", "-U_WIN32", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(3, argv));
ASSERT_EQUALS(1, settings.userUndefs.size());
ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end());
}
void undefs2() {
REDIRECT;
const char *argv[] = {"cppcheck", "-U_WIN32", "-UNODEBUG", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(4, argv));
ASSERT_EQUALS(2, settings.userUndefs.size());
ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end());
ASSERT(settings.userUndefs.find("NODEBUG") != settings.userUndefs.end());
}
void undefs_noarg() {
REDIRECT;
const char *argv[] = {"cppcheck", "-U"};
Settings settings;
CmdLineParser parser(&settings);
// Fails since -U has no param
ASSERT_EQUALS(false, parser.ParseFromArgs(2, argv));
}
void undefs_noarg2() {
REDIRECT;
const char *argv[] = {"cppcheck", "-U", "-v", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
// Fails since -U has no param
ASSERT_EQUALS(false, parser.ParseFromArgs(4, argv));
}
void undefs_noarg3() {
REDIRECT;
const char *argv[] = {"cppcheck", "-U", "--quiet", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
// Fails since -U has no param
ASSERT_EQUALS(false, parser.ParseFromArgs(4, argv));
}
};
REGISTER_TEST(TestCmdlineParser)

View File

@ -235,6 +235,16 @@ private:
// Defines are given: test Preprocessor::handleIncludes
TEST_CASE(def_handleIncludes);
TEST_CASE(def_missingInclude);
// Using -U to undefine symbols
TEST_CASE(undef1);
TEST_CASE(undef2);
TEST_CASE(undef3);
TEST_CASE(undef4);
TEST_CASE(undef5);
TEST_CASE(undef6);
TEST_CASE(undef7);
}
@ -3031,6 +3041,151 @@ private:
ASSERT_EQUALS("", errout.str());
}
}
void undef1() {
Settings settings;
const char filedata[] = "#ifdef X\n"
"Fred & Wilma\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X");
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\n\n\n", actual[""]);
}
void undef2() {
Settings settings;
const char filedata[] = "#ifndef X\n"
"Fred & Wilma\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X");
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\nFred & Wilma\n\n", actual[""]);
}
void undef3() {
Settings settings;
const char filedata[] = "#define X\n"
"#ifdef X\n"
"Fred & Wilma\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X"); // User undefs should override internal defines
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\n\n\n\n", actual[""]);
}
void undef4() {
Settings settings;
const char filedata[] = "#define X Y\n"
"#ifdef X\n"
"Fred & Wilma\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X"); // User undefs should override internal defines
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\n\n\n\n", actual[""]);
}
void undef5() {
Settings settings;
const char filedata[] = "#define X() Y\n"
"#ifdef X\n"
"Fred & Wilma\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X"); // User undefs should override internal defines
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
ASSERT_EQUALS("\n\n\n\n", actual[""]);
}
void undef6() {
Settings settings;
const char filedata[] = "#define X Y\n"
"#ifdef X\n"
"Fred & Wilma\n"
"#else"
"Barney & Betty\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X"); // User undefs should override internal defines
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
TODO_ASSERT_EQUALS("\n\n\nBarney & Betty\n\n","\n\n\n\n\n", actual[""]);
}
void undef7() {
Settings settings;
const char filedata[] = "#define X XDefined\n"
"X;\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
settings.userUndefs.insert("X"); // User undefs should override internal defines
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
ASSERT_EQUALS(1, (int)actual.size());
TODO_ASSERT_EQUALS("\n;\n","\nXDefined;\n", actual[""]);
}
};
REGISTER_TEST(TestPreprocessor)