Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added --debug-lookup to log library loading #6436

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/asan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
# TODO: disable all warnings
- name: CMake
run: |
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=Off -DWITH_QCHART=Off -DUSE_MATCHCOMPILER=Verify -DANALYZE_ADDRESS=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=Off -DWITH_QCHART=Off -DUSE_MATCHCOMPILER=Verify -DANALYZE_ADDRESS=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason to define FILESDIR here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Because it is set by default in CMake but not with make the tests will only work on either. For now I have omitted it from testing. This is one of the reasons an option to disable the usage of the built-in path would make sense.

env:
CC: clang-18
CXX: clang++-18
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tsan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:

- name: CMake
run: |
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=Off -DWITH_QCHART=Off -DUSE_MATCHCOMPILER=Verify -DANALYZE_THREAD=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=Off -DWITH_QCHART=Off -DUSE_MATCHCOMPILER=Verify -DANALYZE_THREAD=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
env:
CC: clang-18
CXX: clang++-18
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubsan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
# TODO: disable warnings
- name: CMake
run: |
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DUSE_MATCHCOMPILER=Verify -DANALYZE_UNDEFINED=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DUSE_MATCHCOMPILER=Verify -DANALYZE_UNDEFINED=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
env:
CC: clang-18
CXX: clang++-18
Expand Down
12 changes: 8 additions & 4 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
std::strcmp(argv[i], "--debug-normal") == 0)
mSettings.debugnormal = true;

// Show debug warnings for lookup for configuration files
else if (std::strcmp(argv[i], "--debug-lookup") == 0)
mSettings.debuglookup = true;

// Flag used for various purposes during debugging
else if (std::strcmp(argv[i], "--debug-simplified") == 0)
mSettings.debugSimplified = true;
Expand Down Expand Up @@ -1810,9 +1814,9 @@ bool CmdLineParser::isCppcheckPremium() const {
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
}

bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename, bool debug)
{
const Library::Error err = destination.load(basepath.c_str(), filename);
const Library::Error err = destination.load(basepath.c_str(), filename, debug);

if (err.errorcode == Library::ErrorCode::UNKNOWN_ELEMENT)
mLogger.printMessage("Found unknown elements in configuration file '" + std::string(filename) + "': " + err.reason); // TODO: print as errors
Expand Down Expand Up @@ -1859,7 +1863,7 @@ bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& base

bool CmdLineParser::loadLibraries(Settings& settings)
{
if (!tryLoadLibrary(settings.library, settings.exename, "std.cfg")) {
if (!tryLoadLibrary(settings.library, settings.exename, "std.cfg", settings.debuglookup)) {
const std::string msg("Failed to load std.cfg. Your Cppcheck installation is broken, please re-install.");
#ifdef FILESDIR
const std::string details("The Cppcheck binary was compiled with FILESDIR set to \""
Expand All @@ -1877,7 +1881,7 @@ bool CmdLineParser::loadLibraries(Settings& settings)

bool result = true;
for (const auto& lib : settings.libraries) {
if (!tryLoadLibrary(settings.library, settings.exename, lib.c_str())) {
if (!tryLoadLibrary(settings.library, settings.exename, lib.c_str(), settings.debuglookup)) {
result = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion cli/cmdlineparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class CmdLineParser {
* Tries to load a library and prints warning/error messages
* @return false, if an error occurred (except unknown XML elements)
*/
bool tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename);
bool tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename, bool debug);

/**
* @brief Load libraries
Expand Down
40 changes: 32 additions & 8 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,35 +836,50 @@ void MainWindow::addIncludeDirs(const QStringList &includeDirs, Settings &result
}
}

Library::Error MainWindow::loadLibrary(Library &library, const QString &filename)
Library::Error MainWindow::loadLibrary(Library &library, const QString &filename, bool debug)
{
Library::Error ret;

// Try to load the library from the project folder..
if (mProjectFile) {
QString path = QFileInfo(mProjectFile->getFilename()).canonicalPath();
ret = library.load(nullptr, (path+"/"+filename).toLatin1());
QString libpath = path+"/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
danmar marked this conversation as resolved.
Show resolved Hide resolved
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
}

// Try to load the library from the application folder..
const QString appPath = QFileInfo(QCoreApplication::applicationFilePath()).canonicalPath();
ret = library.load(nullptr, (appPath+"/"+filename).toLatin1());
QString libpath = appPath+"/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
ret = library.load(nullptr, (appPath+"/cfg/"+filename).toLatin1());
libpath = appPath+"/cfg/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;

#ifdef FILESDIR
// Try to load the library from FILESDIR/cfg..
const QString filesdir = FILESDIR;
if (!filesdir.isEmpty()) {
ret = library.load(nullptr, (filesdir+"/cfg/"+filename).toLatin1());
libpath = filesdir+"/cfg/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
ret = library.load(nullptr, (filesdir+filename).toLatin1());
libpath = filesdir+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
}
Expand All @@ -873,14 +888,23 @@ Library::Error MainWindow::loadLibrary(Library &library, const QString &filename
// Try to load the library from the cfg subfolder..
const QString datadir = getDataDir();
if (!datadir.isEmpty()) {
ret = library.load(nullptr, (datadir+"/"+filename).toLatin1());
libpath = datadir+"/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
ret = library.load(nullptr, (datadir+"/cfg/"+filename).toLatin1());
libpath = datadir+"/cfg/"+filename;
if (debug)
std::cout << "looking for library '" + libpath.toStdString() + "'" << std::endl;
ret = library.load(nullptr, libpath.toLatin1());
if (ret.errorcode != Library::ErrorCode::FILE_NOT_FOUND)
return ret;
}

if (debug)
std::cout << "library not found: '" + filename.toStdString() + "'" << std::endl;

return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ private slots:
* @param filename filename (no path)
* @return error code
*/
Library::Error loadLibrary(Library &library, const QString &filename);
Library::Error loadLibrary(Library &library, const QString &filename, bool debug = false);

/**
* @brief Tries to load library file, prints message on error
Expand Down
19 changes: 17 additions & 2 deletions lib/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <cctype>
#include <climits>
#include <cstring>
#include <iostream>
#include <list>
#include <memory>
#include <sstream>
Expand Down Expand Up @@ -65,9 +66,12 @@ static void gettokenlistfromvalid(const std::string& valid, bool cpp, TokenList&
}
}

Library::Error Library::load(const char exename[], const char path[])
Library::Error Library::load(const char exename[], const char path[], bool debug)
{
// TODO: remove handling of multiple libraries at once?
if (std::strchr(path,',') != nullptr) {
if (debug)
std::cout << "handling multiple libraries '" + std::string(path) + "'" << std::endl;
danmar marked this conversation as resolved.
Show resolved Hide resolved
std::string p(path);
for (;;) {
const std::string::size_type pos = p.find(',');
Expand All @@ -86,15 +90,21 @@ Library::Error Library::load(const char exename[], const char path[])
std::string absolute_path;
// open file..
tinyxml2::XMLDocument doc;
if (debug)
std::cout << "looking for library '" + std::string(path) + "'" << std::endl;
tinyxml2::XMLError error = doc.LoadFile(path);
if (error == tinyxml2::XML_ERROR_FILE_READ_ERROR && Path::getFilenameExtension(path).empty())
{
// Reading file failed, try again...
error = tinyxml2::XML_ERROR_FILE_NOT_FOUND;
}
if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
// failed to open file.. is there no extension?
std::string fullfilename(path);
if (Path::getFilenameExtension(fullfilename).empty()) {
fullfilename += ".cfg";
if (debug)
std::cout << "looking for library '" + std::string(fullfilename) + "'" << std::endl;
error = doc.LoadFile(fullfilename.c_str());
if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
absolute_path = Path::getAbsoluteFilePath(fullfilename);
Expand All @@ -116,6 +126,8 @@ Library::Error Library::load(const char exename[], const char path[])
cfgfolders.pop_back();
const char *sep = (!cfgfolder.empty() && endsWith(cfgfolder,'/') ? "" : "/");
const std::string filename(cfgfolder + sep + fullfilename);
if (debug)
std::cout << "looking for library '" + std::string(filename) + "'" << std::endl;
error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
absolute_path = Path::getAbsoluteFilePath(filename);
Expand All @@ -134,10 +146,13 @@ Library::Error Library::load(const char exename[], const char path[])
return Error(ErrorCode::OK); // ignore duplicates
}

if (debug)
std::cout << "library not found: '" + std::string(path) + "'" << std::endl;

if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
return Error(ErrorCode::FILE_NOT_FOUND);

doc.PrintError();
doc.PrintError(); // TODO: do not print stray messages
return Error(ErrorCode::BAD_XML);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class CPPCHECKLIB Library {
std::string reason;
};

Error load(const char exename[], const char path[]);
Error load(const char exename[], const char path[], bool debug = false);

struct AllocFunc {
int groupId;
Expand Down
3 changes: 3 additions & 0 deletions lib/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
/** @brief Are we running from DACA script? */
bool daca{};

/** @brief Internal: Is --debug-lookup given? */
bool debuglookup{};

/** @brief Is --debug-normal given? */
bool debugnormal{};

Expand Down
98 changes: 76 additions & 22 deletions test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,24 @@
import pytest
import json

from testutils import cppcheck, assert_cppcheck
from testutils import cppcheck, assert_cppcheck, cppcheck_ex


def __remove_std_lookup_log(l : list, exepath):
print(l)
l.remove("looking for library 'std.cfg'")
l.remove("looking for library '{}/std.cfg'".format(exepath))
l.remove("looking for library '{}/../cfg/std.cfg'".format(exepath))
l.remove("looking for library '{}/cfg/std.cfg'".format(exepath))
return l


def __remove_verbose_log(l : list):
l.remove('Defines:')
l.remove('Undefines:')
l.remove('Includes:')
l.remove('Platform:native')
return l


def test_missing_include(tmpdir): # #11283
Expand Down Expand Up @@ -452,13 +469,9 @@ class _clz {

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0
lines = stdout.splitlines()
lines = __remove_verbose_log(stdout.splitlines())
assert lines == [
'Checking {} ...'.format(test_file),
'Defines:',
'Undefines:',
'Includes:',
'Platform:native'
'Checking {} ...'.format(test_file)
]
lines = [line for line in stderr.splitlines() if line != '']
expect = [
Expand Down Expand Up @@ -585,13 +598,9 @@ def test_addon_namingng_config(tmpdir):
exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0

lines = stdout.splitlines()
lines = __remove_verbose_log(stdout.splitlines())
assert lines == [
'Checking {} ...'.format(test_file),
'Defines:',
'Undefines:',
'Includes:',
'Platform:native'
'Checking {} ...'.format(test_file)
]
lines = stderr.splitlines()
# ignore the first line, stating that the addon failed to run properly
Expand Down Expand Up @@ -725,13 +734,9 @@ def test_invalid_addon_py_verbose(tmpdir):

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0 # TODO: needs to be 1
lines = stdout.splitlines()
lines = __remove_verbose_log(stdout.splitlines())
assert lines == [
'Checking {} ...'.format(test_file),
'Defines:',
'Undefines:',
'Includes:',
'Platform:native'
'Checking {} ...'.format(test_file)
]
"""
/tmp/pytest-of-user/pytest-11/test_invalid_addon_py_20/file.cpp:0:0: error: Bailing out from analysis: Checking file failed: Failed to execute addon 'addon1' - exitcode is 1: python3 /home/user/CLionProjects/cppcheck/addons/runaddon.py /tmp/pytest-of-user/pytest-11/test_invalid_addon_py_20/addon1.py --cli /tmp/pytest-of-user/pytest-11/test_invalid_addon_py_20/file.cpp.24762.dump
Expand Down Expand Up @@ -1497,13 +1502,17 @@ def test_cpp_probe(tmpdir):
])

args = ['-q', '--template=simple', '--cpp-header-probe', '--verbose', test_file]
err_lines = [

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0, stdout
lines = stdout.splitlines()
assert lines == []
lines = stderr.splitlines()
assert lines == [
# TODO: fix that awkward format
"{}:1:1: error: Code 'classA{{' is invalid C code.: Use --std, -x or --language to enforce C++. Or --cpp-header-probe to identify C++ headers via the Emacs marker. [syntaxError]".format(test_file)
]

assert_cppcheck(args, ec_exp=0, err_exp=err_lines, out_exp=[])


def test_cpp_probe_2(tmpdir):
test_file = os.path.join(tmpdir, 'test.h')
Expand All @@ -1516,3 +1525,48 @@ def test_cpp_probe_2(tmpdir):
args = ['-q', '--template=simple', '--cpp-header-probe', test_file]

assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=[])


# TODO: test with FILESDIR
def test_lib_lookup(tmpdir):
test_file = os.path.join(tmpdir, 'test.c')
with open(test_file, 'wt'):
pass

exitcode, stdout, _, exe = cppcheck_ex(['--library=gnu', '--debug-lookup', test_file])
exepath = os.path.dirname(exe)
if sys.platform == 'win32':
exepath = exepath.replace('\\', '/')
assert exitcode == 0, stdout
lines = __remove_std_lookup_log(stdout.splitlines(), exepath)
assert lines == [
"looking for library 'gnu'",
"looking for library 'gnu.cfg'",
"looking for library '{}/gnu.cfg'".format(exepath),
"looking for library '{}/../cfg/gnu.cfg'".format(exepath),
"looking for library '{}/cfg/gnu.cfg'".format(exepath),
'Checking {} ...'.format(test_file)
]


# TODO: test with FILESDIR
def test_lib_lookup_notfound(tmpdir):
test_file = os.path.join(tmpdir, 'test.c')
with open(test_file, 'wt'):
pass

exitcode, stdout, _, exe = cppcheck_ex(['--library=none', '--debug-lookup', test_file])
exepath = os.path.dirname(exe)
if sys.platform == 'win32':
exepath = exepath.replace('\\', '/')
assert exitcode == 1, stdout
lines = __remove_std_lookup_log(stdout.splitlines(), exepath)
assert lines == [
"looking for library 'none'",
"looking for library 'none.cfg'",
"looking for library '{}/none.cfg'".format(exepath),
"looking for library '{}/../cfg/none.cfg'".format(exepath),
"looking for library '{}/cfg/none.cfg'".format(exepath),
"library not found: 'none'",
"cppcheck: Failed to load library configuration file 'none'. File not found"
]
Loading
Loading