Skip to content

Commit ce5690a

Browse files
authored
store language in FileWithDetails (danmar#7116)
1 parent 031aa17 commit ce5690a

15 files changed

+258
-43
lines changed

cli/cmdlineparser.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,39 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
214214

215215
mFileSettings.clear();
216216

217+
if (mSettings.enforcedLang != Standards::Language::None)
218+
{
219+
// apply enforced language
220+
for (auto& fs : fileSettings)
221+
{
222+
if (mSettings.library.markupFile(fs.filename()))
223+
continue;
224+
fs.file.setLang(mSettings.enforcedLang);
225+
}
226+
}
227+
else
228+
{
229+
// identify files
230+
for (auto& fs : fileSettings)
231+
{
232+
if (mSettings.library.markupFile(fs.filename()))
233+
continue;
234+
bool header = false;
235+
fs.file.setLang(Path::identify(fs.filename(), mSettings.cppHeaderProbe, &header));
236+
// unknown extensions default to C++
237+
if (!header && fs.file.lang() == Standards::Language::None)
238+
fs.file.setLang(Standards::Language::CPP);
239+
}
240+
}
241+
242+
// enforce the language since markup files are special and do not adhere to the enforced language
243+
for (auto& fs : fileSettings)
244+
{
245+
if (mSettings.library.markupFile(fs.filename())) {
246+
fs.file.setLang(Standards::Language::C);
247+
}
248+
}
249+
217250
// sort the markup last
218251
std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
219252
return !mSettings.library.markupFile(fs.filename()) || !mSettings.library.processMarkupAfterCode(fs.filename());
@@ -284,6 +317,41 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
284317
files = std::move(filesResolved);
285318
}
286319

320+
if (mSettings.enforcedLang != Standards::Language::None)
321+
{
322+
// apply enforced language
323+
for (auto& f : files)
324+
{
325+
if (mSettings.library.markupFile(f.path()))
326+
continue;
327+
f.setLang(mSettings.enforcedLang);
328+
}
329+
}
330+
else
331+
{
332+
// identify remaining files
333+
for (auto& f : files)
334+
{
335+
if (f.lang() != Standards::Language::None)
336+
continue;
337+
if (mSettings.library.markupFile(f.path()))
338+
continue;
339+
bool header = false;
340+
f.setLang(Path::identify(f.path(), mSettings.cppHeaderProbe, &header));
341+
// unknown extensions default to C++
342+
if (!header && f.lang() == Standards::Language::None)
343+
f.setLang(Standards::Language::CPP);
344+
}
345+
}
346+
347+
// enforce the language since markup files are special and do not adhere to the enforced language
348+
for (auto& f : files)
349+
{
350+
if (mSettings.library.markupFile(f.path())) {
351+
f.setLang(Standards::Language::C);
352+
}
353+
}
354+
287355
// sort the markup last
288356
std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
289357
return !mSettings.library.markupFile(entry.path()) || !mSettings.library.processMarkupAfterCode(entry.path());

cli/filelister.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ static std::string addFiles2(std::list<FileWithDetails>&files, const std::string
104104

105105
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
106106
// File
107-
if ((!checkAllFilesInDir || Path::acceptFile(fname, extra)) && !ignored.match(fname)) {
107+
Standards::Language lang = Standards::Language::None;
108+
if ((!checkAllFilesInDir || Path::acceptFile(fname, extra, &lang)) && !ignored.match(fname)) {
108109
std::string nativename = Path::fromNativeSeparators(fname);
109110

110111
// Limitation: file sizes are assumed to fit in a 'size_t'
@@ -114,7 +115,7 @@ static std::string addFiles2(std::list<FileWithDetails>&files, const std::string
114115
const std::size_t filesize = ffd.nFileSizeLow;
115116

116117
#endif
117-
files.emplace_back(std::move(nativename), filesize);
118+
files.emplace_back(std::move(nativename), lang, filesize);
118119
}
119120
} else {
120121
// Directory
@@ -192,7 +193,7 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
192193
return ""; // TODO: return error?
193194
if ((file_stat.st_mode & S_IFMT) != S_IFDIR)
194195
{
195-
files.emplace_back(path, file_stat.st_size);
196+
files.emplace_back(path, Standards::Language::None, file_stat.st_size);
196197
return "";
197198
}
198199

@@ -229,12 +230,13 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
229230
}
230231
}
231232
} else {
232-
if (Path::acceptFile(new_path, extra) && !ignored.match(new_path)) {
233+
Standards::Language lang = Standards::Language::None;
234+
if (Path::acceptFile(new_path, extra, &lang) && !ignored.match(new_path)) {
233235
if (stat(new_path.c_str(), &file_stat) == -1) {
234236
const int err = errno;
235237
return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")";
236238
}
237-
files.emplace_back(new_path, file_stat.st_size);
239+
files.emplace_back(new_path, lang, file_stat.st_size);
238240
}
239241
}
240242
}

gui/checkthread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void CheckThread::run()
139139
qDebug() << "Whole program analysis";
140140
std::list<FileWithDetails> files2;
141141
std::transform(mFiles.cbegin(), mFiles.cend(), std::back_inserter(files2), [&](const QString& file) {
142-
return FileWithDetails{file.toStdString(), 0};
142+
return FileWithDetails{file.toStdString(), Path::identify(file.toStdString(), cppcheck.settings().cppHeaderProbe), 0};
143143
});
144144
cppcheck.analyseWholeProgram(cppcheck.settings().buildDir, files2, {}, ctuInfo);
145145
mFiles.clear();

lib/filesettings.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "config.h"
2323
#include "path.h"
2424
#include "platform.h"
25+
#include "standards.h"
2526

2627
#include <list>
2728
#include <set>
@@ -33,12 +34,13 @@ class FileWithDetails
3334
{
3435
public:
3536
explicit FileWithDetails(std::string path)
36-
: FileWithDetails(std::move(path), 0)
37+
: FileWithDetails(std::move(path), Standards::Language::None, 0)
3738
{}
3839

39-
FileWithDetails(std::string path, std::size_t size)
40+
FileWithDetails(std::string path, Standards::Language lang, std::size_t size)
4041
: mPath(std::move(path))
4142
, mPathSimplified(Path::simplifyPath(mPath))
43+
, mLang(lang)
4244
, mSize(size)
4345
{
4446
if (mPath.empty())
@@ -59,9 +61,20 @@ class FileWithDetails
5961
{
6062
return mSize;
6163
}
64+
65+
void setLang(Standards::Language lang)
66+
{
67+
mLang = lang;
68+
}
69+
70+
Standards::Language lang() const
71+
{
72+
return mLang;
73+
}
6274
private:
6375
std::string mPath;
6476
std::string mPathSimplified;
77+
Standards::Language mLang = Standards::Language::None;
6578
std::size_t mSize;
6679
};
6780

@@ -71,8 +84,8 @@ struct CPPCHECKLIB FileSettings {
7184
: file(std::move(path))
7285
{}
7386

74-
FileSettings(std::string path, std::size_t size)
75-
: file(std::move(path), size)
87+
FileSettings(std::string path, Standards::Language lang, std::size_t size)
88+
: file(std::move(path), lang, size)
7689
{}
7790

7891
std::string cfg;

lib/path.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,13 @@ static const std::unordered_set<std::string> header_exts = {
216216
".h", ".hpp", ".h++", ".hxx", ".hh"
217217
};
218218

219-
bool Path::acceptFile(const std::string &path, const std::set<std::string> &extra)
219+
bool Path::acceptFile(const std::string &path, const std::set<std::string> &extra, Standards::Language* lang)
220220
{
221221
bool header = false;
222-
return (identify(path, false, &header) != Standards::Language::None && !header) || extra.find(getFilenameExtension(path)) != extra.end();
222+
Standards::Language l = identify(path, false, &header);
223+
if (lang)
224+
*lang = l;
225+
return (l != Standards::Language::None && !header) || extra.find(getFilenameExtension(path)) != extra.end();
223226
}
224227

225228
static bool hasEmacsCppMarker(const char* path)

lib/path.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,21 +137,23 @@ class CPPCHECKLIB Path {
137137
* @brief Check if the file extension indicates that it's a C/C++ source file.
138138
* Check if the file has source file extension: *.c;*.cpp;*.cxx;*.c++;*.cc;*.txx
139139
* @param filename filename to check. path info is optional
140+
* @param lang the detected language
140141
* @return true if the file extension indicates it should be checked
141142
*/
142-
static bool acceptFile(const std::string &filename) {
143+
static bool acceptFile(const std::string &filename, Standards::Language* lang = nullptr) {
143144
const std::set<std::string> extra;
144-
return acceptFile(filename, extra);
145+
return acceptFile(filename, extra, lang);
145146
}
146147

147148
/**
148149
* @brief Check if the file extension indicates that it's a C/C++ source file.
149150
* Check if the file has source file extension: *.c;*.cpp;*.cxx;*.c++;*.cc;*.txx
150151
* @param path filename to check. path info is optional
151-
* @param extra extra file extensions
152+
* @param extra extra file extensions
153+
* @param lang the detected language
152154
* @return true if the file extension indicates it should be checked
153155
*/
154-
static bool acceptFile(const std::string &path, const std::set<std::string> &extra);
156+
static bool acceptFile(const std::string &path, const std::set<std::string> &extra, Standards::Language* lang = nullptr);
155157

156158
/**
157159
* @brief Is filename a header based on file extension

test/cli/clang-import_test.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ def test_warning(tmpdir): # #12424
139139
assert stderr == ''
140140

141141

142-
def __test_cmd(tmp_path, file_name, extra_args, stdout_exp_1):
142+
def __test_cmd(tmp_path, file_name, extra_args, stdout_exp_1, content=''):
143143
test_file = tmp_path / file_name
144144
with open(test_file, 'wt') as f:
145-
f.write('')
145+
f.write(content)
146146

147147
args = [
148148
'--enable=information',
@@ -173,6 +173,21 @@ def test_cmd_cpp(tmp_path):
173173
__test_cmd(tmp_path, 'test.cpp', [], '-x c++')
174174

175175

176+
# files with unknown extensions are treated as C++
177+
@pytest.mark.xfail(strict=True)
178+
def test_cmd_unk(tmp_path):
179+
__test_cmd(tmp_path, 'test.cplusplus', [], '-x c++')
180+
181+
182+
# headers are treated as C by default
183+
def test_cmd_hdr(tmp_path):
184+
__test_cmd(tmp_path, 'test.h', [], '-x c')
185+
186+
187+
def test_cmd_hdr_probe(tmp_path):
188+
__test_cmd(tmp_path, 'test.h', ['--cpp-header-probe'], '-x c++', '// -*- C++ -*-')
189+
190+
176191
def test_cmd_inc(tmp_path):
177192
inc_path = tmp_path / 'inc'
178193
os.makedirs(inc_path)

test/testcmdlineparser.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ class TestCmdlineParser : public TestFixture {
430430
TEST_CASE(ignorefilepaths2);
431431
TEST_CASE(ignorefilepaths3);
432432

433+
TEST_CASE(nonexistentpath);
434+
433435
TEST_CASE(checkconfig);
434436
TEST_CASE(unknownParam);
435437

@@ -2955,6 +2957,13 @@ class TestCmdlineParser : public TestFixture {
29552957
ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]);
29562958
}
29572959

2960+
void nonexistentpath() {
2961+
REDIRECT;
2962+
const char * const argv[] = {"cppcheck", "file.cpp"};
2963+
ASSERT(!parser->fillSettingsFromArgs(2, argv));
2964+
ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\n", logger->str());
2965+
}
2966+
29582967
void checkconfig() {
29592968
REDIRECT;
29602969
const char * const argv[] = {"cppcheck", "--check-config", "file.cpp"};

test/testfilelister.cpp

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class TestFileLister : public TestFixture {
3939
TEST_CASE(recursiveAddFilesEmptyPath);
4040
TEST_CASE(excludeFile1);
4141
TEST_CASE(excludeFile2);
42+
TEST_CASE(addFiles);
4243
}
4344

4445
// TODO: generate file list instead
@@ -81,11 +82,25 @@ class TestFileLister : public TestFixture {
8182
};
8283

8384
// Make sure source files are added..
84-
ASSERT(find_file(dirprefix + "cli/main.cpp") != files.end());
85-
ASSERT(find_file(dirprefix + "lib/token.cpp") != files.end());
86-
ASSERT(find_file(dirprefix + "lib/tokenize.cpp") != files.end());
87-
ASSERT(find_file(dirprefix + "gui/main.cpp") != files.end());
88-
ASSERT(find_file(dirprefix + "test/testfilelister.cpp") != files.end());
85+
auto it = find_file(dirprefix + "cli/main.cpp");
86+
ASSERT(it != files.end());
87+
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());
88+
89+
it = find_file(dirprefix + "lib/token.cpp");
90+
ASSERT(it != files.end());
91+
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());
92+
93+
it = find_file(dirprefix + "lib/tokenize.cpp");
94+
ASSERT(it != files.end());
95+
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());
96+
97+
it = find_file(dirprefix + "gui/main.cpp");
98+
ASSERT(it != files.end());
99+
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());
100+
101+
it = find_file(dirprefix + "test/testfilelister.cpp");
102+
ASSERT(it != files.end());
103+
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());
89104

90105
// Make sure headers are not added..
91106
ASSERT(find_file(dirprefix + "lib/tokenize.h") == files.end());
@@ -120,7 +135,65 @@ class TestFileLister : public TestFixture {
120135
ASSERT_EQUALS(basedir + "lib/token.cpp", files.begin()->path());
121136
}
122137

138+
void addFiles() const {
139+
const std::string adddir = findBaseDir() + ".";
140+
141+
// TODO: on Windows the prefix is different from when a recursive a folder (see recursiveAddFiles test)
142+
const std::string dirprefix = adddir + "/";
143+
#ifdef _WIN32
144+
const std::string dirprefix_nat = Path::toNativeSeparators(dirprefix);
145+
#endif
146+
147+
std::list<FileWithDetails> files;
148+
149+
{
150+
const std::string addfile = Path::join(Path::join(adddir, "cli"), "main.cpp");
151+
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
152+
ASSERT_EQUALS("", err);
153+
}
154+
{
155+
const std::string addfile = Path::join(Path::join(adddir, "lib"), "token.cpp");
156+
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
157+
ASSERT_EQUALS("", err);
158+
}
159+
{
160+
const std::string addfile = Path::join(Path::join(adddir, "cli"), "token.cpp"); // does not exist
161+
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
162+
ASSERT_EQUALS("", err);
163+
}
164+
{
165+
const std::string addfile = Path::join(Path::join(adddir, "lib2"), "token.cpp"); // does not exist
166+
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
167+
#ifdef _WIN32
168+
// TODO: get rid of this error - caused by missing intermediate folder
169+
ASSERT_EQUALS("finding files failed. Search pattern: '" + dirprefix_nat + "lib2\\token.cpp'. (error: 3)", err);
170+
#else
171+
ASSERT_EQUALS("", err);
172+
#endif
173+
}
174+
{
175+
const std::string addfile = Path::join(Path::join(adddir, "lib"), "matchcompiler.h");
176+
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
177+
ASSERT_EQUALS("", err);
178+
}
179+
180+
ASSERT_EQUALS(3, files.size());
181+
auto it = files.cbegin();
182+
ASSERT_EQUALS(dirprefix + "cli/main.cpp", it->path());
183+
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "cli/main.cpp"), it->spath());
184+
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
185+
it++;
186+
ASSERT_EQUALS(dirprefix + "lib/token.cpp", it->path());
187+
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "lib/token.cpp"), it->spath());
188+
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
189+
it++;
190+
ASSERT_EQUALS(dirprefix + "lib/matchcompiler.h", it->path());
191+
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "lib/matchcompiler.h"), it->spath());
192+
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
193+
}
194+
123195
// TODO: test errors
196+
// TODO: test wildcards
124197
};
125198

126199
REGISTER_TEST(TestFileLister)

0 commit comments

Comments
 (0)