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;
|
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 only errors are printed, print filename after the check
|
||||||
if (_settings._errorsOnly == false && it != configurations.begin()) {
|
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("..."));
|
_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();
|
const std::string &appendCode = _settings.append();
|
||||||
|
|
||||||
if (_settings.debugFalsePositive) {
|
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)
|
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);
|
_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
|
// For the error report
|
||||||
unsigned int lineno = 0;
|
unsigned int lineno = 0;
|
||||||
|
@ -1705,6 +1705,10 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
|
||||||
ret << line << "\n";
|
ret << line << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validate && !validateCfg(ret.str(), cfg)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
return expandMacros(ret.str(), filename, cfg, _errorLogger);
|
return expandMacros(ret.str(), filename, cfg, _errorLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2552,6 +2556,53 @@ static bool getlines(std::istream &istr, std::string &line)
|
||||||
return true;
|
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)
|
std::string Preprocessor::expandMacros(const std::string &code, std::string filename, const std::string &cfg, ErrorLogger *errorLogger)
|
||||||
{
|
{
|
||||||
// Search for macros and expand them..
|
// Search for macros and expand them..
|
||||||
|
@ -2829,5 +2880,6 @@ void Preprocessor::getErrorMessages(ErrorLogger *errorLogger, const Settings *se
|
||||||
Settings settings2(*settings);
|
Settings settings2(*settings);
|
||||||
Preprocessor preprocessor(&settings2, errorLogger);
|
Preprocessor preprocessor(&settings2, errorLogger);
|
||||||
preprocessor.missingInclude("", 1, "", true);
|
preprocessor.missingInclude("", 1, "", true);
|
||||||
|
preprocessor.validateCfgError("X");
|
||||||
preprocessor.error("", 1, "#error message"); // #error ..
|
preprocessor.error("", 1, "#error message"); // #error ..
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,12 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get preprocessed code for a given configuration
|
* 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
|
* simplify condition
|
||||||
|
@ -110,6 +114,16 @@ public:
|
||||||
* @param processedFile The data to be processed
|
* @param processedFile The data to be processed
|
||||||
*/
|
*/
|
||||||
static void preprocessWhitespaces(std::string &processedFile);
|
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:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -268,6 +268,8 @@ private:
|
||||||
TEST_CASE(undef9);
|
TEST_CASE(undef9);
|
||||||
|
|
||||||
TEST_CASE(macroChar);
|
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));
|
ASSERT_EQUALS("\n" + std::string(char(1),1U) + "1\n", OurPreprocessor::expandMacros(filedata,NULL));
|
||||||
OurPreprocessor::macroChar = '$';
|
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)
|
REGISTER_TEST(TestPreprocessor)
|
||||||
|
|
Loading…
Reference in New Issue