From fc84f55f801a9f2a75b7256c9a3ee5193ecc6341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 15 Mar 2012 20:04:34 +0100 Subject: [PATCH] Fixed #3536 (Preprocessor #if fails to correctly compare two #defined values) --- lib/preprocessor.cpp | 22 +++++++++++++++++++++- lib/preprocessor.h | 2 +- test/testpreprocessor.cpp | 19 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 0e11e48bb..3326f6df5 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -876,7 +876,25 @@ std::string Preprocessor::getdef(std::string line, bool def) return line; } +/** + * 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 &variables) +{ + for (std::map::iterator i = variables.begin(); i != variables.end(); ++i) { + std::string& varValue = i->second; + // TODO: 1. tokenize the value, replace each token like this. + // TODO: 2. handle function-macros too. + + std::map::iterator it = variables.find(varValue); + while (it != variables.end() && it != i) { + varValue = it->second; + it = variables.find(varValue); + } + } +} std::list Preprocessor::getcfgs(const std::string &filedata, const std::string &filename) { @@ -998,6 +1016,7 @@ std::list Preprocessor::getcfgs(const std::string &filedata, const varmap[varname] = value; } + simplifyVarMap(varmap); simplifyCondition(varmap, def, false); } @@ -1386,7 +1405,7 @@ void Preprocessor::simplifyCondition(const std::map &c condition = "0"; } -bool Preprocessor::match_cfg_def(const std::map &cfg, std::string def) +bool Preprocessor::match_cfg_def(std::map cfg, std::string def) { /* std::cout << "cfg: \""; @@ -1401,6 +1420,7 @@ bool Preprocessor::match_cfg_def(const std::map &cfg, std::cout << "def: \"" << def << "\"\n"; */ + simplifyVarMap(cfg); simplifyCondition(cfg, def, true); if (cfg.find(def) != cfg.end()) diff --git a/lib/preprocessor.h b/lib/preprocessor.h index b30587e28..19763995f 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -206,7 +206,7 @@ public: * @param def condition * @return result when evaluating the condition */ - bool match_cfg_def(const std::map &cfg, std::string def); + bool match_cfg_def(std::map cfg, std::string def); static void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings); diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 2e799deab..6961b7b1a 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -128,6 +128,8 @@ private: TEST_CASE(if_or_1); TEST_CASE(if_or_2); + TEST_CASE(if_macro_eq_macro); // #3536 + TEST_CASE(multiline1); TEST_CASE(multiline2); TEST_CASE(multiline3); @@ -1501,6 +1503,23 @@ private: ASSERT_EQUALS("\na1;\n\n", preprocessor.getcode(code, "Y", "test.c")); } + void if_macro_eq_macro() { + const std::string code("#define A B\n" + "#define B 1\n" + "#define C 1\n" + "#if A == C\n" + "Wilma\n" + "#else\n" + "Betty\n" + "#endif\n"); + Settings settings; + Preprocessor preprocessor(&settings, this); + std::istringstream istr(code); + std::map actual; + preprocessor.preprocess(istr, actual, "file.c"); + + ASSERT_EQUALS("\n\n\n\nWilma\n\n\n\n", actual[""]); + } void multiline1() { const char filedata[] = "#define str \"abc\" \\\n"