diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 4c3bcb7d0b6..67be1dd51e9 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -551,6 +551,14 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file) return mExitCode; } +static ErrorMessage makeError(const std::string &filename, int line, unsigned int column, const std::string &msg, const std::string &id) +{ + const ErrorMessage::FileLocation loc1(filename, line, column); + const std::list callstack(1, loc1); + + return ErrorMessage(callstack, emptyString, Severity::error, msg, id, Certainty::normal); +} + unsigned int CppCheck::check(const FileWithDetails &file) { if (mSettings.clang) @@ -570,7 +578,6 @@ unsigned int CppCheck::check(const FileSettings &fs) // TODO: move to constructor when CppCheck no longer owns the settings if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mUnusedFunctionsCheck) mUnusedFunctionsCheck.reset(new CheckUnusedFunctions()); - CppCheck temp(mErrorLogger, mUseGlobalSuppressions, mExecuteCommand); temp.mSettings = mSettings; if (!temp.mSettings.userDefines.empty()) @@ -622,8 +629,6 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mUnusedFunctionsCheck) mUnusedFunctionsCheck.reset(new CheckUnusedFunctions()); - mExitCode = 0; - if (Settings::terminated()) return mExitCode; @@ -688,16 +693,20 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string std::string locfile = Path::fromNativeSeparators(output.location.file()); if (mSettings.relativePaths) locfile = Path::getRelativePath(locfile, mSettings.basePaths); - - ErrorMessage::FileLocation loc1(locfile, output.location.line, output.location.col); - - ErrorMessage errmsg({std::move(loc1)}, - "", // TODO: is this correct? - Severity::error, - output.msg, - "syntaxError", - Certainty::normal); - reportErr(errmsg); + if (output.type == simplecpp::Output::Type::FILE_NOT_FOUND) { + const std::string fixedpath = Path::toNativeSeparators(file.path()); + const std::string errorMsg("File " + fixedpath + " does not exist. Skipping file."); + + reportErr(ErrorMessage(std::list (), + emptyString, + Severity::error, + errorMsg, + "fileNotFound", + Certainty::normal)); + } + else { + reportErr(makeError(file.path(), output.location.line, output.location.col, output.msg, "syntaxError")); + } return mExitCode; } @@ -757,7 +766,6 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string return mExitCode; // known results => no need to reanalyze file } } - FilesDeleter filesDeleter; // write dump file xml prolog @@ -1027,18 +1035,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string // TODO: replace with ErrorMessage::fromInternalError() void CppCheck::internalError(const std::string &filename, const std::string &msg) { - const std::string fullmsg("Bailing out from analysis: " + msg); - - ErrorMessage::FileLocation loc1(filename, 0, 0); - - ErrorMessage errmsg({std::move(loc1)}, - emptyString, - Severity::error, - fullmsg, - "internalError", - Certainty::normal); - - mErrorLogger.reportErr(errmsg); + mErrorLogger.reportErr(makeError(filename, 0, 0U, "Bailing out from analysis:" + msg, "internalError")); } //--------------------------------------------------------------------------- diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 17c5a82c977..29e97777869 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -44,6 +44,7 @@ const std::set ErrorLogger::mCriticalErrorIds{ "cppcheckError", "cppcheckLimit", + "fileNotFound", "internalAstError", "instantiationError", "internalError", diff --git a/test/cli/more-projects_test.py b/test/cli/more-projects_test.py index 7824bb88f5c..981b0a4e07a 100644 --- a/test/cli/more-projects_test.py +++ b/test/cli/more-projects_test.py @@ -864,3 +864,136 @@ def test_shared_items_project(tmpdir = ""): # Assume no errors, and that shared items code files have been checked as well assert any('2/2 files checked 100% done' in x for x in lines) assert stderr == '' + + +def test_project_missing_files(tmpdir): + filename = os.path.join(tmpdir, 'main.c') + project_file = os.path.join(tmpdir, 'helloworld.vcxproj') + with open(project_file, 'wt') as f: + f.write( +""" + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {7319858B-261C-4F0D-B022-92BB896242DD} + invalidProjet + 10.0.16299.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + +""") + ret, _, stderr = cppcheck(['--template=cppcheck1', '--project=' + os.path.join(tmpdir, 'helloworld.vcxproj')]) + assert ret == 0 + assert stderr == ': (error) File {} does not exists. Skipping file.\n'.format(filename) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 34f07414dd9..9198708dd33 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -54,6 +54,7 @@ class TestCppcheck : public TestFixture { void run() override { TEST_CASE(getErrorMessages); TEST_CASE(checkWithFile); + TEST_CASE(checkWithoutFile); TEST_CASE(checkWithFS); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); @@ -112,6 +113,17 @@ class TestCppcheck : public TestFixture { ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); } + void checkWithoutFile() const + { + ErrorLogger2 errorLogger; + CppCheck cppcheck(errorLogger, false, {}); + ASSERT_EQUALS(1, cppcheck.check(FileWithDetails("NotAFile"))); + + ASSERT_EQUALS(1, errorLogger.ids.size()); + ASSERT_EQUALS("fileNotFound", *errorLogger.ids.cbegin()); + ASSERT_EQUALS("File NotAFile does not exists. Skipping file.", errorLogger.errmsgs.cbegin()->shortMessage()); + } + void checkWithFS() const { ScopedFile file("test.cpp", diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index d206f1f1b2a..2dc8b31247d 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -1190,8 +1190,9 @@ class TestSuppressions : public TestFixture { ASSERT_EQUALS("", settings.supprs.nomsg.addSuppressionLine("uninitvar")); settings.exitCode = 1; - const char code[] = "int f() { int a; return a; }"; - ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("test.c"), code)); // <- no unsuppressed error is seen + ScopedFile file("test.c", "int f() { int a; return a; }"); + FileSettings fs{file.path()}; + ASSERT_EQUALS(0, cppCheck.check(fs)); // <- no unsuppressed error is seen ASSERT_EQUALS("[test.c:1]: (error) Uninitialized variable: a\n", errout_str()); // <- report error so ThreadExecutor can suppress it and make sure the global suppression is matched. } @@ -1223,16 +1224,17 @@ class TestSuppressions : public TestFixture { settings.inlineSuppressions = true; settings.relativePaths = true; settings.basePaths.emplace_back("/somewhere"); - const char code[] = - "struct Point\n" - "{\n" - " // cppcheck-suppress unusedStructMember\n" - " int x;\n" - " // cppcheck-suppress unusedStructMember\n" - " int y;\n" - "};"; - ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("/somewhere/test.cpp"), code)); - ASSERT_EQUALS("",errout_str()); + ScopedFile file("test.cpp", + "struct Point\n" + "{\n" + " // cppcheck-suppress unusedStructMember\n" + " int x;\n" + " // cppcheck-suppress unusedStructMember\n" + " int y;\n" + "};"); + FileSettings fs{file.path()}; + ASSERT_EQUALS(0, cppCheck.check(fs)); + ASSERT_EQUALS("", errout_str()); } void suppressingSyntaxErrorsInternal(unsigned int (TestSuppressions::*check)(const char[], const std::string &)) { // syntaxErrors should be suppressible (#7076)