diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 2048d6f8098..51fafddacd7 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -884,6 +884,21 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string return checkInternal(file, cfgname, fileIndex, f); } +void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector& files) +{ + if (!mSettings.plistOutput.empty()) { + const bool slashFound = file.spath().find('/') != std::string::npos; + std::string filename = slashFound ? file.spath().substr(file.spath().rfind('/') + 1) : file.spath(); + // removes suffix from filename when it exists + const std::string noSuffixFilename = filename.substr(0, filename.find('.')); + + // the hash is added to handle when files in different folders have the same name + const std::size_t fileNameHash = std::hash {}(file.spath()); + filename = mSettings.plistOutput + noSuffixFilename + "_" + std::to_string(fileNameHash) + ".plist"; + mLogger->openPlist(filename, files); + } +} + unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const CreateTokenListFn& createTokenList) { // TODO: move to constructor when CppCheck no longer owns the settings @@ -989,16 +1004,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (!preprocessor.loadFiles(tokens1, files)) return mLogger->exitcode(); - if (!mSettings.plistOutput.empty()) { - std::string filename2; - if (file.spath().find('/') != std::string::npos) - filename2 = file.spath().substr(file.spath().rfind('/') + 1); - else - filename2 = file.spath(); - const std::size_t fileNameHash = std::hash {}(file.spath()); - filename2 = mSettings.plistOutput + filename2.substr(0, filename2.find('.')) + "_" + std::to_string(fileNameHash) + ".plist"; - mLogger->openPlist(filename2, files); - } + checkPlistOutput(file, files); std::string dumpProlog; if (mSettings.dump || !mSettings.addons.empty()) { diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 9108ac28430..54ed1d73227 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -185,6 +185,8 @@ class CPPCHECKLIB CppCheck { */ unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex); + void checkPlistOutput(const FileWithDetails& file, const std::vector& files); + /** * @brief Check a file using buffer * @param file the file diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 643355ad2c3..0b6829a29f4 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -79,6 +79,7 @@ class TestCppcheck : public TestFixture { TEST_CASE(isPremiumCodingStandardId); TEST_CASE(getDumpFileContentsRawTokens); TEST_CASE(getDumpFileContentsLibrary); + TEST_CASE(checkPlistOutput); TEST_CASE(premiumResultsCache); TEST_CASE(toomanyconfigs); TEST_CASE(purgedConfiguration); @@ -522,6 +523,43 @@ class TestCppcheck : public TestFixture { } } + void checkPlistOutput() const { + Suppressions supprs; + ErrorLogger2 errorLogger; + std::vector files = {"textfile.txt"}; + + { + const auto s = dinit(Settings, $.templateFormat = templateFormat, $.plistOutput = "output"); + const ScopedFile file("file", ""); + CppCheck cppcheck(s, supprs, errorLogger, false, {}); + const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; + + cppcheck.checkPlistOutput(fileWithDetails, files); + const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; + ASSERT(Path::exists(outputFile)); + std::remove(outputFile.c_str()); + } + + { + const auto s = dinit(Settings, $.plistOutput = "output"); + const ScopedFile file("file.c", ""); + CppCheck cppcheck(s, supprs, errorLogger, false, {}); + const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; + + cppcheck.checkPlistOutput(fileWithDetails, files); + const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; + ASSERT(Path::exists(outputFile)); + std::remove(outputFile.c_str()); + } + + { + Settings s; + const ScopedFile file("file.c", ""); + CppCheck cppcheck(s, supprs, errorLogger, false, {}); + cppcheck.checkPlistOutput(FileWithDetails(file.path(), Path::identify(file.path(), false), 0), files); + } + } + void premiumResultsCache() const { // Trac #13889 - cached misra results are shown after removing --premium=misra-c-2012 option