Fixed #6617 (preprocessor performance improvement)

This commit is contained in:
Simon Shanks 2015-07-24 13:30:41 +02:00 committed by Daniel Marjamäki
parent 8ffa917fa2
commit 9910c1fa0c
8 changed files with 321 additions and 306 deletions

View File

@ -154,7 +154,7 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
bool internalErrorFound(false);
try {
Preprocessor preprocessor(&_settings, this);
Preprocessor preprocessor(_settings, this);
std::list<std::string> configurations;
std::string filedata;
@ -289,7 +289,7 @@ void CppCheck::internalError(const std::string &filename, const std::string &msg
void CppCheck::analyseFile(std::istream &fin, const std::string &filename)
{
// Preprocess file..
Preprocessor preprocessor(&_settings, this);
Preprocessor preprocessor(_settings, this);
std::list<std::string> configurations;
std::string filedata;
preprocessor.preprocess(fin, filedata, configurations, filename, _settings._includePaths);

View File

@ -38,7 +38,7 @@ bool Preprocessor::missingSystemIncludeFlag;
char Preprocessor::macroChar = char(1);
Preprocessor::Preprocessor(Settings *settings, ErrorLogger *errorLogger) : _settings(settings), _errorLogger(errorLogger)
Preprocessor::Preprocessor(Settings& settings, ErrorLogger *errorLogger) : _settings(settings), _errorLogger(errorLogger)
{
}
@ -183,10 +183,10 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
bom = 0; // allowed boms are 0/0xfffe/0xfeff
}
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
if (_settings && _settings->checkConfiguration)
if (_settings.checkConfiguration)
return readpreprocessor(istr,bom);
// ------------------------------------------------------------------------------------------
@ -251,27 +251,27 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
//
// Remove all comments..
result = removeComments(result, filename);
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
// ------------------------------------------------------------------------------------------
//
// Clean up all preprocessor statements
result = preprocessCleanupDirectives(result);
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
// ------------------------------------------------------------------------------------------
//
// Clean up preprocessor #if statements with Parentheses
result = removeParentheses(result);
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
// Remove '#if 0' blocks
if (result.find("#if 0\n") != std::string::npos)
result = removeIf0(result);
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
return result;
@ -476,7 +476,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
unsigned char previous = 0;
bool inPreprocessorLine = false;
std::vector<std::string> suppressionIDs;
const bool detectFallThroughComments = _settings && _settings->experimental && _settings->isEnabled("style");
const bool detectFallThroughComments = _settings.experimental && _settings.isEnabled("style");
bool fallThroughComment = false;
for (std::string::size_type i = hasbom(str) ? 3U : 0U; i < str.length(); ++i) {
@ -491,21 +491,9 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
writeError(filename, lineno, _errorLogger, "unhandledCharacters", errmsg.str());
}
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
if (str.compare(i, 7, "#error ") == 0 || str.compare(i, 9, "#warning ") == 0) {
if (str.compare(i, 6, "#error") == 0)
code << "#error";
i = str.find("\n", i);
if (i == std::string::npos)
break;
--i;
continue;
}
// First skip over any whitespace that may be present
if (std::isspace(ch)) {
if (ch == ' ' && previous == ' ') {
@ -530,6 +518,18 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
continue;
}
if ((ch == '#') && (str.compare(i, 7, "#error ") == 0 || str.compare(i, 9, "#warning ") == 0)) {
if (str.compare(i, 6, "#error") == 0)
code << "#error";
i = str.find("\n", i);
if (i == std::string::npos)
break;
--i;
continue;
}
// Remove comments..
if (str.compare(i, 2, "//") == 0) {
const std::size_t commentStart = i + 2;
@ -538,7 +538,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
break;
std::string comment(str, commentStart, i - commentStart);
if (_settings && _settings->_inlineSuppressions) {
if (_settings._inlineSuppressions) {
std::istringstream iss(comment);
std::string word;
iss >> word;
@ -575,7 +575,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
fallThroughComment = true;
}
if (_settings && _settings->_inlineSuppressions) {
if (_settings._inlineSuppressions) {
std::istringstream iss(comment);
std::string word;
iss >> word;
@ -617,13 +617,11 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
// Add any pending inline suppressions that have accumulated.
if (!suppressionIDs.empty()) {
if (_settings != nullptr) {
// Add the suppressions.
for (std::size_t j = 0; j < suppressionIDs.size(); ++j) {
const std::string errmsg(_settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno));
if (!errmsg.empty()) {
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
}
// Add the suppressions.
for (std::size_t j = 0; j < suppressionIDs.size(); ++j) {
const std::string errmsg(_settings.nomsg.addSuppression(suppressionIDs[j], filename, lineno));
if (!errmsg.empty()) {
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
}
}
suppressionIDs.clear();
@ -645,24 +643,22 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
// Add any pending inline suppressions that have accumulated.
if (!suppressionIDs.empty()) {
if (_settings != nullptr) {
// Relative filename
std::string relativeFilename(filename);
if (_settings->_relativePaths) {
for (std::size_t j = 0U; j < _settings->_basePaths.size(); ++j) {
const std::string bp = _settings->_basePaths[j] + "/";
if (relativeFilename.compare(0,bp.size(),bp)==0) {
relativeFilename = relativeFilename.substr(bp.size());
}
// Relative filename
std::string relativeFilename(filename);
if (_settings._relativePaths) {
for (std::size_t j = 0U; j < _settings._basePaths.size(); ++j) {
const std::string bp = _settings._basePaths[j] + "/";
if (relativeFilename.compare(0,bp.size(),bp)==0) {
relativeFilename = relativeFilename.substr(bp.size());
}
}
}
// Add the suppressions.
for (std::size_t j = 0; j < suppressionIDs.size(); ++j) {
const std::string errmsg(_settings->nomsg.addSuppression(suppressionIDs[j], relativeFilename, lineno));
if (!errmsg.empty()) {
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
}
// Add the suppressions.
for (std::size_t j = 0; j < suppressionIDs.size(); ++j) {
const std::string errmsg(_settings.nomsg.addSuppression(suppressionIDs[j], relativeFilename, lineno));
if (!errmsg.empty()) {
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
}
}
suppressionIDs.clear();
@ -789,7 +785,7 @@ std::string Preprocessor::removeParentheses(const std::string &str)
std::ostringstream ret;
std::string line;
while (std::getline(istr, line)) {
if (line.compare(0, 3, "#if") == 0 || line.compare(0, 5, "#elif") == 0) {
if ((line[0] == '#') && (line.compare(0, 3, "#if") == 0 || line.compare(0, 5, "#elif") == 0)) {
std::string::size_type pos;
pos = 0;
while ((pos = line.find(" (", pos)) != std::string::npos)
@ -868,7 +864,7 @@ void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::str
std::string data;
preprocess(istr, data, configs, filename, includePaths);
for (std::list<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it) {
if (_settings && (_settings->userUndefs.find(*it) == _settings->userUndefs.end())) {
if (_settings.userUndefs.find(*it) == _settings.userUndefs.end()) {
result[ *it ] = getcode(data, *it, filename);
}
}
@ -909,7 +905,7 @@ void Preprocessor::replaceIfDefined(std::string &str) const
}
++pos;
if (_settings && _settings->terminated())
if (_settings.terminated())
return;
}
@ -925,7 +921,7 @@ void Preprocessor::replaceIfDefined(std::string &str) const
}
++pos;
if (_settings && _settings->terminated())
if (_settings.terminated())
return;
}
@ -940,7 +936,7 @@ void Preprocessor::replaceIfDefined(std::string &str) const
}
++pos;
if (_settings && _settings->terminated())
if (_settings.terminated())
return;
}
}
@ -963,42 +959,40 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
processedFile = read(srcCodeStream, filename);
if (_settings) {
for (std::list<std::string>::const_iterator it = _settings->userIncludes.begin();
it != _settings->userIncludes.end();
++it) {
std::string cur = *it;
for (std::list<std::string>::iterator it = _settings.userIncludes.begin();
it != _settings.userIncludes.end();
++it) {
std::string cur = *it;
// try to open file
std::ifstream fin;
// try to open file
std::ifstream fin;
fin.open(cur.c_str());
if (!fin.is_open()) {
missingInclude(cur,
1,
cur,
UserHeader
);
continue;
}
const std::string fileData = read(fin, filename);
fin.close();
forcedIncludes =
forcedIncludes +
"#file \"" + cur + "\"\n" +
"#line 1\n" +
fileData + "\n" +
"#endfile\n"
;
fin.open(cur.c_str());
if (!fin.is_open()) {
missingInclude(cur,
1,
cur,
UserHeader
);
continue;
}
const std::string fileData = read(fin, filename);
for (std::vector<std::string>::const_iterator it = _settings->library.defines.begin();
it != _settings->library.defines.end();
++it) {
forcedIncludes += *it;
}
fin.close();
forcedIncludes =
forcedIncludes +
"#file \"" + cur + "\"\n" +
"#line 1\n" +
fileData + "\n" +
"#endfile\n"
;
}
for (std::vector<std::string>::iterator it = _settings.library.defines.begin();
it != _settings.library.defines.end();
++it) {
forcedIncludes += *it;
}
if (!forcedIncludes.empty()) {
@ -1030,7 +1024,7 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
else
line.insert(pos, ")");
if (_settings && _settings->terminated())
if (_settings.terminated())
return;
}
}
@ -1039,9 +1033,9 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
processedFile = ostr.str();
}
std::map<std::string, std::string> defs(getcfgmap(_settings ? _settings->userDefines : emptyString, _settings, filename));
std::map<std::string, std::string> defs(getcfgmap(_settings.userDefines, &_settings, filename));
if (_settings && _settings->_maxConfigs == 1U) {
if (_settings._maxConfigs == 1U) {
std::set<std::string> pragmaOnce;
std::list<std::string> includes;
processedFile = handleIncludes(processedFile, filename, includePaths, defs, pragmaOnce, includes);
@ -1061,10 +1055,10 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
void Preprocessor::handleUndef(std::list<std::string> &configurations) const
{
if (_settings && !_settings->userUndefs.empty()) {
if (!_settings.userUndefs.empty()) {
for (std::list<std::string>::iterator cfg = configurations.begin(); cfg != configurations.end();) {
bool undef = false;
for (std::set<std::string>::const_iterator it = _settings->userUndefs.begin(); it != _settings->userUndefs.end(); ++it) {
for (std::set<std::string>::const_iterator it = _settings.userUndefs.begin(); it != _settings.userUndefs.end(); ++it) {
if (*it == *cfg)
undef = true;
else if (cfg->compare(0,it->length(),*it)==0 && cfg->find_first_of(";=") == it->length())
@ -1133,7 +1127,7 @@ std::string Preprocessor::getdef(std::string line, bool def)
}
/** Simplify variable in variable map. */
static Token *simplifyVarMapExpandValue(Token *tok, const std::map<std::string, std::string> &variables, std::set<std::string> seenVariables, const Settings* settings)
static Token *simplifyVarMapExpandValue(Token *tok, const std::map<std::string, std::string> &variables, std::set<std::string> seenVariables, const Settings& settings)
{
// TODO: handle function-macros too.
@ -1144,7 +1138,7 @@ static Token *simplifyVarMapExpandValue(Token *tok, const std::map<std::string,
const std::map<std::string, std::string>::const_iterator it = variables.find(tok->str());
if (it != variables.end()) {
TokenList tokenList(settings);
TokenList tokenList(&settings);
std::istringstream istr(it->second);
if (tokenList.createTokens(istr)) {
// expand token list
@ -1172,10 +1166,10 @@ static Token *simplifyVarMapExpandValue(Token *tok, const std::map<std::string,
* Simplifies the variable map. For example if the map contains A=>B, B=>1, then A=>B is simplified to A=>1.
* @param [in,out] variables - a map of variable name to variable value. This map will be modified.
*/
static void simplifyVarMap(std::map<std::string, std::string> &variables, const Settings* settings)
static void simplifyVarMap(std::map<std::string, std::string> &variables, const Settings& settings)
{
for (std::map<std::string, std::string>::iterator i = variables.begin(); i != variables.end(); ++i) {
TokenList tokenList(settings);
TokenList tokenList(&settings);
std::istringstream istr(i->second);
if (tokenList.createTokens(istr)) {
for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
@ -1214,11 +1208,11 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
unsigned int linenr = 0;
std::istringstream istr(filedata);
std::string line;
const bool printDebug = (_settings && _settings->debugwarnings);
const bool printDebug = _settings.debugwarnings;
while (std::getline(istr, line)) {
++linenr;
if (_settings && _settings->terminated())
if (_settings.terminated())
return ret;
if (_errorLogger)
@ -1232,13 +1226,8 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
const std::string::size_type start=line.find("\"");
const std::string::size_type end=line.find("\"",start+1);
const std::string includeFile=line.substr(start+1,end-start-1);
bool fileExcluded = false;
++filelevel;
if (! _settings) {
fileExcluded = false;
} else {
fileExcluded = _settings->configurationExcluded(includeFile);
}
bool fileExcluded = _settings.configurationExcluded(includeFile);
includeStack.push(std::pair<std::string,bool>(includeFile,fileExcluded));
continue;
}
@ -1487,7 +1476,7 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
std::string s(*it);
if (s.find("&&") != std::string::npos) {
Tokenizer tokenizer(_settings, _errorLogger);
Tokenizer tokenizer(&_settings, _errorLogger);
if (!tokenizer.tokenizeCondition(s)) {
std::ostringstream lineStream;
lineStream << __LINE__;
@ -1766,7 +1755,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
std::list<bool> matched_ifdef;
// Create a map for the cfg for faster access to defines
std::map<std::string, std::string> cfgmap(getcfgmap(cfg, _settings, filename));
std::map<std::string, std::string> cfgmap(getcfgmap(cfg, &_settings, filename));
std::stack<std::string> filenames;
filenames.push(filename);
@ -1776,7 +1765,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
while (std::getline(istr, line)) {
++lineno;
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
if (line.compare(0, 11, "#pragma asm") == 0) {
@ -1794,7 +1783,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
break;
if (line.find("=") != std::string::npos) {
Tokenizer tokenizer(_settings, _errorLogger);
Tokenizer tokenizer(&_settings, _errorLogger);
line.erase(0, sizeof("#pragma endasm"));
std::istringstream tempIstr(line);
tokenizer.tokenize(tempIstr, "", "", true);
@ -1816,19 +1805,18 @@ 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>::const_iterator It;
for (It it = _settings->userUndefs.begin(); it != _settings->userUndefs.end(); ++it) {
const 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;
}
typedef std::set<std::string>::const_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;
}
}
}
@ -1922,7 +1910,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string
// #error => return ""
if (match && line.compare(0, 6, "#error") == 0) {
if (_settings && !_settings->userDefines.empty() && !_settings->_force) {
if (!_settings.userDefines.empty() && !_settings._force) {
error(filenames.top(), lineno, line);
}
return "";
@ -2067,7 +2055,7 @@ std::string Preprocessor::handleIncludes(const std::string &code, const std::str
unsigned int linenr = 0;
const std::set<std::string>& undefs = _settings ? _settings->userUndefs : std::set<std::string>();
const std::set<std::string> &undefs = _settings.userUndefs;
if (_errorLogger)
_errorLogger->reportProgress(filePath, "Preprocessor (handleIncludes)", 0);
@ -2079,7 +2067,7 @@ std::string Preprocessor::handleIncludes(const std::string &code, const std::str
while (std::getline(istr,line)) {
++linenr;
if (_settings && _settings->terminated())
if (_settings.terminated())
return "";
// has there been a true #if condition at the current indentmatch level?
@ -2279,7 +2267,7 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filePath
}
std::set<std::string> handledFiles;
while ((pos = code.find("#include", pos)) != std::string::npos) {
if (_settings && _settings->terminated())
if (_settings.terminated())
return;
// Accept only includes that are at the start of a line
@ -2338,7 +2326,7 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filePath
path = filename;
path.erase(1 + path.find_last_of("\\/"));
paths.push_back(path);
} else if (!fileOpened && _settings) {
} else if (!fileOpened) {
std::string f = filePath;
// Determine line number of include
@ -2373,16 +2361,16 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filePath
void Preprocessor::missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, HeaderTypes headerType)
{
const std::string fname = Path::fromNativeSeparators(filename);
if (_settings->nomsg.isSuppressed("missingInclude", fname, linenr))
if (_settings.nomsg.isSuppressed("missingInclude", fname, linenr))
return;
if (headerType == SystemHeader && _settings->nomsg.isSuppressed("missingIncludeSystem", fname, linenr))
if (headerType == SystemHeader && _settings.nomsg.isSuppressed("missingIncludeSystem", fname, linenr))
return;
if (headerType == SystemHeader)
missingSystemIncludeFlag = true;
else
missingIncludeFlag = true;
if (_errorLogger && _settings->checkConfiguration) {
if (_errorLogger && _settings.checkConfiguration) {
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
if (!filename.empty()) {
@ -2868,7 +2856,7 @@ static bool getlines(std::istream &istr, std::string &line)
bool Preprocessor::validateCfg(const std::string &code, const std::string &cfg)
{
const bool printInformation = (_settings && _settings->isEnabled("information"));
const bool printInformation = _settings.isEnabled("information");
// fill up "macros" with empty configuration macros
std::set<std::string> macros;
@ -3273,7 +3261,7 @@ std::string Preprocessor::expandMacros(const std::string &code, std::string file
void Preprocessor::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
{
Settings settings2(*settings);
Preprocessor preprocessor(&settings2, errorLogger);
Preprocessor preprocessor(settings2, errorLogger);
settings2.checkConfiguration=true;
preprocessor.missingInclude("", 1, "", UserHeader);
preprocessor.missingInclude("", 1, "", SystemHeader);

View File

@ -54,7 +54,7 @@ public:
/** character that is inserted in expanded macros */
static char macroChar;
Preprocessor(Settings *settings = nullptr, ErrorLogger *errorLogger = nullptr);
Preprocessor(Settings& settings, ErrorLogger *errorLogger = nullptr);
static bool missingIncludeFlag;
static bool missingSystemIncludeFlag;
@ -268,7 +268,7 @@ private:
*/
void handleIncludes(std::string &code, const std::string &filePath, const std::list<std::string> &includePaths);
Settings *_settings;
Settings& _settings;
ErrorLogger *_errorLogger;
/** filename for cpp/c file - useful when reporting errors */

View File

@ -6453,7 +6453,7 @@ private:
errout.str("");
// Preprocess...
Preprocessor preprocessor(&settings, this);
Preprocessor preprocessor(settings, this);
std::istringstream istrpreproc(code);
std::map<std::string, std::string> actual;
preprocessor.preprocess(istrpreproc, actual, "test.c");
@ -6507,7 +6507,7 @@ private:
errout.str("");
// Preprocess...
Preprocessor preprocessor(&settings, this);
Preprocessor preprocessor(settings, this);
std::istringstream istrpreproc(code);
std::map<std::string, std::string> actual;
preprocessor.preprocess(istrpreproc, actual, "test.c");

View File

@ -183,7 +183,7 @@ private:
settings->experimental = experimental;
// Preprocess file..
Preprocessor preprocessor(settings);
Preprocessor preprocessor(*settings);
std::list<std::string> configurations;
std::string filedata = "";
std::istringstream fin(raw_code);
@ -237,7 +237,7 @@ private:
// Preprocess file..
SimpleSuppressor logger(settings, this);
Preprocessor preprocessor(&settings, &logger);
Preprocessor preprocessor(settings, &logger);
std::list<std::string> configurations;
std::string filedata = "";
std::istringstream fin(precode);

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@ private:
settings.addEnabled("warning");
// Preprocess file..
Preprocessor preprocessor(&settings, this);
Preprocessor preprocessor(settings, this);
std::list<std::string> configurations;
std::string filedata;
std::istringstream fin(precode);

View File

@ -8653,7 +8653,7 @@ private:
// Preprocess file..
Settings settings;
Preprocessor preprocessor(&settings);
Preprocessor preprocessor(settings);
std::list<std::string> configurations;
std::string filedata = "";
std::istringstream fin(raw_code);