diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index da078e5eb20..b7ab1f99039 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1136,15 +1136,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 243f600b5a6..614e9eb4679 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -4240,6 +4240,117 @@ def test_no_valid_configuration(tmp_path): ] +# 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', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_unused_private_function_multi_file(tmpdir): # ticket #2567 + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( +""" +struct Fred +{ + Fred() + { + Init(); + } +private: + void Init(); +}; +""") + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "test.h" + +void Fred::Init() +{ +} +""") + + args = [ + '-q', + '--template=simple', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_missing_doublequote_include(tmpdir): + test_inc = os.path.join(tmpdir, 'abc.h') + with open(test_inc, 'wt') as f: + f.write( +''' +#define a +" +''') + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "abc.h" +""") + + args = [ + '-q', + '--template=simple', + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_inc}:3:1: error: No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]" + ] + assert ret == 0, stdout + + def test_no_valid_configuration_check_config(tmp_path): test_file = tmp_path / 'test.c' with open(test_file, "w") as f: diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 7e01f6f233b..b90a879738d 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -50,13 +50,14 @@ class TestPreprocessor : public TestFixture { TestPreprocessor() : TestFixture("TestPreprocessor") {} private: + #define expandMacros(...) expandMacros_(__FILE__, __LINE__, __VA_ARGS__) template - std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger) const { + std::string expandMacros_(const char* file, int line, const char (&code)[size], ErrorLogger &errorLogger) 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)); - ASSERT(p.loadFiles(files)); + ASSERT_LOC(p.loadFiles(files), file, line); simplecpp::TokenList tokens2 = p.preprocess("", files, outputList); (void)p.reportOutput(outputList, true); return tokens2.stringify(); @@ -140,7 +141,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] = ""; @@ -392,7 +393,7 @@ class TestPreprocessor : public TestFixture { std::vector files; simplecpp::OutputList outputList; simplecpp::TokenList tokens(code,files,"test.c",&outputList); - Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); // TODO: do we need to consider #file? + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); ASSERT(preprocessor.loadFiles(files)); ASSERT(!preprocessor.reportOutput(outputList, true)); preprocessor.removeComments(); @@ -407,7 +408,7 @@ class TestPreprocessor : public TestFixture { std::size_t getHash(const char (&code)[size]) { std::vector files; simplecpp::TokenList tokens(code,files,"test.c"); - Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); // TODO: do we need to consider #file? + Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); ASSERT(preprocessor.loadFiles(files)); preprocessor.removeComments(); return preprocessor.calculateHash(""); @@ -472,16 +473,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()); } @@ -584,35 +588,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=ABC\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=ABC\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"; @@ -1576,22 +1580,9 @@ class TestPreprocessor : public TestFixture { } { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "\"\n" - "#endfile\n"; - - // expand macros.. - const std::string actual(expandMacros(filedata, *this)); - - 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.. @@ -2286,14 +2277,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=ABC\n", getConfigsStr(filedata)); } @@ -2315,12 +2306,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 5f4d59503e2..7e4bb9f394c 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8821,14 +8821,11 @@ class TestTokenizer : public TestFixture { } void testDirectiveIncludeLocations() { + ScopedFile inc1("inc1.h", "#define macro2 val\n#include \"inc2.h\"\n#define macro4 val\n"); + ScopedFile inc2("inc2.h", "#define macro3 val\n"); + // TODO: preprocess? const char filedata[] = "#define macro1 val\n" - "#file \"inc1.h\"\n" - "#define macro2 val\n" - "#file \"inc2.h\"\n" - "#define macro3 val\n" - "#endfile\n" - "#define macro4 val\n" - "#endfile\n" + "#include \"inc1.h\"\n" "#define macro5 val\n"; const char dumpdata[] = " \n" " \n" @@ -8839,8 +8836,14 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8850,14 +8853,8 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8865,10 +8862,10 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index 4a2a6ca1894..09f8c21d102 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. @@ -76,7 +75,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(testDoesNotIdentifyMethodAsMiddleFunctionArgument); TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument); - TEST_CASE(multiFile); TEST_CASE(unknownBaseTemplate); // ticket #2580 TEST_CASE(hierarchy_loop); // ticket 5590 @@ -482,24 +480,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" @@ -780,25 +760,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void multiFile() { // ticket #2567 - check("#file \"test.h\"\n" - "struct Fred\n" - "{\n" - " Fred()\n" - " {\n" - " Init();\n" - " }\n" - "private:\n" - " void Init();\n" - "};\n" - "#endfile\n" - "void Fred::Init()\n" - "{\n" - "}"); - - ASSERT_EQUALS("", errout_str()); - } - void unknownBaseTemplate() { // ticket #2580 check("class Bla : public Base2 {\n" "public:\n"