Skip to content

Commit 499f566

Browse files
authored
got rid of duplicated file/directory existence implementations / improved errorhandling and testing of FileLister (danmar#5350)
1 parent 0901e49 commit 499f566

12 files changed

Lines changed: 171 additions & 159 deletions

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h l
737737
test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/check.h lib/checkexceptionsafety.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
738738
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexceptionsafety.cpp
739739

740-
test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
740+
test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
741741
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfilelister.cpp
742742

743743
test/testfunctions.o: test/testfunctions.cpp lib/check.h lib/checkfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
@@ -779,7 +779,7 @@ test/testoptions.o: test/testoptions.cpp lib/check.h lib/color.h lib/config.h li
779779
test/testother.o: test/testother.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
780780
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testother.cpp
781781

782-
test/testpath.o: test/testpath.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
782+
test/testpath.o: test/testpath.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
783783
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpath.cpp
784784

785785
test/testpathmatch.o: test/testpathmatch.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h

cli/cmdlineparser.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
285285
if (endsWith(mSettings.buildDir, '/'))
286286
mSettings.buildDir.pop_back();
287287

288-
if (!Path::directoryExists(mSettings.buildDir)) {
288+
if (!Path::isDirectory(mSettings.buildDir)) {
289289
printError("Directory '" + mSettings.buildDir + "' specified by --cppcheck-build-dir argument has to be existent.");
290290
return false;
291291
}
@@ -452,7 +452,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
452452
path = Path::fromNativeSeparators(path);
453453
path = Path::simplifyPath(path);
454454

455-
if (FileLister::isDirectory(path)) {
455+
if (Path::isDirectory(path)) {
456456
// If directory name doesn't end with / or \, add it
457457
if (!endsWith(path, '/'))
458458
path += '/';
@@ -651,7 +651,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
651651
mSettings.plistOutput += '/';
652652

653653
const std::string plistOutput = Path::toNativeSeparators(mSettings.plistOutput);
654-
if (!FileLister::isDirectory(plistOutput)) {
654+
if (!Path::isDirectory(plistOutput)) {
655655
std::string message("plist folder does not exist: \"");
656656
message += plistOutput;
657657
message += "\".";

cli/cppcheckexecutor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ bool CppCheckExecutor::parseFromArgs(Settings &settings, int argc, const char* c
137137
iter != settings.includePaths.end();
138138
) {
139139
const std::string path(Path::toNativeSeparators(*iter));
140-
if (FileLister::isDirectory(path))
140+
if (Path::isDirectory(path))
141141
++iter;
142142
else {
143143
// If the include path is not found, warn user and remove the non-existing path from the list.

cli/filelister.cpp

Lines changed: 62 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <cstring>
2828
// fix NAME_MAX not found on macOS GCC8.1
2929
#include <climits>
30+
#include <memory>
3031

3132
#ifdef _WIN32
3233

@@ -41,30 +42,16 @@
4142
// When compiling Unicode targets WinAPI automatically uses *W Unicode versions
4243
// of called functions. Thus, we explicitly call *A versions of the functions.
4344

44-
static BOOL myIsDirectory(const std::string& path)
45-
{
46-
// See http://msdn.microsoft.com/en-us/library/bb773621(VS.85).aspx
47-
return PathIsDirectoryA(path.c_str());
48-
}
49-
50-
static HANDLE myFindFirstFile(const std::string& path, LPWIN32_FIND_DATAA findData)
51-
{
52-
HANDLE hFind = FindFirstFileA(path.c_str(), findData);
53-
return hFind;
54-
}
55-
56-
static BOOL myFileExists(const std::string& path)
57-
{
58-
return PathFileExistsA(path.c_str()) && !PathIsDirectoryA(path.c_str());
59-
}
60-
6145
std::string FileLister::recursiveAddFiles(std::map<std::string, std::size_t> &files, const std::string &path, const std::set<std::string> &extra, const PathMatch& ignored)
6246
{
6347
return addFiles(files, path, extra, true, ignored);
6448
}
6549

6650
std::string FileLister::addFiles(std::map<std::string, std::size_t> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored)
6751
{
52+
if (path.empty())
53+
return "no path specified";
54+
6855
const std::string cleanedPath = Path::toNativeSeparators(path);
6956

7057
// basedir is the base directory which is used to form pathnames.
@@ -75,7 +62,7 @@ std::string FileLister::addFiles(std::map<std::string, std::size_t> &files, cons
7562
std::string searchPattern = cleanedPath;
7663

7764
// The user wants to check all files in a dir
78-
const bool checkAllFilesInDir = (myIsDirectory(cleanedPath) != FALSE);
65+
const bool checkAllFilesInDir = Path::isDirectory(cleanedPath);
7966

8067
if (checkAllFilesInDir) {
8168
const char c = cleanedPath.back();
@@ -100,60 +87,63 @@ std::string FileLister::addFiles(std::map<std::string, std::size_t> &files, cons
10087
}
10188

10289
WIN32_FIND_DATAA ffd;
103-
HANDLE hFind = myFindFirstFile(searchPattern, &ffd);
104-
if (INVALID_HANDLE_VALUE == hFind)
105-
return "";
90+
HANDLE hFind = FindFirstFileA(searchPattern.c_str(), &ffd);
91+
if (INVALID_HANDLE_VALUE == hFind) {
92+
const DWORD err = GetLastError();
93+
if (err == ERROR_FILE_NOT_FOUND) {
94+
// no files matched
95+
return "";
96+
}
97+
return "finding files failed (error: " + std::to_string(err) + ")";
98+
}
99+
std::unique_ptr<void, decltype(&FindClose)> hFind_deleter(hFind, FindClose);
106100

107101
do {
108-
if (ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0')
109-
continue;
110-
111-
const char* ansiFfd = ffd.cFileName;
112-
if (std::strchr(ansiFfd,'?')) {
113-
ansiFfd = ffd.cAlternateFileName;
114-
}
102+
if (ffd.cFileName[0] != '.' && ffd.cFileName[0] != '\0')
103+
{
104+
const char* ansiFfd = ffd.cFileName;
105+
if (std::strchr(ansiFfd,'?')) {
106+
ansiFfd = ffd.cAlternateFileName;
107+
}
115108

116-
const std::string fname(basedir + ansiFfd);
109+
const std::string fname(basedir + ansiFfd);
117110

118-
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
119-
// File
120-
if ((!checkAllFilesInDir || Path::acceptFile(fname, extra)) && !ignored.match(fname)) {
121-
const std::string nativename = Path::fromNativeSeparators(fname);
111+
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
112+
// File
113+
if ((!checkAllFilesInDir || Path::acceptFile(fname, extra)) && !ignored.match(fname)) {
114+
const std::string nativename = Path::fromNativeSeparators(fname);
122115

123-
// Limitation: file sizes are assumed to fit in a 'size_t'
116+
// Limitation: file sizes are assumed to fit in a 'size_t'
124117
#ifdef _WIN64
125-
files[nativename] = (static_cast<std::size_t>(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow;
118+
files[nativename] = (static_cast<std::size_t>(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow;
126119
#else
127-
files[nativename] = ffd.nFileSizeLow;
120+
files[nativename] = ffd.nFileSizeLow;
128121
#endif
129-
}
130-
} else {
131-
// Directory
132-
if (recursive) {
133-
if (!ignored.match(fname)) {
134-
std::string err = FileLister::recursiveAddFiles(files, fname, extra, ignored);
135-
if (!err.empty())
136-
return err;
122+
}
123+
} else {
124+
// Directory
125+
if (recursive) {
126+
if (!ignored.match(fname)) {
127+
std::string err = FileLister::recursiveAddFiles(files, fname, extra, ignored);
128+
if (!err.empty())
129+
return err;
130+
}
137131
}
138132
}
139133
}
140-
} while (FindNextFileA(hFind, &ffd) != FALSE);
141134

142-
FindClose(hFind);
143-
return "";
144-
}
145-
146-
bool FileLister::isDirectory(const std::string &path)
147-
{
148-
return (myIsDirectory(path) != FALSE);
149-
}
135+
if (!FindNextFileA(hFind, &ffd)) {
136+
const DWORD err = GetLastError();
137+
// no more files matched
138+
if (err != ERROR_NO_MORE_FILES)
139+
return "failed to get next file (error: " + std::to_string(err) + ")";
140+
break;
141+
}
142+
} while (true);
150143

151-
bool FileLister::fileExists(const std::string &path)
152-
{
153-
return (myFileExists(path) != FALSE);
144+
return "";
154145
}
155146

156-
157147
#else
158148

159149
///////////////////////////////////////////////////////////////////////////////
@@ -189,8 +179,11 @@ static std::string addFiles2(std::map<std::string, std::size_t> &files,
189179
if (stat(path.c_str(), &file_stat) != -1) {
190180
if ((file_stat.st_mode & S_IFMT) == S_IFDIR) {
191181
DIR * dir = opendir(path.c_str());
192-
if (!dir)
193-
return "";
182+
if (!dir) {
183+
const int err = errno;
184+
return "could not open directory '" + path + "' (errno: " + std::to_string(err) + ")";
185+
}
186+
std::unique_ptr<DIR, decltype(&closedir)> dir_deleter(dir, closedir);
194187

195188
std::string new_path = path;
196189
new_path += '/';
@@ -204,15 +197,14 @@ static std::string addFiles2(std::map<std::string, std::size_t> &files,
204197
new_path += dir_result->d_name;
205198

206199
#if defined(_DIRENT_HAVE_D_TYPE) || defined(_BSD_SOURCE)
207-
const bool path_is_directory = (dir_result->d_type == DT_DIR || (dir_result->d_type == DT_UNKNOWN && FileLister::isDirectory(new_path)));
200+
const bool path_is_directory = (dir_result->d_type == DT_DIR || (dir_result->d_type == DT_UNKNOWN && Path::isDirectory(new_path)));
208201
#else
209-
const bool path_is_directory = FileLister::isDirectory(new_path);
202+
const bool path_is_directory = Path::isDirectory(new_path);
210203
#endif
211204
if (path_is_directory) {
212205
if (recursive && !ignored.match(new_path)) {
213206
std::string err = addFiles2(files, new_path, extra, recursive, ignored);
214207
if (!err.empty()) {
215-
closedir(dir);
216208
return err;
217209
}
218210
}
@@ -221,13 +213,12 @@ static std::string addFiles2(std::map<std::string, std::size_t> &files,
221213
if (stat(new_path.c_str(), &file_stat) != -1)
222214
files[new_path] = file_stat.st_size;
223215
else {
224-
closedir(dir);
225-
return "Can't stat " + new_path + " errno: " + std::to_string(errno);
216+
const int err = errno;
217+
return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")";
226218
}
227219
}
228220
}
229221
}
230-
closedir(dir);
231222
} else
232223
files[path] = file_stat.st_size;
233224
}
@@ -241,27 +232,14 @@ std::string FileLister::recursiveAddFiles(std::map<std::string, std::size_t> &fi
241232

242233
std::string FileLister::addFiles(std::map<std::string, std::size_t> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored)
243234
{
244-
if (!path.empty()) {
245-
std::string corrected_path = path;
246-
if (endsWith(corrected_path, '/'))
247-
corrected_path.erase(corrected_path.end() - 1);
235+
if (path.empty())
236+
return "no path specified";
248237

249-
return addFiles2(files, corrected_path, extra, recursive, ignored);
250-
}
251-
252-
return "";
253-
}
254-
255-
bool FileLister::isDirectory(const std::string &path)
256-
{
257-
struct stat file_stat;
258-
return (stat(path.c_str(), &file_stat) != -1 && (file_stat.st_mode & S_IFMT) == S_IFDIR);
259-
}
238+
std::string corrected_path = path;
239+
if (endsWith(corrected_path, '/'))
240+
corrected_path.erase(corrected_path.end() - 1);
260241

261-
bool FileLister::fileExists(const std::string &path)
262-
{
263-
struct stat file_stat;
264-
return (stat(path.c_str(), &file_stat) != -1 && (file_stat.st_mode & S_IFMT) == S_IFREG);
242+
return addFiles2(files, corrected_path, extra, recursive, ignored);
265243
}
266244

267245
#endif

cli/filelister.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,6 @@ class FileLister {
7373
* @return On success, an empty string is returned. On error, a error message is returned.
7474
*/
7575
static std::string addFiles(std::map<std::string, std::size_t> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored);
76-
77-
/**
78-
* @brief Is given path a directory?
79-
* @return returns true if the path is a directory
80-
*/
81-
static bool isDirectory(const std::string &path);
82-
83-
/**
84-
* @brief Check if the given path is a file and if it exists?
85-
* @return true if path points to file and the file exists.
86-
*/
87-
static bool fileExists(const std::string &path);
8876
};
8977

9078
/// @}

lib/cppcheck.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,19 @@ namespace {
9999
std::string runScript;
100100

101101
static std::string getFullPath(const std::string &fileName, const std::string &exename) {
102-
if (Path::fileExists(fileName))
102+
if (Path::isFile(fileName))
103103
return fileName;
104104

105105
const std::string exepath = Path::getPathFromFilename(exename);
106-
if (Path::fileExists(exepath + fileName))
106+
if (Path::isFile(exepath + fileName))
107107
return exepath + fileName;
108-
if (Path::fileExists(exepath + "addons/" + fileName))
108+
if (Path::isFile(exepath + "addons/" + fileName))
109109
return exepath + "addons/" + fileName;
110110

111111
#ifdef FILESDIR
112-
if (Path::fileExists(FILESDIR + ("/" + fileName)))
112+
if (Path::isFile(FILESDIR + ("/" + fileName)))
113113
return FILESDIR + ("/" + fileName);
114-
if (Path::fileExists(FILESDIR + ("/addons/" + fileName)))
114+
if (Path::isFile(FILESDIR + ("/addons/" + fileName)))
115115
return FILESDIR + ("/addons/" + fileName);
116116
#endif
117117
return "";

lib/importproject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,5 +1367,5 @@ void ImportProject::printError(const std::string &message)
13671367

13681368
bool ImportProject::sourceFileExists(const std::string &file)
13691369
{
1370-
return Path::fileExists(file);
1370+
return Path::isFile(file);
13711371
}

lib/path.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,17 +261,26 @@ std::string Path::stripDirectoryPart(const std::string &file)
261261
return file;
262262
}
263263

264-
bool Path::fileExists(const std::string &file)
264+
#ifdef _WIN32
265+
using mode_t = unsigned short;
266+
#endif
267+
268+
static mode_t file_type(const std::string &path)
265269
{
266-
std::ifstream f(file.c_str());
267-
return f.is_open();
270+
struct stat file_stat;
271+
if (stat(path.c_str(), &file_stat) == -1)
272+
return 0;
273+
return file_stat.st_mode & S_IFMT;
268274
}
269275

276+
bool Path::isFile(const std::string &path)
277+
{
278+
return file_type(path) == S_IFREG;
279+
}
270280

271-
bool Path::directoryExists(const std::string &path)
281+
bool Path::isDirectory(const std::string &path)
272282
{
273-
struct stat info;
274-
return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
283+
return file_type(path) == S_IFDIR;
275284
}
276285

277286
std::string Path::join(std::string path1, std::string path2) {

lib/path.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,18 @@ class CPPCHECKLIB Path {
181181
static std::string stripDirectoryPart(const std::string &file);
182182

183183
/**
184-
* @brief Checks if a File exists
185-
* @param file Path to be checked if it is a File
186-
* @return true if given path is a File
184+
* @brief Checks if given path is a file
185+
* @param path Path to be checked
186+
* @return true if given path is a file
187187
*/
188-
static bool fileExists(const std::string &file);
188+
static bool isFile(const std::string &path);
189189

190190
/**
191-
* @brief Checks if a directory exists
191+
* @brief Checks if a given path is a directory
192192
* @param path Path to be checked
193193
* @return true if given path is a directory
194194
*/
195-
static bool directoryExists(const std::string &path);
195+
static bool isDirectory(const std::string &path);
196196

197197
/**
198198
* join 2 paths with '/' separators

0 commit comments

Comments
 (0)