diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9aa7ec9d6b0..3fdf745f239 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1124,15 +1124,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str codeWithoutCfg = preprocessor.getcode(currentConfig, files, true); }); - if (startsWith(codeWithoutCfg,"#file")) - codeWithoutCfg.insert(0U, "//"); std::string::size_type pos = 0; - while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; - while ((pos = codeWithoutCfg.find("\n#endfile",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; while ((pos = codeWithoutCfg.find(Preprocessor::macroChar,pos)) != std::string::npos) codeWithoutCfg[pos] = ' '; mErrorLogger.reportOut(codeWithoutCfg, Color::Reset); diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 0da8b09f9d7..d57340dcb73 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3986,3 +3986,41 @@ def test_max_configs(tmp_path, max_configs, number_of_configs, check_config, exp '{}:0:0: information: Too many #ifdef configurations - cppcheck only checks {} of {} configurations. Use --force to check all configurations. [toomanyconfigs]' .format(test_file, max_configs, number_of_configs) ] + + +# The implementation for "A::a" is missing - so don't check if "A::b" is used or not +def test_unused_private_function_incomplete_impl(tmpdir): + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( + """ + class A + { + public: + A(); + void a(); + private: + void b(); + }; + """) + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( + """ + #include "test.h" + + A::A() { } + void A::b() { } + """) + + args = [ + '-q', + '--template=simple', + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout \ No newline at end of file diff --git a/test/helpers.cpp b/test/helpers.cpp index e3087966cda..8a293231394 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -113,9 +113,12 @@ ScopedFile::~ScopedFile() { void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vector &files, const std::string& file0, Tokenizer& tokenizer, ErrorLogger& errorlogger) { - simplecpp::TokenList tokens1(code, size, files, file0); + simplecpp::OutputList outputList; + simplecpp::TokenList tokens1(code, size, files, file0, &outputList); Preprocessor preprocessor(tokens1, tokenizer.getSettings(), errorlogger, Path::identify(tokens1.getFiles()[0], false)); + (void)preprocessor.reportOutput(outputList, true); + (void)preprocessor.loadFiles(files); // TODO: check result simplecpp::TokenList tokens2 = preprocessor.preprocess("", files, true); // Tokenizer.. diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 2e10fbb5ef0..66ab2e5b7a1 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -50,12 +50,13 @@ class TestPreprocessor : public TestFixture { private: template - std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger) const { + std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger, bool throwError = true) const { simplecpp::OutputList outputList; std::vector files; simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList); Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); - simplecpp::TokenList tokens2 = p.preprocess("", files, true); + ASSERT(p.loadFiles(files)); + simplecpp::TokenList tokens2 = p.preprocess("", files, throwError); (void)p.reportOutput(outputList, true); return tokens2.stringify(); } @@ -69,13 +70,14 @@ class TestPreprocessor : public TestFixture { if (tokenlist.front()) throw std::runtime_error("token list not empty"); - const simplecpp::TokenList tokens1(code, files, file0); + simplecpp::OutputList outputList; + const simplecpp::TokenList tokens1(code, files, file0, &outputList); // Preprocess.. simplecpp::TokenList tokens2(files); simplecpp::FileDataCache cache; - // TODO: provide and handle outputList - simplecpp::preprocess(tokens2, tokens1, files, cache, dui); + simplecpp::preprocess(tokens2, tokens1, files, cache, dui, outputList); + // TODO: handle outputList // Tokenizer.. tokenlist.createTokens(std::move(tokens2)); @@ -135,7 +137,7 @@ class TestPreprocessor : public TestFixture { cfgs = preprocessor.getConfigs(); for (const std::string & config : cfgs) { try { - const bool writeLocations = (strstr(code, "#file") != nullptr) || (strstr(code, "#include") != nullptr); + const bool writeLocations = (strstr(code, "#include") != nullptr); cfgcode[config] = preprocessor.getcode(config, files, writeLocations); } catch (const simplecpp::Output &) { cfgcode[config] = ""; @@ -368,9 +370,12 @@ class TestPreprocessor : public TestFixture { if (library) ASSERT(settings.library.load("", library, false).errorcode == Library::ErrorCode::OK); std::vector files; + simplecpp::OutputList outputList; // TODO: this adds an empty filename - simplecpp::TokenList tokens(code,files); - Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); // TODO: do we need to consider #file? + simplecpp::TokenList tokens(code,files,"",&outputList); + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); + ASSERT(preprocessor.loadFiles(files)); + ASSERT(!preprocessor.reportOutput(outputList, true)); preprocessor.removeComments(); const std::set configs = preprocessor.getConfigs(); std::string ret; @@ -383,8 +388,9 @@ class TestPreprocessor : public TestFixture { std::size_t getHash(const char (&code)[size]) { std::vector files; // TODO: this adds an empty filename - simplecpp::TokenList tokens(code,files); - Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); // TODO: do we need to consider #file? + simplecpp::TokenList tokens(code,files,""); + Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); + ASSERT(preprocessor.loadFiles(files)); preprocessor.removeComments(); return preprocessor.calculateHash(""); } @@ -448,16 +454,19 @@ class TestPreprocessor : public TestFixture { void error4() { // In included file { + ScopedFile header("ab.h", "#error hello world!\n"); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n#error hello world!\n#endfile"; + const char code[] = "#include \"ab.h\""; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[ab.h:1:2]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); } // After including a file { + ScopedFile header("ab.h", ""); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n\n#endfile\n#error aaa"; + const char code[] = "#include \"ab.h\"\n" + "#error aaa"; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[test.c:2:2]: (error) #error aaa [preprocessorErrorDirective]\n", errout_str()); } @@ -560,35 +569,35 @@ class TestPreprocessor : public TestFixture { } void includeguard1() { + ScopedFile header("abc.h", + "#ifndef abcH\n" + "#define abcH\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "#ifndef abcH\n" - "#define abcH\n" - "#endif\n" - "#endfile\n" + const char filedata[] = "#include \"abc.h\"\n" "#ifdef ABC\n" "#endif"; ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); } void includeguard2() { + ScopedFile header("abc.h", + "foo\n" + "#ifdef ABC\n" + "\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "foo\n" - "#ifdef ABC\n" - "\n" - "#endif\n" - "#endfile\n"; + const char filedata[] = "#include \"abc.h\"\n"; ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); } void ifdefwithfile() { + ScopedFile header("abc.h", "class A{};/*\n\n\n\n\n\n\n*/\n"); + // Handling include guards.. const char filedata[] = "#ifdef ABC\n" - "#file \"abc.h\"\n" - "class A{};/*\n\n\n\n\n\n\n*/\n" - "#endfile\n" + "#include \"abc.h\"\n" "#endif\n" "int main() {}\n"; @@ -1552,26 +1561,26 @@ class TestPreprocessor : public TestFixture { } { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "\"\n" - "#endfile\n"; + ScopedFile header("abc.h", + "#define a\n" + "\"\n"); + const char filedata[] = "#include \"abc.h\""; // expand macros.. - const std::string actual(expandMacros(filedata, *this)); + const std::string actual(expandMacros(filedata, *this, false)); ASSERT_EQUALS("", actual); ASSERT_EQUALS("[abc.h:2:1]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); } { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "#endfile\n" + ScopedFile header("abc.h", + "#define a\n"); + const char filedata[] = "#include \"abc.h\"\n" "\"\n"; // expand macros.. - const std::string actual(expandMacros(filedata, *this)); + const std::string actual(expandMacros(filedata, *this, false)); ASSERT_EQUALS("", actual); ASSERT_EQUALS("[file.cpp:2:1]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); @@ -2230,14 +2239,14 @@ class TestPreprocessor : public TestFixture { } void getConfigs7e() { + ScopedFile header("test.h", + "#ifndef test_h\n" + "#define test_h\n" + "#ifdef ABC\n" + "#endif\n" + "#endif\n"); const char filedata[] = "#ifdef ABC\n" - "#file \"test.h\"\n" - "#ifndef test_h\n" - "#define test_h\n" - "#ifdef ABC\n" - "#endif\n" - "#endif\n" - "#endfile\n" + "#include \"test.h\"\n" "#endif\n"; ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); } @@ -2259,12 +2268,12 @@ class TestPreprocessor : public TestFixture { } void getConfigs11() { // #9832 - include guards - const char filedata[] = "#file \"test.h\"\n" - "#if !defined(test_h)\n" - "#define test_h\n" - "123\n" - "#endif\n" - "#endfile\n"; + ScopedFile header("test.h", + "#if !defined(test_h)\n" + "#define test_h\n" + "123\n" + "#endif\n"); + const char filedata[] = "#include \"test.h\"\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata)); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 7eb3576f688..5b393d38eda 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -599,6 +599,8 @@ class TestTokenizer : public TestFixture { std::vector files; simplecpp::TokenList tokens1(code, files, filename, &outputList); Preprocessor preprocessor(tokens1, settings, *this, Path::identify(tokens1.getFiles()[0], false)); + (void)preprocessor.reportOutput(outputList, true); + ASSERT(preprocessor.loadFiles(files)); std::list directives = preprocessor.createDirectives(); TokenList tokenlist{settings, Path::identify(filename, false)}; @@ -8582,9 +8584,9 @@ class TestTokenizer : public TestFixture { "#define macro2 val\n" "#file \"inc2.h\"\n" "#define macro3 val\n" - "#endfile\n" + "#endfile\n" // TODO "#define macro4 val\n" - "#endfile\n" + "#endfile\n" // TODO "#define macro5 val\n"; const char dumpdata[] = " \n" " \n" diff --git a/test/testtokenlist.cpp b/test/testtokenlist.cpp index 2e7baa9e3a5..1b345e9deb5 100644 --- a/test/testtokenlist.cpp +++ b/test/testtokenlist.cpp @@ -158,6 +158,7 @@ class TestTokenList : public TestFixture { std::vector files; simplecpp::TokenList tokens1(code, files, "poll.h", nullptr); Preprocessor preprocessor(tokens1, settingsDefault, *this, Path::identify(tokens1.getFiles()[0], false)); + ASSERT(preprocessor.loadFiles(files)); simplecpp::TokenList tokensP = preprocessor.preprocess("", files, true); TokenList tokenlist(settingsDefault, Standards::Language::C); // headers are treated as C files tokenlist.createTokens(std::move(tokensP)); // do not assert diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index 5a364347163..f7dcfdf6161 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.cpp @@ -58,7 +58,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(classInClass); TEST_CASE(sameFunctionNames); - TEST_CASE(incompleteImplementation); TEST_CASE(derivedClass); // skip warning for derived classes. It might be a virtual function. @@ -482,24 +481,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void incompleteImplementation() { - // The implementation for "A::a" is missing - so don't check if - // "A::b" is used or not - check("#file \"test.h\"\n" - "class A\n" - "{\n" - "public:\n" - " A();\n" - " void a();\n" - "private:\n" - " void b();\n" - "};\n" - "#endfile\n" - "A::A() { }\n" - "void A::b() { }"); - ASSERT_EQUALS("", errout_str()); - } - void derivedClass() { // skip warning in derived classes in case the base class is invisible check("class derived : public base\n" @@ -791,7 +772,7 @@ class TestUnusedPrivateFunction : public TestFixture { "private:\n" " void Init();\n" "};\n" - "#endfile\n" + "#endfile\n" // TODO "void Fred::Init()\n" "{\n" "}");