From 272f0d3be5950fb83a669a7375ae04eca5b27ae8 Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Tue, 6 Oct 2009 11:47:36 +0300 Subject: [PATCH] Fix #795 (Preprocessor: Incorrect handling of #if (A) || (B)) http://sourceforge.net/apps/trac/cppcheck/ticket/795 --- src/preprocessor.cpp | 32 +++++++++++++-- test/testpreprocessor.cpp | 85 +++++++++++++++++++++++++++++++++------ 2 files changed, 100 insertions(+), 17 deletions(-) diff --git a/src/preprocessor.cpp b/src/preprocessor.cpp index 559e62b1b..2bbe19d0e 100644 --- a/src/preprocessor.cpp +++ b/src/preprocessor.cpp @@ -444,7 +444,7 @@ std::string Preprocessor::removeComments(const std::string &str) std::string Preprocessor::removeParantheses(const std::string &str) { - if (str.find("\n#if") == std::string::npos) + if (str.find("\n#if") == std::string::npos && str.compare(0, 3, "#if") != 0) return str; std::istringstream istr(str.c_str()); @@ -481,14 +481,38 @@ std::string Preprocessor::removeParantheses(const std::string &str) } } - if (line.compare(0, 4, "#if(") == 0 && line.find(")") == line.length() - 1) + // "#if(A) => #if A", but avoid "#if (defined A) || defined (B)" + if (line.compare(0, 4, "#if(") == 0 && line[line.length() - 1] == ')') { - line[3] = ' '; - line.erase(line.length() - 1); + int ind = 0; + for (std::string::size_type i = 0; i < line.length(); ++i) + { + if (line[i] == '(') + ++ind; + else if (line[i] == ')') + { + --ind; + if (ind == 0) + { + if (i == line.length() - 1) + { + line[3] = ' '; + line.erase(line.length() - 1); + } + break; + } + } + } } + + if (line.compare(0, 4, "#if(") == 0) + line.insert(3, " "); + else if (line.compare(0, 4, "#elif(") == 0) + line.insert(5, " "); } ret << line << "\n"; } + return ret.str(); } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index b935e89eb..59cc31e8e 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -651,21 +651,80 @@ private: void if_cond4() { - const char filedata[] = "#define A\n" - "#define B\n" - "#if defined A || defined B\n" - "ab\n" - "#endif\n"; + { + const char filedata[] = "#define A\n" + "#define B\n" + "#if defined A || defined B\n" + "ab\n" + "#endif\n"; - // Preprocess => actual result.. - std::istringstream istr(filedata); - std::map actual; - Preprocessor preprocessor; - preprocessor.preprocess(istr, actual, "file.c"); + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); - // Compare results.. - ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nab\n\n", actual[""]); + // Compare results.. + ASSERT_EQUALS(1, static_cast(actual.size())); + ASSERT_EQUALS("\n\n\nab\n\n", actual[""]); + } + + { + const char filedata[] = "#if A\n" + "{\n" + "#if (defined(B))\n" + "foo();\n" + "#endif\n" + "}\n" + "#endif\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS(3, static_cast(actual.size())); + ASSERT_EQUALS("\n\n\n\n\n\n\n", actual[""]); + ASSERT_EQUALS("\n{\n\n\n\n}\n\n", actual["A"]); + ASSERT_EQUALS("\n{\n\nfoo();\n\n}\n\n", actual["A;B"]); + } + + { + const char filedata[] = "#define A\n" + "#define B\n" + "#if (defined A) || defined (B)\n" + "ab\n" + "#endif\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS(1, static_cast(actual.size())); + ASSERT_EQUALS("\n\n\nab\n\n", actual[""]); + } + + { + const char filedata[] = "#if (A)\n" + "foo();\n" + "#endif\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS(2, static_cast(actual.size())); + ASSERT_EQUALS("\n\n\n", actual[""]); + ASSERT_EQUALS("\nfoo();\n\n", actual["A"]); + } } void if_cond5()