From ff036c8742e8f3a0a54d36dbbbb9845af7d22c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 21 Aug 2016 13:53:44 +0200 Subject: [PATCH] Fixed #7700 (Using -D to force a configuration still checks the configuration as well as configurations that are not relevant) --- lib/preprocessor.cpp | 80 +++++++++++++++++++++++++++++++-------- test/testpreprocessor.cpp | 33 +++++++++++----- 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 1db2ec32d..704c6475b 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -215,7 +215,22 @@ static std::string readcondition(const simplecpp::Token *iftok, const std::set &configs) +static bool hasDefine(const std::string &userDefines, const std::string &cfg) +{ + std::string::size_type pos = 0; + while (pos < userDefines.size()) { + pos = userDefines.find(cfg, pos); + if (pos == std::string::npos) + break; + const std::string::size_type pos2 = pos + cfg.size(); + if ((pos == 0 || userDefines[pos-1U] == ';') && (pos2 == userDefines.size() || userDefines[pos2] == '=')) + return true; + pos = pos2; + } + return false; +} + +static std::string cfg(const std::vector &configs, const std::string &userDefines) { std::set configs2(configs.begin(), configs.end()); std::string ret; @@ -224,6 +239,8 @@ static std::string cfg(const std::vector &configs) continue; if (*it == "0") return ""; + if (hasDefine(userDefines, *it)) + continue; if (!ret.empty()) ret += ';'; ret += *it; @@ -248,7 +265,33 @@ static bool isUndefined(const std::string &cfg, const std::set &und return false; } -static void getConfigs(const simplecpp::TokenList &tokens, std::set &defined, const std::set &undefined, std::set &ret) +static bool getConfigsElseIsFalse(const std::vector &configs_if, const std::string &userDefines) +{ + for (unsigned int i = 0; i < configs_if.size(); ++i) { + if (hasDefine(userDefines, configs_if[i])) + return true; + } + return false; +} + +static const simplecpp::Token *gotoEndIf(const simplecpp::Token *cmdtok) +{ + int level = 0; + while (nullptr != (cmdtok = cmdtok->next)) { + if (cmdtok->op == '#' && !sameline(cmdtok->previous,cmdtok) && sameline(cmdtok, cmdtok->next)) { + if (cmdtok->next->str.compare(0,2,"if")==0) + ++level; + else if (cmdtok->next->str == "endif") { + --level; + if (level < 0) + return cmdtok; + } + } + } + return nullptr; +} + +static void getConfigs(const simplecpp::TokenList &tokens, std::set &defined, const std::string &userDefines, const std::set &undefined, std::set &ret) { std::vector configs_if; std::vector configs_ifndef; @@ -277,21 +320,26 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set configs_if.push_back((cmdtok->str == "ifndef") ? std::string() : config); configs_ifndef.push_back((cmdtok->str == "ifndef") ? config : std::string()); - ret.insert(cfg(configs_if)); - } else if (cmdtok->str == "elif") { + ret.insert(cfg(configs_if,userDefines)); + } else if (cmdtok->str == "elif" || cmdtok->str == "else") { + if (getConfigsElseIsFalse(configs_if,userDefines)) { + tok = gotoEndIf(tok); + if (!tok) + break; + tok = tok->previous; + continue; + } if (!configs_if.empty()) configs_if.pop_back(); - std::string config = readcondition(cmdtok, defined); - if (undefined.find(config) != undefined.end()) - config.clear(); - configs_if.push_back(config); - ret.insert(cfg(configs_if)); - } else if (cmdtok->str == "else") { - if (!configs_if.empty()) - configs_if.pop_back(); - if (!configs_ifndef.empty()) { + if (cmdtok->str == "elif") { + std::string config = readcondition(cmdtok, defined); + if (isUndefined(config,undefined)) + config.clear(); + configs_if.push_back(config); + ret.insert(cfg(configs_if, userDefines)); + } else if (!configs_ifndef.empty()) { configs_if.push_back(configs_ifndef.back()); - ret.insert(cfg(configs_if)); + ret.insert(cfg(configs_if, userDefines)); } } else if (cmdtok->str == "endif" && !sameline(tok, cmdtok->next)) { if (!configs_if.empty()) @@ -315,10 +363,10 @@ std::set Preprocessor::getConfigs(const simplecpp::TokenList &token std::set defined; defined.insert("__cplusplus"); - ::getConfigs(tokens, defined, _settings.userUndefs, ret); + ::getConfigs(tokens, defined, _settings.userDefines, _settings.userUndefs, ret); for (std::map::const_iterator it = tokenlists.begin(); it != tokenlists.end(); ++it) - ::getConfigs(*(it->second), defined, _settings.userUndefs, ret); + ::getConfigs(*(it->second), defined, _settings.userDefines, _settings.userUndefs, ret); return ret; } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index ace807257..7b1ce4398 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -28,6 +28,7 @@ #include "settings.h" #include "simplecpp.h" +#include #include #include #include @@ -215,6 +216,8 @@ private: TEST_CASE(getConfigs8); // #if A==1 => cfg: A=1 TEST_CASE(getConfigs10); // #5139 + TEST_CASE(getConfigsD1); + TEST_CASE(getConfigsU1); TEST_CASE(getConfigsU2); TEST_CASE(getConfigsU3); @@ -255,10 +258,12 @@ private: } } - std::string getConfigsStr(const char filedata[], const char *u1=NULL) { + std::string getConfigsStr(const char filedata[], const char *arg=NULL) { Settings settings; - if (u1) - settings.userUndefs.insert(u1); + if (arg && std::strncmp(arg,"-D",2)==0) + settings.userDefines = arg + 2; + if (arg && std::strncmp(arg,"-U",2)==0) + settings.userUndefs.insert(arg+2); Preprocessor preprocessor(settings, this); std::vector files; std::istringstream istr(filedata); @@ -2060,17 +2065,27 @@ private: ASSERT_EQUALS("\n", getConfigsStr(filedata)); } + void getConfigsD1() { + const char filedata[] = "#ifdef X\n" + "#else\n" + "#ifdef Y\n" + "#endif\n" + "#endif\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-DX")); + ASSERT_EQUALS("\nX\nY\n", getConfigsStr(filedata)); + } + void getConfigsU1() { const char filedata[] = "#ifdef X\n" "#endif\n"; - ASSERT_EQUALS("\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\nX\n", getConfigsStr(filedata)); } void getConfigsU2() { const char filedata[] = "#ifndef X\n" "#endif\n"; - ASSERT_EQUALS("\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\n", getConfigsStr(filedata)); // no #else } @@ -2080,7 +2095,7 @@ private: "#else\n" "Barney & Betty\n" "#endif\n"; - ASSERT_EQUALS("\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\nX\n", getConfigsStr(filedata)); } @@ -2088,21 +2103,21 @@ private: const char filedata[] = "#if defined(X) || defined(Y) || defined(Z)\n" "#else\n" "#endif\n"; - ASSERT_EQUALS("\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\nX;Y;Z\n", getConfigsStr(filedata)); } void getConfigsU5() { const char filedata[] = "#if X==1\n" "#endif\n"; - ASSERT_EQUALS("\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\nX=1\n", getConfigsStr(filedata)); } void getConfigsU6() { const char filedata[] = "#if X==0\n" "#endif\n"; - ASSERT_EQUALS("\nX=0\n", getConfigsStr(filedata, "X")); + ASSERT_EQUALS("\nX=0\n", getConfigsStr(filedata, "-UX")); ASSERT_EQUALS("\nX=0\n", getConfigsStr(filedata)); }