From e5e82274dc00ff4dd7b8847c3b805521fd6c10e4 Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Wed, 13 May 2009 22:18:02 +0300 Subject: [PATCH] Fix ticket #306 (Invalid multi-line comment produces cryptic internal error) http://apps.sourceforge.net/trac/cppcheck/ticket/306 --- src/preprocessor.cpp | 172 ++++++++++++++++++++++++-------------- src/preprocessor.h | 7 ++ test/testpreprocessor.cpp | 47 +++++++---- 3 files changed, 147 insertions(+), 79 deletions(-) diff --git a/src/preprocessor.cpp b/src/preprocessor.cpp index 262355ab9..f283739ac 100644 --- a/src/preprocessor.cpp +++ b/src/preprocessor.cpp @@ -71,9 +71,6 @@ std::string Preprocessor::read(std::istream &istr) std::ostringstream code; for (char ch = readChar(istr); istr.good(); ch = readChar(istr)) { - if (ch < 0) - throw std::runtime_error("The code contains characters that are unhandled"); - if (ch == '\n') ++lineno; @@ -84,7 +81,7 @@ std::string Preprocessor::read(std::istream &istr) // Skip spaces after ' ' and after '#' if (ch == ' ' && ignoreSpace) continue; - ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/'); + ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/' || ch == '\n'); if (needSpace) { @@ -96,68 +93,8 @@ std::string Preprocessor::read(std::istream &istr) if (ch == '#') needSpace = true; - // Remove comments.. - if (ch == '/') - { - char chNext = readChar(istr); - - if (chNext == '/') - { - while (istr.good() && ch != '\n') - ch = readChar(istr); - code << "\n"; - ++lineno; - } - - else if (chNext == '*') - { - char chPrev = 0; - while (istr.good() && (chPrev != '*' || ch != '/')) - { - chPrev = ch; - ch = readChar(istr); - if (ch == '\n') - { - code << "\n"; - ++lineno; - } - } - } - - else - { - if (chNext == '\n') - ++lineno; - code << std::string(1, ch) << std::string(1, chNext); - } - } - - // String or char constants.. - else if (ch == '\"' || ch == '\'') - { - code << std::string(1, ch); - char chNext; - do - { - chNext = (char)istr.get(); - if (chNext == '\\') - { - char chSeq = readChar(istr); - if (chSeq == '\n') - ++newlines; - else - { - code << std::string(1, chNext); - code << std::string(1, chSeq); - } - } - else - code << std::string(1, chNext); - } - while (istr.good() && chNext != ch); - } // .. - else if (ch == '\\') + if (ch == '\\') { char chNext = 0; while (true) @@ -197,6 +134,111 @@ std::string Preprocessor::read(std::istream &istr) } } + return removeComments(code.str()); +} + + + +std::string Preprocessor::removeComments(const std::string &str) +{ + // For the error report + int lineno = 1; + + // handling + // when this is encountered the will be "skipped". + // on the next , extra newlines will be added + unsigned int newlines = 0; + + std::ostringstream code; + for (std::string::size_type i = 0; i < str.length(); ++i) + { + char ch = str[i]; + if (ch < 0) + throw std::runtime_error("The code contains characters that are unhandled"); + + // Remove comments.. + if (ch == '/') + { + ++i; + char chNext = str[i]; + + if (chNext == '/') + { + while (i < str.length() && ch != '\n') + { + ++i; + ch = str[i]; + } + code << "\n"; + ++lineno; + } + + else if (chNext == '*') + { + char chPrev = 0; + while (i < str.length() && (chPrev != '*' || ch != '/')) + { + chPrev = ch; + ++i; + ch = str[i]; + if (ch == '\n') + { + code << "\n"; + ++lineno; + } + } + } + + else + { + if (chNext == '\n') + ++lineno; + code << std::string(1, ch) << std::string(1, chNext); + } + } + + // String or char constants.. + else if (ch == '\"' || ch == '\'') + { + code << std::string(1, ch); + char chNext; + do + { + ++i; + chNext = str[i]; + if (chNext == '\\') + { + ++i; + char chSeq = str[i]; + if (chSeq == '\n') + ++newlines; + else + { + code << std::string(1, chNext); + code << std::string(1, chSeq); + } + } + else + code << std::string(1, chNext); + } + while (i < str.length() && chNext != ch); + } + + + // Just some code.. + else + { + code << std::string(1, ch); + + // if there has been sequences, add extra newlines.. + if (ch == '\n' && newlines > 0) + { + code << std::string(newlines, '\n'); + newlines = 0; + } + } + } + return code.str(); } diff --git a/src/preprocessor.h b/src/preprocessor.h index b684041c5..ecfcb0f7e 100644 --- a/src/preprocessor.h +++ b/src/preprocessor.h @@ -86,6 +86,13 @@ protected: static std::string expandMacros(std::string code, const std::string &filename, ErrorLogger *errorLogger); + /** + * Remove comments from code. This should only be called from read(). + * @param str Code processed by read(). + * @return code without comments + */ + static std::string removeComments(const std::string &str); + private: /** diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index cfa7755b8..dc9c34d68 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -234,7 +234,7 @@ private: preprocessor.preprocess(istr, actual, "file.c"); // Compare results.. - ASSERT_EQUALS("\n\" # ifdef WIN32\"\n\n\n\n", actual[""]); + ASSERT_EQUALS("\n\" #ifdef WIN32\"\n\n\n\n", actual[""]); ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]); ASSERT_EQUALS(2, static_cast(actual.size())); } @@ -383,20 +383,39 @@ private: void comments1() { - const char filedata[] = "/*\n" - "#ifdef WIN32\n" - "#endif\n" - "*/\n"; + { + const char filedata[] = "/*\n" + "#ifdef WIN32\n" + "#endif\n" + "*/\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("\n\n\n\n", actual[""]); - ASSERT_EQUALS(1, static_cast(actual.size())); + // Compare results.. + ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS(1, static_cast(actual.size())); + } + + { + const char filedata[] = "/*\n" + "\x080 #ifdef WIN32\n" + "#endif\n" + "*/\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS(1, static_cast(actual.size())); + } } @@ -944,7 +963,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - TODO_ASSERT_EQUALS("\n\nvoid f() { }\n", actual[""]); + ASSERT_EQUALS("\n\nvoid f() { }\n", actual[""]); ASSERT_EQUALS("", errout.str()); }