Fixed #3643 (Preprocessor: Invalid configuration (macro is used in code))
This commit is contained in:
parent
68e19b33ff
commit
17cf24ed34
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¯o = *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 ..
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue