diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 6495779fe..c1cb6c915 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -209,8 +209,7 @@ bool CppCheckExecutor::parseFromArgs(Settings &settings, int argc, const char* c } if (!pathnames.empty()) { - // TODO: this should be a vector or list so the order is kept - std::map files; + std::list> files; // TODO: this needs to be inlined into PathMatch as it depends on the underlying filesystem #if defined(_WIN32) // For Windows we want case-insensitive path matching @@ -286,7 +285,7 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck) return check_internal(cppcheck); } -bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::map &files, ErrorLogger& errorLogger) { +bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::list> &files, ErrorLogger& errorLogger) { const auto& suppressions = settings.nomsg.getSuppressions(); if (std::any_of(suppressions.begin(), suppressions.end(), [](const Suppressions::Suppression& s) { return s.errorId == "unmatchedSuppression" && s.fileName.empty() && s.lineNumber == Suppressions::Suppression::NO_LINE; @@ -295,7 +294,7 @@ bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedF bool err = false; if (settings.useSingleJob()) { - for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) { + for (std::list>::const_iterator i = files.cbegin(); i != files.cend(); ++i) { err |= Suppressions::reportUnmatchedSuppressions( settings.nomsg.getUnmatchedLocalSuppressions(i->first, unusedFunctionCheckEnabled), errorLogger); } @@ -326,7 +325,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) settings.loadSummaries(); std::list fileNames; - for (std::map::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) + for (std::list>::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) fileNames.emplace_back(i->first); AnalyzerInformation::writeFilesTxt(settings.buildDir, fileNames, settings.userDefines, mFileSettings); } diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index ca66558a0..93c094bee 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -28,9 +28,9 @@ #include #include #include -#include #include #include +#include #include class CppCheck; @@ -129,7 +129,7 @@ private: */ bool parseFromArgs(Settings &settings, int argc, const char* const argv[]); - static bool reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::map &files, ErrorLogger& errorLogger); + static bool reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::list> &files, ErrorLogger& errorLogger); /** * Wrapper around check_internal @@ -183,7 +183,7 @@ private: /** * Filename associated with size of file */ - std::map mFiles; + std::list> mFiles; std::list mFileSettings; diff --git a/cli/executor.cpp b/cli/executor.cpp index 7febba3a7..40ae2437b 100644 --- a/cli/executor.cpp +++ b/cli/executor.cpp @@ -30,7 +30,7 @@ struct FileSettings; -Executor::Executor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) +Executor::Executor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) : mFiles(files), mFileSettings(fileSettings), mSettings(settings), mSuppressions(suppressions), mErrorLogger(errorLogger) { // the two inputs may only be used exclusively diff --git a/cli/executor.h b/cli/executor.h index df9138903..da6c3c9fc 100644 --- a/cli/executor.h +++ b/cli/executor.h @@ -21,9 +21,9 @@ #include #include -#include #include #include +#include class Settings; class ErrorLogger; @@ -40,7 +40,7 @@ struct FileSettings; */ class Executor { public: - Executor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); + Executor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); virtual ~Executor() = default; Executor(const Executor &) = delete; @@ -66,7 +66,7 @@ protected: */ bool hasToLog(const ErrorMessage &msg); - const std::map &mFiles; + const std::list> &mFiles; const std::list& mFileSettings; const Settings &mSettings; Suppressions &mSuppressions; diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 4e7528938..1f94ea77f 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #ifdef _WIN32 @@ -39,12 +40,12 @@ // When compiling Unicode targets WinAPI automatically uses *W Unicode versions // of called functions. Thus, we explicitly call *A versions of the functions. -std::string FileLister::recursiveAddFiles(std::map &files, const std::string &path, const std::set &extra, const PathMatch& ignored) +std::string FileLister::recursiveAddFiles(std::list>&files, const std::string &path, const std::set &extra, const PathMatch& ignored) { return addFiles(files, path, extra, true, ignored); } -std::string FileLister::addFiles(std::map &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) +std::string FileLister::addFiles(std::list>&files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) { if (path.empty()) return "no path specified"; @@ -112,18 +113,27 @@ std::string FileLister::addFiles(std::map &files, cons // Limitation: file sizes are assumed to fit in a 'size_t' #ifdef _WIN64 - files[nativename] = (static_cast(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow; + files.emplace_back(nativename, (static_cast(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow); #else - files[nativename] = ffd.nFileSizeLow; + files.emplace_back(nativename, ffd.nFileSizeLow); #endif } } else { // Directory if (recursive) { if (!ignored.match(fname)) { - std::string err = FileLister::recursiveAddFiles(files, fname, extra, ignored); + std::list> filesSorted; + + std::string err = FileLister::recursiveAddFiles(filesSorted, fname, extra, ignored); if (!err.empty()) return err; + + // files inside directories need to be sorted as the filesystem doesn't provide a stable order + filesSorted.sort([](const decltype(filesSorted)::value_type& a, const decltype(filesSorted)::value_type& b) { + return a.first < b.first; + }); + + files.insert(files.end(), std::make_move_iterator(filesSorted.begin()), std::make_move_iterator(filesSorted.end())); } } } @@ -155,7 +165,7 @@ std::string FileLister::addFiles(std::map &files, cons #include #include -static std::string addFiles2(std::map &files, +static std::string addFiles2(std::list> &files, const std::string &path, const std::set &extra, bool recursive, @@ -178,6 +188,8 @@ static std::string addFiles2(std::map &files, std::string new_path = path; new_path += '/'; + std::list> filesSorted; + while (const dirent* dir_result = readdir(dir)) { if ((std::strcmp(dir_result->d_name, ".") == 0) || (std::strcmp(dir_result->d_name, "..") == 0)) @@ -193,15 +205,16 @@ static std::string addFiles2(std::map &files, #endif if (path_is_directory) { if (recursive && !ignored.match(new_path)) { - std::string err = addFiles2(files, new_path, extra, recursive, ignored); + std::string err = addFiles2(filesSorted, new_path, extra, recursive, ignored); if (!err.empty()) { return err; } } } else { if (Path::acceptFile(new_path, extra) && !ignored.match(new_path)) { - if (stat(new_path.c_str(), &file_stat) != -1) - files[new_path] = file_stat.st_size; + if (stat(new_path.c_str(), &file_stat) != -1) { + filesSorted.emplace_back(new_path, file_stat.st_size); + } else { const int err = errno; return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")"; @@ -209,18 +222,25 @@ static std::string addFiles2(std::map &files, } } } + + // files inside directories need to be sorted as the filesystem doesn't provide a stable order + filesSorted.sort([](const decltype(filesSorted)::value_type& a, const decltype(filesSorted)::value_type& b) { + return a.first < b.first; + }); + + files.insert(files.end(), std::make_move_iterator(filesSorted.begin()), std::make_move_iterator(filesSorted.end())); } else - files[path] = file_stat.st_size; + files.emplace_back(path, file_stat.st_size); } return ""; } -std::string FileLister::recursiveAddFiles(std::map &files, const std::string &path, const std::set &extra, const PathMatch& ignored) +std::string FileLister::recursiveAddFiles(std::list> &files, const std::string &path, const std::set &extra, const PathMatch& ignored) { return addFiles(files, path, extra, true, ignored); } -std::string FileLister::addFiles(std::map &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) +std::string FileLister::addFiles(std::list> &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) { if (path.empty()) return "no path specified"; diff --git a/cli/filelister.h b/cli/filelister.h index dc1f34b3b..c17dea3c3 100644 --- a/cli/filelister.h +++ b/cli/filelister.h @@ -20,9 +20,10 @@ #define filelisterH #include -#include +#include #include #include +#include class PathMatch; @@ -37,12 +38,12 @@ public: * Add source files from given directory and all subdirectries to the * given map. Only files with accepted extensions * (*.c;*.cpp;*.cxx;*.c++;*.cc;*.txx) are added. - * @param files output map that associates the size of each file with its name + * @param files output list that associates the size of each file with its name * @param path root path * @param ignored ignored paths * @return On success, an empty string is returned. On error, a error message is returned. */ - static std::string recursiveAddFiles(std::map &files, const std::string &path, const PathMatch& ignored) { + static std::string recursiveAddFiles(std::list> &files, const std::string &path, const PathMatch& ignored) { const std::set extra; return recursiveAddFiles(files, path, extra, ignored); } @@ -52,27 +53,27 @@ public: * Add source files from given directory and all subdirectries to the * given map. Only files with accepted extensions * (*.c;*.cpp;*.cxx;*.c++;*.cc;*.txx) are added. - * @param files output map that associates the size of each file with its name + * @param files output list that associates the size of each file with its name * @param path root path * @param extra Extra file extensions * @param ignored ignored paths * @return On success, an empty string is returned. On error, a error message is returned. */ - static std::string recursiveAddFiles(std::map &files, const std::string &path, const std::set &extra, const PathMatch& ignored); + static std::string recursiveAddFiles(std::list> &files, const std::string &path, const std::set &extra, const PathMatch& ignored); /** * @brief (Recursively) add source files to a map. * Add source files from given directory and all subdirectries to the * given map. Only files with accepted extensions * (*.c;*.cpp;*.cxx;*.c++;*.cc;*.txx) are added. - * @param files output map that associates the size of each file with its name + * @param files output list that associates the size of each file with its name * @param path root path * @param extra Extra file extensions * @param recursive Enable recursion * @param ignored ignored paths * @return On success, an empty string is returned. On error, a error message is returned. */ - static std::string addFiles(std::map &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored); + static std::string addFiles(std::list> &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored); }; /// @} diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index 791c0c880..103399b53 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include // IWYU pragma: keep #include #include @@ -60,7 +61,7 @@ enum class Color; using std::memset; -ProcessExecutor::ProcessExecutor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) +ProcessExecutor::ProcessExecutor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) : Executor(files, fileSettings, settings, suppressions, errorLogger) , mExecuteCommand(std::move(executeCommand)) { @@ -236,7 +237,7 @@ unsigned int ProcessExecutor::check() std::map childFile; std::map pipeFile; std::size_t processedsize = 0; - std::map::const_iterator iFile = mFiles.cbegin(); + std::list>::const_iterator iFile = mFiles.cbegin(); std::list::const_iterator iFileSettings = mFileSettings.cbegin(); for (;;) { // Start a new child @@ -325,7 +326,9 @@ unsigned int ProcessExecutor::check() std::size_t size = 0; if (p != pipeFile.end()) { pipeFile.erase(p); - const std::map::const_iterator fs = mFiles.find(name); + const auto fs = std::find_if(mFiles.cbegin(), mFiles.cend(), [&name](const std::pair& entry) { + return entry.first == name; + }); if (fs != mFiles.end()) { size = fs->second; } diff --git a/cli/processexecutor.h b/cli/processexecutor.h index 65e27975f..0ecde2372 100644 --- a/cli/processexecutor.h +++ b/cli/processexecutor.h @@ -24,8 +24,8 @@ #include #include -#include #include +#include class Settings; class ErrorLogger; @@ -41,7 +41,7 @@ struct FileSettings; */ class ProcessExecutor : public Executor { public: - ProcessExecutor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); + ProcessExecutor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); ProcessExecutor(const ProcessExecutor &) = delete; void operator=(const ProcessExecutor &) = delete; diff --git a/cli/singleexecutor.cpp b/cli/singleexecutor.cpp index 5a8fb2281..d174fed9d 100644 --- a/cli/singleexecutor.cpp +++ b/cli/singleexecutor.cpp @@ -31,7 +31,7 @@ class ErrorLogger; -SingleExecutor::SingleExecutor(CppCheck &cppcheck, const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) +SingleExecutor::SingleExecutor(CppCheck &cppcheck, const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) : Executor(files, fileSettings, settings, suppressions, errorLogger) , mCppcheck(cppcheck) { @@ -50,7 +50,7 @@ unsigned int SingleExecutor::check() std::size_t processedsize = 0; unsigned int c = 0; - for (std::map::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) { + for (std::list>::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) { if (!mSettings.library.markupFile(i->first) || !mSettings.library.processMarkupAfterCode(i->first)) { result += mCppcheck.check(i->first); processedsize += i->second; @@ -77,7 +77,7 @@ unsigned int SingleExecutor::check() // second loop to parse all markup files which may not work until all // c/cpp files have been parsed and checked // TODO: get rid of duplicated code - for (std::map::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) { + for (std::list>::const_iterator i = mFiles.cbegin(); i != mFiles.cend(); ++i) { if (mSettings.library.markupFile(i->first) && mSettings.library.processMarkupAfterCode(i->first)) { result += mCppcheck.check(i->first); processedsize += i->second; diff --git a/cli/singleexecutor.h b/cli/singleexecutor.h index 6f6a9a2d7..43584c68a 100644 --- a/cli/singleexecutor.h +++ b/cli/singleexecutor.h @@ -23,8 +23,8 @@ #include #include -#include #include +#include class ErrorLogger; class Settings; @@ -35,7 +35,7 @@ struct FileSettings; class SingleExecutor : public Executor { public: - SingleExecutor(CppCheck &cppcheck, const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); + SingleExecutor(CppCheck &cppcheck, const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); SingleExecutor(const SingleExecutor &) = delete; void operator=(const SingleExecutor &) = delete; diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index 9fdfbc5d7..d8903b87b 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -39,7 +39,7 @@ enum class Color; -ThreadExecutor::ThreadExecutor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) +ThreadExecutor::ThreadExecutor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) : Executor(files, fileSettings, settings, suppressions, errorLogger) , mExecuteCommand(std::move(executeCommand)) { @@ -81,7 +81,7 @@ private: class ThreadData { public: - ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::map &files, const std::list &fileSettings, CppCheck::ExecuteCmdFn executeCommand) + ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::list> &files, const std::list &fileSettings, CppCheck::ExecuteCmdFn executeCommand) : mFiles(files), mFileSettings(fileSettings), mSettings(settings), mExecuteCommand(std::move(executeCommand)), logForwarder(threadExecutor, errorLogger) { mItNextFile = mFiles.begin(); @@ -140,8 +140,8 @@ public: } private: - const std::map &mFiles; - std::map::const_iterator mItNextFile; + const std::list> &mFiles; + std::list>::const_iterator mItNextFile; const std::list &mFileSettings; std::list::const_iterator mItNextFileSettings; diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index aba60139e..47a6173ad 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -24,8 +24,8 @@ #include #include -#include #include +#include class Settings; class ErrorLogger; @@ -43,7 +43,7 @@ class ThreadExecutor : public Executor { friend class SyncLogForwarder; public: - ThreadExecutor(const std::map &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); + ThreadExecutor(const std::list> &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); ThreadExecutor(const ThreadExecutor &) = delete; void operator=(const ThreadExecutor &) = delete; diff --git a/gui/checkthread.cpp b/gui/checkthread.cpp index ba731ff41..0da46e6fa 100644 --- a/gui/checkthread.cpp +++ b/gui/checkthread.cpp @@ -34,10 +34,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -111,9 +111,10 @@ void CheckThread::run() if (!mFiles.isEmpty() || mAnalyseWholeProgram) { mAnalyseWholeProgram = false; qDebug() << "Whole program analysis"; - std::map files2; - for (const QString& file : mFiles) - files2[file.toStdString()] = 0; + std::list> files2; + std::transform(mFiles.cbegin(), mFiles.cend(), std::back_inserter(files2), [&](const QString& file) { + return std::pair{file.toStdString(), 0}; + }); mCppcheck.analyseWholeProgram(mCppcheck.settings().buildDir, files2, {}); mFiles.clear(); emit done(); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 32ab74b9c..abb323ed0 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index ea6577b48..d69e0ea7f 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1451,7 +1451,7 @@ void CppCheck::executeAddons(const std::vector& files, const std::s } } -void CppCheck::executeAddonsWholeProgram(const std::map &files) +void CppCheck::executeAddonsWholeProgram(const std::list> &files) { if (mSettings.addons.empty()) return; @@ -1722,7 +1722,7 @@ bool CppCheck::analyseWholeProgram() return errors && (mExitCode > 0); } -void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::map &files, const std::list& fileSettings) +void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::list> &files, const std::list& fileSettings) { executeAddonsWholeProgram(files); // TODO: pass FileSettings if (buildDir.empty()) { @@ -1790,7 +1790,7 @@ bool CppCheck::isUnusedFunctionCheckEnabled() const return (mSettings.useSingleJob() && mSettings.checks.isEnabled(Checks::unusedFunction)); } -void CppCheck::removeCtuInfoFiles(const std::map &files, const std::list& fileSettings) +void CppCheck::removeCtuInfoFiles(const std::list> &files, const std::list& fileSettings) { if (mSettings.buildDir.empty()) { for (const auto& f: files) { diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 93cc7ebb8..4ed6c9188 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -137,14 +137,14 @@ public: void analyseClangTidy(const FileSettings &fileSettings); /** analyse whole program use .analyzeinfo files */ - void analyseWholeProgram(const std::string &buildDir, const std::map &files, const std::list& fileSettings); + void analyseWholeProgram(const std::string &buildDir, const std::list> &files, const std::list& fileSettings); /** Check if the user wants to check for unused functions * and if it's possible at all */ bool isUnusedFunctionCheckEnabled() const; /** Remove *.ctu-info files */ - void removeCtuInfoFiles(const std::map& files, const std::list& fileSettings); // cppcheck-suppress functionConst // has side effects + void removeCtuInfoFiles(const std::list>& files, const std::list& fileSettings); // cppcheck-suppress functionConst // has side effects static void resetTimerResults(); static void printTimerResults(SHOWTIME_MODES mode); @@ -188,7 +188,7 @@ private: /** * Execute addons */ - void executeAddonsWholeProgram(const std::map &files); + void executeAddonsWholeProgram(const std::list> &files); #ifdef HAVE_RULES /** diff --git a/test/cli/test-more-projects.py b/test/cli/test-more-projects.py index 39d80b9e8..3693f930d 100644 --- a/test/cli/test-more-projects.py +++ b/test/cli/test-more-projects.py @@ -387,3 +387,48 @@ def test_project_file_filter_no_match(tmpdir): ] assert_cppcheck(args, ec_exp=1, err_exp=[], out_exp=out_lines) + + +def test_project_file_order(tmpdir): + test_file_a = os.path.join(tmpdir, 'a.c') + with open(test_file_a, 'wt'): + pass + test_file_b = os.path.join(tmpdir, 'b.c') + with open(test_file_b, 'wt'): + pass + test_file_c = os.path.join(tmpdir, 'c.c') + with open(test_file_c, 'wt'): + pass + test_file_d = os.path.join(tmpdir, 'd.c') + with open(test_file_d, 'wt'): + pass + + project_file = os.path.join(tmpdir, 'test.cppcheck') + with open(project_file, 'wt') as f: + f.write( + """ + + + + + + + +""".format(test_file_c, test_file_d, test_file_b, test_file_a)) + + args = ['--project={}'.format(project_file)] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + lines = stdout.splitlines() + assert lines == [ + 'Checking {} ...'.format(test_file_c), + '1/4 files checked 0% done', + 'Checking {} ...'.format(test_file_d), + '2/4 files checked 0% done', + 'Checking {} ...'.format(test_file_b), + '3/4 files checked 0% done', + 'Checking {} ...'.format(test_file_a), + '4/4 files checked 0% done' + ] + assert stderr == '' diff --git a/test/cli/test-other.py b/test/cli/test-other.py index 89b6e4467..5d7b68141 100644 --- a/test/cli/test-other.py +++ b/test/cli/test-other.py @@ -632,3 +632,35 @@ def test_file_filter_no_match(tmpdir): ] assert_cppcheck(args, ec_exp=1, err_exp=[], out_exp=out_lines) + + +def test_file_order(tmpdir): + test_file_a = os.path.join(tmpdir, 'a.c') + with open(test_file_a, 'wt'): + pass + test_file_b = os.path.join(tmpdir, 'b.c') + with open(test_file_b, 'wt'): + pass + test_file_c = os.path.join(tmpdir, 'c.c') + with open(test_file_c, 'wt'): + pass + test_file_d = os.path.join(tmpdir, 'd.c') + with open(test_file_d, 'wt'): + pass + + args = [test_file_c, test_file_d, test_file_b, test_file_a] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0 + lines = stdout.splitlines() + assert lines == [ + 'Checking {} ...'.format(test_file_c), + '1/4 files checked 0% done', + 'Checking {} ...'.format(test_file_d), + '2/4 files checked 0% done', + 'Checking {} ...'.format(test_file_b), + '3/4 files checked 0% done', + 'Checking {} ...'.format(test_file_a), + '4/4 files checked 0% done' + ] + assert stderr == '' diff --git a/test/helpers.cpp b/test/helpers.cpp index 1f58eeff8..b4c46a90d 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -75,7 +75,7 @@ ScopedFile::~ScopedFile() { // TODO: remove all files // TODO: simplify the function call // hack to be able to delete *.plist output files - std::map files; + std::list> files; const std::string res = FileLister::addFiles(files, mPath, {".plist"}, false, PathMatch({})); if (!res.empty()) { std::cout << "ScopedFile(" << mPath + ") - generating file list failed (" << res << ")" << std::endl; diff --git a/test/testfilelister.cpp b/test/testfilelister.cpp index 5bd84379d..60ebc78fc 100644 --- a/test/testfilelister.cpp +++ b/test/testfilelister.cpp @@ -21,8 +21,9 @@ #include "pathmatch.h" #include "fixture.h" +#include #include -#include +#include #include #include #include @@ -57,7 +58,7 @@ private: const std::string adddir = findBaseDir() + "."; // Recursively add add files.. - std::map files; + std::list> files; std::vector masks; PathMatch matcher(masks); std::string err = FileLister::recursiveAddFiles(files, adddir, matcher); @@ -73,19 +74,25 @@ private: const std::string dirprefix = adddir + "/"; #endif + const auto find_file = [&](const std::string& name) { + return std::find_if(files.cbegin(), files.cend(), [&name](const std::pair& entry) { + return entry.first == name; + }); + }; + // Make sure source files are added.. - ASSERT(files.find(dirprefix + "cli/main.cpp") != files.end()); - ASSERT(files.find(dirprefix + "lib/token.cpp") != files.end()); - ASSERT(files.find(dirprefix + "lib/tokenize.cpp") != files.end()); - ASSERT(files.find(dirprefix + "gui/main.cpp") != files.end()); - ASSERT(files.find(dirprefix + "test/testfilelister.cpp") != files.end()); + ASSERT(find_file(dirprefix + "cli/main.cpp") != files.end()); + ASSERT(find_file(dirprefix + "lib/token.cpp") != files.end()); + ASSERT(find_file(dirprefix + "lib/tokenize.cpp") != files.end()); + ASSERT(find_file(dirprefix + "gui/main.cpp") != files.end()); + ASSERT(find_file(dirprefix + "test/testfilelister.cpp") != files.end()); // Make sure headers are not added.. - ASSERT(files.find(dirprefix + "lib/tokenize.h") == files.end()); + ASSERT(find_file(dirprefix + "lib/tokenize.h") == files.end()); } void recursiveAddFilesEmptyPath() const { - std::map files; + std::list> files; const std::string err = FileLister::recursiveAddFiles(files, "", PathMatch({})); ASSERT_EQUALS("no path specified", err); } @@ -93,7 +100,7 @@ private: void excludeFile1() const { const std::string basedir = findBaseDir(); - std::map files; + std::list> files; std::vector ignored{"lib/token.cpp"}; PathMatch matcher(ignored); std::string err = FileLister::recursiveAddFiles(files, basedir + "lib/token.cpp", matcher); @@ -104,7 +111,7 @@ private: void excludeFile2() const { const std::string basedir = findBaseDir(); - std::map files; + std::list> files; std::vector ignored; PathMatch matcher(ignored); std::string err = FileLister::recursiveAddFiles(files, basedir + "lib/token.cpp", matcher); diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index 694835130..624a0246b 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -74,11 +74,11 @@ private: std::list fileSettings; - std::map filemap; + std::list> filelist; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp"; - filemap[f_s] = data.size(); + filelist.emplace_back(f_s, data.size()); if (useFS) { FileSettings fs; fs.filename = std::move(f_s); @@ -89,7 +89,7 @@ private: else { for (const auto& f : opt.filesList) { - filemap[f] = data.size(); + filelist.emplace_back(f, data.size()); if (useFS) { FileSettings fs; fs.filename = f; @@ -117,15 +117,15 @@ private: }; std::vector> scopedfiles; - scopedfiles.reserve(filemap.size()); - for (std::map::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) + scopedfiles.reserve(filelist.size()); + for (std::list>::const_iterator i = filelist.cbegin(); i != filelist.cend(); ++i) scopedfiles.emplace_back(new ScopedFile(i->first, data)); // clear files list so only fileSettings are used if (useFS) - filemap.clear(); + filelist.clear(); - ProcessExecutor executor(filemap, fileSettings, s, s.nomsg, *this, executeFn); + ProcessExecutor executor(filelist, fileSettings, s, s.nomsg, *this, executeFn); ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); ASSERT_EQUALS(opt.exe, exe); diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 201a657b0..96f98fdfe 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -79,11 +79,11 @@ private: std::list fileSettings; - std::map filemap; + std::list> filelist; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { std::string f_s = fprefix() + "_" + zpad3(i) + ".cpp"; - filemap[f_s] = data.size(); + filelist.emplace_back(f_s, data.size()); if (useFS) { FileSettings fs; fs.filename = std::move(f_s); @@ -94,7 +94,7 @@ private: else { for (const auto& f : opt.filesList) { - filemap[f] = data.size(); + filelist.emplace_back(f, data.size()); if (useFS) { FileSettings fs; fs.filename = f; @@ -123,15 +123,15 @@ private: cppcheck.settings() = s; std::vector> scopedfiles; - scopedfiles.reserve(filemap.size()); - for (std::map::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) + scopedfiles.reserve(filelist.size()); + for (std::list>::const_iterator i = filelist.cbegin(); i != filelist.cend(); ++i) scopedfiles.emplace_back(new ScopedFile(i->first, data)); // clear files list so only fileSettings are used if (useFS) - filemap.clear(); + filelist.clear(); - SingleExecutor executor(cppcheck, filemap, fileSettings, s, s.nomsg, *this); + SingleExecutor executor(cppcheck, filelist, fileSettings, s, s.nomsg, *this); ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); ASSERT_EQUALS(opt.exe, exe); diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 1fbbcf0a6..87aee88a0 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -193,9 +193,9 @@ private: errout.str(""); output.str(""); - std::map files; + std::list> files; for (std::map::const_iterator i = f.cbegin(); i != f.cend(); ++i) { - files[i->first] = i->second.size(); + files.emplace_back(i->first, i->second.size()); } CppCheck cppCheck(*this, true, nullptr); @@ -227,8 +227,8 @@ private: errout.str(""); output.str(""); - std::map files; - files["test.cpp"] = strlen(code); + std::list> files; + files.emplace_back("test.cpp", strlen(code)); Settings settings; settings.jobs = 2; @@ -242,7 +242,7 @@ private: ThreadExecutor executor(files, fileSettings, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand); std::vector> scopedfiles; scopedfiles.reserve(files.size()); - for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) + for (std::list>::const_iterator i = files.cbegin(); i != files.cend(); ++i) scopedfiles.emplace_back(new ScopedFile(i->first, code)); const unsigned int exitCode = executor.check(); @@ -257,8 +257,8 @@ private: errout.str(""); output.str(""); - std::map files; - files["test.cpp"] = strlen(code); + std::list> files; + files.emplace_back("test.cpp", strlen(code)); Settings settings; settings.jobs = 2; @@ -272,7 +272,7 @@ private: ProcessExecutor executor(files, fileSettings, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand); std::vector> scopedfiles; scopedfiles.reserve(files.size()); - for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) + for (std::list>::const_iterator i = files.cbegin(); i != files.cend(); ++i) scopedfiles.emplace_back(new ScopedFile(i->first, code)); const unsigned int exitCode = executor.check(); diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 7740c0151..fe666ca9d 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -74,11 +74,11 @@ private: std::list fileSettings; - std::map filemap; + std::list> filelist; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp"; - filemap[f_s] = data.size(); + filelist.emplace_back(f_s, data.size()); if (useFS) { FileSettings fs; fs.filename = std::move(f_s); @@ -89,7 +89,7 @@ private: else { for (const auto& f : opt.filesList) { - filemap[f] = data.size(); + filelist.emplace_back(f, data.size()); if (useFS) { FileSettings fs; fs.filename = f; @@ -118,15 +118,15 @@ private: }; std::vector> scopedfiles; - scopedfiles.reserve(filemap.size()); - for (std::map::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) + scopedfiles.reserve(filelist.size()); + for (std::list>::const_iterator i = filelist.cbegin(); i != filelist.cend(); ++i) scopedfiles.emplace_back(new ScopedFile(i->first, data)); // clear files list so only fileSettings are used if (useFS) - filemap.clear(); + filelist.clear(); - ThreadExecutor executor(filemap, fileSettings, s, s.nomsg, *this, executeFn); + ThreadExecutor executor(filelist, fileSettings, s, s.nomsg, *this, executeFn); ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); ASSERT_EQUALS(opt.exe, exe); diff --git a/tools/dmake.cpp b/tools/dmake.cpp index f36597c44..474a6b31d 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -24,6 +24,7 @@ #include // IWYU pragma: keep #include #include +#include #include #include #include @@ -139,16 +140,16 @@ static void compilefiles(std::ostream &fout, const std::vector &fil static std::string getCppFiles(std::vector &files, const std::string &path, bool recursive) { - std::map filemap; + std::list> filelist; const std::set extra; const std::vector masks; const PathMatch matcher(masks); - std::string err = FileLister::addFiles(filemap, path, extra, recursive, matcher); + std::string err = FileLister::addFiles(filelist, path, extra, recursive, matcher); if (!err.empty()) return err; // add *.cpp files to the "files" vector.. - for (const std::pair file : filemap) { + for (const std::pair file : filelist) { if (endsWith(file.first, ".cpp")) files.push_back(file.first); } diff --git a/tools/dmake.vcxproj b/tools/dmake.vcxproj index e6d7f14a6..4dfc06f01 100644 --- a/tools/dmake.vcxproj +++ b/tools/dmake.vcxproj @@ -70,7 +70,6 @@ $(OutDir)dmake.exe true Console - MachineX86 @@ -93,7 +92,6 @@ Console true true - MachineX86