Skip to content

Commit

Permalink
store language in FileWithDetails
Browse files Browse the repository at this point in the history
  • Loading branch information
firewave committed Dec 21, 2024
1 parent 85eadd8 commit 3d4292d
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 41 deletions.
60 changes: 60 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,35 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])

mFileSettings.clear();

if (mSettings.enforcedLang != Standards::Language::None)
{
// apply enforced language
for (auto& fs : fileSettings)
{
if (mSettings.library.markupFile(fs.filename()))
continue;
fs.file.setLang(mSettings.enforcedLang);
}
}
else
{
// identify files
for (auto& fs : fileSettings)
{
if (mSettings.library.markupFile(fs.filename()))
continue;
fs.file.setLang(Path::identify(fs.filename(), mSettings.cppHeaderProbe));
}
}

// enforce the language since markup files are special and do not adhere to the enforced language
for (auto& fs : fileSettings)
{
if (mSettings.library.markupFile(fs.filename())) {
fs.file.setLang(Standards::Language::C);
}
}

// sort the markup last
std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
return !mSettings.library.markupFile(fs.filename()) || !mSettings.library.processMarkupAfterCode(fs.filename());
Expand Down Expand Up @@ -284,6 +313,37 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
files = std::move(filesResolved);
}

if (mSettings.enforcedLang != Standards::Language::None)
{
// apply enforced language
for (auto& f : files)
{
if (mSettings.library.markupFile(f.path()))
continue;
f.setLang(mSettings.enforcedLang);
}
}
else
{
// identify remaining files
for (auto& f : files)
{
if (f.lang() != Standards::Language::None)
continue;
if (mSettings.library.markupFile(f.path()))
continue;
f.setLang(Path::identify(f.path(), mSettings.cppHeaderProbe));
}
}

// enforce the language since markup files are special and do not adhere to the enforced language
for (auto& f : files)
{
if (mSettings.library.markupFile(f.path())) {
f.setLang(Standards::Language::C);
}
}

// sort the markup last
std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
return !mSettings.library.markupFile(entry.path()) || !mSettings.library.processMarkupAfterCode(entry.path());
Expand Down
12 changes: 7 additions & 5 deletions cli/filelister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ static std::string addFiles2(std::list<FileWithDetails>&files, const std::string

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

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

#endif
files.emplace_back(std::move(nativename), filesize);
files.emplace_back(std::move(nativename), lang, filesize);
}
} else {
// Directory
Expand Down Expand Up @@ -192,7 +193,7 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
return ""; // TODO: return error?
if ((file_stat.st_mode & S_IFMT) != S_IFDIR)
{
files.emplace_back(path, file_stat.st_size);
files.emplace_back(path, Standards::Language::None, file_stat.st_size);
return "";
}

Expand Down Expand Up @@ -229,12 +230,13 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
}
}
} else {
if (Path::acceptFile(new_path, extra) && !ignored.match(new_path)) {
Standards::Language lang = Standards::Language::None;
if (Path::acceptFile(new_path, extra, &lang) && !ignored.match(new_path)) {
if (stat(new_path.c_str(), &file_stat) == -1) {
const int err = errno;
return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")";
}
files.emplace_back(new_path, file_stat.st_size);
files.emplace_back(new_path, lang, file_stat.st_size);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion gui/checkthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ void CheckThread::run()
qDebug() << "Whole program analysis";
std::list<FileWithDetails> files2;
std::transform(mFiles.cbegin(), mFiles.cend(), std::back_inserter(files2), [&](const QString& file) {
return FileWithDetails{file.toStdString(), 0};
return FileWithDetails{file.toStdString(), Path::identify(file.toStdString(), cppcheck.settings().cppHeaderProbe), 0};
});
cppcheck.analyseWholeProgram(cppcheck.settings().buildDir, files2, {}, ctuInfo);
mFiles.clear();
Expand Down
21 changes: 17 additions & 4 deletions lib/filesettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "config.h"
#include "path.h"
#include "platform.h"
#include "standards.h"

#include <list>
#include <set>
Expand All @@ -33,12 +34,13 @@ class FileWithDetails
{
public:
explicit FileWithDetails(std::string path)
: FileWithDetails(std::move(path), 0)
: FileWithDetails(std::move(path), Standards::Language::None, 0)
{}

FileWithDetails(std::string path, std::size_t size)
FileWithDetails(std::string path, Standards::Language lang, std::size_t size)
: mPath(std::move(path))
, mPathSimplified(Path::simplifyPath(mPath))
, mLang(lang)
, mSize(size)
{
if (mPath.empty())
Expand All @@ -59,9 +61,20 @@ class FileWithDetails
{
return mSize;
}

void setLang(Standards::Language lang)
{
mLang = lang;
}

Standards::Language lang() const
{
return mLang;
}
private:
std::string mPath;
std::string mPathSimplified;
Standards::Language mLang = Standards::Language::None;
std::size_t mSize;
};

Expand All @@ -71,8 +84,8 @@ struct CPPCHECKLIB FileSettings {
: file(std::move(path))
{}

FileSettings(std::string path, std::size_t size)
: file(std::move(path), size)
FileSettings(std::string path, Standards::Language lang, std::size_t size)
: file(std::move(path), lang, size)
{}

std::string cfg;
Expand Down
7 changes: 5 additions & 2 deletions lib/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,13 @@ static const std::unordered_set<std::string> header_exts = {
".h", ".hpp", ".h++", ".hxx", ".hh"
};

bool Path::acceptFile(const std::string &path, const std::set<std::string> &extra)
bool Path::acceptFile(const std::string &path, const std::set<std::string> &extra, Standards::Language* lang)
{
bool header = false;
return (identify(path, false, &header) != Standards::Language::None && !header) || extra.find(getFilenameExtension(path)) != extra.end();
Standards::Language l = identify(path, false, &header);
if (lang)
*lang = l;
return (l != Standards::Language::None && !header) || extra.find(getFilenameExtension(path)) != extra.end();
}

static bool hasEmacsCppMarker(const char* path)
Expand Down
10 changes: 6 additions & 4 deletions lib/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,23 @@ class CPPCHECKLIB Path {
* @brief Check if the file extension indicates that it's a C/C++ source file.
* Check if the file has source file extension: *.c;*.cpp;*.cxx;*.c++;*.cc;*.txx
* @param filename filename to check. path info is optional
* @param lang the detected language
* @return true if the file extension indicates it should be checked
*/
static bool acceptFile(const std::string &filename) {
static bool acceptFile(const std::string &filename, Standards::Language* lang = nullptr) {
const std::set<std::string> extra;
return acceptFile(filename, extra);
return acceptFile(filename, extra, lang);
}

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

/**
* @brief Is filename a header based on file extension
Expand Down
9 changes: 9 additions & 0 deletions test/testcmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(ignorefilepaths2);
TEST_CASE(ignorefilepaths3);

TEST_CASE(nonexistentpath);

TEST_CASE(checkconfig);
TEST_CASE(unknownParam);

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

void nonexistentpath() {
REDIRECT;
const char * const argv[] = {"cppcheck", "file.cpp"};
ASSERT(!parser->fillSettingsFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\n", logger->str());
}

void checkconfig() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--check-config", "file.cpp"};
Expand Down
81 changes: 76 additions & 5 deletions test/testfilelister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class TestFileLister : public TestFixture {
TEST_CASE(recursiveAddFilesEmptyPath);
TEST_CASE(excludeFile1);
TEST_CASE(excludeFile2);
TEST_CASE(addFiles);
}

// TODO: generate file list instead
Expand Down Expand Up @@ -81,11 +82,25 @@ class TestFileLister : public TestFixture {
};

// Make sure source files are added..
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());
auto it = find_file(dirprefix + "cli/main.cpp");
ASSERT(it != files.end());
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());

it = find_file(dirprefix + "lib/token.cpp");
ASSERT(it != files.end());
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());

it = find_file(dirprefix + "lib/tokenize.cpp");
ASSERT(it != files.end());
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());

it = find_file(dirprefix + "gui/main.cpp");
ASSERT(it != files.end());
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());

it = find_file(dirprefix + "test/testfilelister.cpp");
ASSERT(it != files.end());
ASSERT_EQUALS_ENUM(Standards::Language::CPP, it->lang());

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

void addFiles() const {
const std::string adddir = findBaseDir() + ".";

// TODO: on Windows the prefix is different from when a recursive a folder (see recursiveAddFiles test)
const std::string dirprefix = adddir + "/";
const std::string dirprefix_nat = Path::toNativeSeparators(dirprefix);

std::list<FileWithDetails> files;

{
const std::string addfile = Path::join(Path::join(adddir, "cli"), "main.cpp");
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
ASSERT_EQUALS("", err);
}
{
const std::string addfile = Path::join(Path::join(adddir, "lib"), "token.cpp");
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
ASSERT_EQUALS("", err);
}
{
const std::string addfile = Path::join(Path::join(adddir, "cli"), "token.cpp"); // does not exist
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
ASSERT_EQUALS("", err);
}
{
const std::string addfile = Path::join(Path::join(adddir, "lib2"), "token.cpp"); // does not exist
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
#ifdef _WIN32
// TODO: get rid of this error - caused by missing intermediate folder
ASSERT_EQUALS("finding files failed. Search pattern: '" + dirprefix_nat + "lib2\\token.cpp'. (error: 3)", err);
#else
ASSERT_EQUALS("", err);
#endif
}
{
const std::string addfile = Path::join(Path::join(adddir, "lib"), "matchcompiler.h");
const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({}));
ASSERT_EQUALS("", err);
}

ASSERT_EQUALS(3, files.size());
auto it = files.cbegin();
ASSERT_EQUALS(dirprefix + "cli/main.cpp", it->path());
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "cli/main.cpp"), it->spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
it++;
ASSERT_EQUALS(dirprefix + "lib/token.cpp", it->path());
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "lib/token.cpp"), it->spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
it++;
ASSERT_EQUALS(dirprefix + "lib/matchcompiler.h", it->path());
ASSERT_EQUALS(Path::simplifyPath(dirprefix + "lib/matchcompiler.h"), it->spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, it->lang());
}

// TODO: test errors
// TODO: test wildcards
};

REGISTER_TEST(TestFileLister)
8 changes: 7 additions & 1 deletion test/testfilesettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,42 @@ class TestFileSettings : public TestFixture {
const FileWithDetails p{"file.cpp"};
ASSERT_EQUALS("file.cpp", p.path());
ASSERT_EQUALS("file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, p.lang());
ASSERT_EQUALS(0, p.size());
}
{
const FileWithDetails p{"file.cpp", 123};
const FileWithDetails p{"file.cpp", Standards::Language::C, 123};
ASSERT_EQUALS("file.cpp", p.path());
ASSERT_EQUALS("file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::C, p.lang());
ASSERT_EQUALS(123, p.size());
}
{
const FileWithDetails p{"in/file.cpp"};
ASSERT_EQUALS("in/file.cpp", p.path());
ASSERT_EQUALS("in/file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, p.lang());
ASSERT_EQUALS(0, p.size());
}
{
const FileWithDetails p{"in\\file.cpp"};
ASSERT_EQUALS("in\\file.cpp", p.path());
ASSERT_EQUALS("in/file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, p.lang());
ASSERT_EQUALS(0, p.size());
}
{
const FileWithDetails p{"in/../file.cpp"};
ASSERT_EQUALS("in/../file.cpp", p.path());
ASSERT_EQUALS("file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, p.lang());
ASSERT_EQUALS(0, p.size());
}
{
const FileWithDetails p{"in\\..\\file.cpp"};
ASSERT_EQUALS("in\\..\\file.cpp", p.path());
ASSERT_EQUALS("file.cpp", p.spath());
ASSERT_EQUALS_ENUM(Standards::Language::None, p.lang());
ASSERT_EQUALS(0, p.size());
}
}
Expand Down
Loading

0 comments on commit 3d4292d

Please sign in to comment.