Fixed #3643 (Preprocessor: Invalid configuration (macro is used in code))

This commit is contained in:
Daniel Marjamäki 2012-07-10 20:29:04 +02:00
parent 68e19b33ff
commit 17cf24ed34
4 changed files with 99 additions and 5 deletions

View File

@ -214,9 +214,6 @@ unsigned int CppCheck::processFile(const std::string& filename)
}
cfg = *it;
Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults);
const std::string codeWithoutCfg = preprocessor.getcode(filedata, *it, filename);
t.Stop();
// If only errors are printed, print filename after the check
if (_settings._errorsOnly == false && it != configurations.begin()) {
@ -225,6 +222,10 @@ unsigned int CppCheck::processFile(const std::string& filename)
_errorLogger.reportOut(std::string("Checking ") + fixedpath + ": " + cfg + std::string("..."));
}
Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults);
const std::string codeWithoutCfg = preprocessor.getcode(filedata, *it, filename, _settings.userDefines.empty());
t.Stop();
const std::string &appendCode = _settings.append();
if (_settings.debugFalsePositive) {
@ -513,6 +514,21 @@ void CppCheck::reportProgress(const std::string &filename, const char stage[], c
void CppCheck::reportInfo(const ErrorLogger::ErrorMessage &msg)
{
// Suppressing info message?
std::string file;
unsigned int line(0);
if (!msg._callStack.empty()) {
file = msg._callStack.back().getfile(false);
line = msg._callStack.back().line;
}
if (_useGlobalSuppressions) {
if (_settings.nomsg.isSuppressed(msg._id, file, line))
return;
} else {
if (_settings.nomsg.isSuppressedLocal(msg._id, file, line))
return;
}
_errorLogger.reportInfo(msg);
}

View File

@ -1510,7 +1510,7 @@ static std::map<std::string,std::string> getcfgmap(const std::string &cfg)
}
std::string Preprocessor::getcode(const std::string &filedata, const std::string &cfg, const std::string &filename)
std::string Preprocessor::getcode(const std::string &filedata, const std::string &cfg, const std::string &filename, const bool validate)
{
// For the error report
unsigned int lineno = 0;
@ -1705,6 +1705,10 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
ret << line << "\n";
}
if (validate && !validateCfg(ret.str(), cfg)) {
return "";
}
return expandMacros(ret.str(), filename, cfg, _errorLogger);
}
@ -2552,6 +2556,53 @@ static bool getlines(std::istream &istr, std::string &line)
return true;
}
bool Preprocessor::validateCfg(const std::string &code, const std::string &cfg)
{
// fill up "macros" with empty configuration macros
std::set<std::string> macros;
for (std::string::size_type pos = 0; pos < cfg.size(); ++pos) {
const std::string::size_type pos2 = cfg.find_first_of(";=", pos);
if (pos2 == std::string::npos) {
macros.insert(cfg.substr(pos));
break;
}
if (cfg[pos2] == ';')
macros.insert(cfg.substr(pos, pos2-pos));
pos = cfg.find(";", pos2);
if (pos != std::string::npos)
++pos;
}
// check if any empty macros are used in code
for (std::set<std::string>::const_iterator it = macros.begin(); it != macros.end(); ++it) {
const std::string &macro = *it;
std::string::size_type pos;
for (pos = code.find(macro); pos != std::string::npos; pos = code.find(macro,pos)) {
if (pos > 0 && (std::isalnum(code[pos-1U]) || code[pos-1U] == '_'))
continue;
pos += macro.size();
if (pos < code.size() && (std::isalnum(code[pos]) || code[pos] == '_'))
continue;
// macro is used in code, return false
if (_settings->isEnabled("information"))
validateCfgError(cfg);
return false;
}
}
return true;
}
void Preprocessor::validateCfgError(const std::string &cfg)
{
const std::string id = "ConfigurationNotChecked";
const std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
const Severity::SeverityType severity = Severity::information;
ErrorLogger::ErrorMessage errmsg(locationList, severity, "Skipping configuration '" + cfg + "' because it seems to be invalid. Use -D if you want to check it.", id, false);
errmsg.file0 = file0;
_errorLogger->reportInfo(errmsg);
}
std::string Preprocessor::expandMacros(const std::string &code, std::string filename, const std::string &cfg, ErrorLogger *errorLogger)
{
// Search for macros and expand them..
@ -2829,5 +2880,6 @@ void Preprocessor::getErrorMessages(ErrorLogger *errorLogger, const Settings *se
Settings settings2(*settings);
Preprocessor preprocessor(&settings2, errorLogger);
preprocessor.missingInclude("", 1, "", true);
preprocessor.validateCfgError("X");
preprocessor.error("", 1, "#error message"); // #error ..
}

View File

@ -94,8 +94,12 @@ public:
/**
* Get preprocessed code for a given configuration
* @param filedata file data including #if, #define, etc
* @param cfg configuration to read out
* @param filename name of source file
* @param validate true => perform validation that empty configuration macros are not used in the code
*/
std::string getcode(const std::string &filedata, const std::string &cfg, const std::string &filename);
std::string getcode(const std::string &filedata, const std::string &cfg, const std::string &filename, const bool validate = false);
/**
* simplify condition
@ -110,6 +114,16 @@ public:
* @param processedFile The data to be processed
*/
static void preprocessWhitespaces(std::string &processedFile);
/**
* make sure empty configuration macros are not used in code. the given code must be a single configuration
* @param code The input code
* @param cfg configuration
* @return true => configuration is valid
*/
bool validateCfg(const std::string &code, const std::string &cfg);
void validateCfgError(const std::string &cfg);
protected:
/**

View File

@ -268,6 +268,8 @@ private:
TEST_CASE(undef9);
TEST_CASE(macroChar);
TEST_CASE(validateCfg);
}
@ -3532,6 +3534,16 @@ private:
ASSERT_EQUALS("\n" + std::string(char(1),1U) + "1\n", OurPreprocessor::expandMacros(filedata,NULL));
OurPreprocessor::macroChar = '$';
}
void validateCfg() {
Settings settings;
Preprocessor preprocessor(&settings, this);
ASSERT_EQUALS(false, preprocessor.validateCfg("int x=X;", "X"));
ASSERT_EQUALS(false, preprocessor.validateCfg("X=1;", "X"));
ASSERT_EQUALS(true, preprocessor.validateCfg("int x=X;", "Y"));
}
};
REGISTER_TEST(TestPreprocessor)