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

refs #13532 - removed unnecessary temporary output files with --clang #7216

Merged
merged 5 commits into from
Jan 23, 2025
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
4 changes: 4 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mSettings.cppHeaderProbe = true;
}

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

// Show --debug output after the first simplifications
else if (std::strcmp(argv[i], "--debug") == 0 ||
std::strcmp(argv[i], "--debug-normal") == 0)
Expand Down
35 changes: 14 additions & 21 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,10 +658,10 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
mErrorLogger.reportOut(std::string("Checking ") + file.spath() + " ...", Color::FgGreen);

// TODO: get language from FileWithDetails object
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "");
const std::string clangcmd = analyzerInfo + ".clang-cmd";
const std::string clangStderr = analyzerInfo + ".clang-stderr";
const std::string clangAst = analyzerInfo + ".clang-ast";
std::string clangStderr;
if (!mSettings.buildDir.empty())
clangStderr = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "") + ".clang-stderr";

std::string exe = mSettings.clangExecutable;
#ifdef _WIN32
// append .exe if it is not a path
Expand All @@ -673,17 +673,17 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
const std::string args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " +
getClangFlags(Path::identify(file.spath(), mSettings.cppHeaderProbe)) +
file.spath();
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangcmd);
fout << exe << " " << args2 << " " << redirect2 << std::endl;
}
const std::string redirect2 = clangStderr.empty() ? "2>&1" : ("2> " + clangStderr);
if (mSettings.verbose && !mSettings.quiet) {
mErrorLogger.reportOut(exe + " " + args2);
}

std::string output2;
const int exitcode = mExecuteCommand(exe,split(args2),redirect2,output2);
if (mSettings.debugClangOutput) {
std::cout << output2 << std::endl;
}
// TODO: this might also fail if compiler errors are encountered - we should report them properly
if (exitcode != EXIT_SUCCESS) {
// TODO: report as proper error
std::cerr << "Failed to execute '" << exe << " " << args2 << " " << redirect2 << "' - (exitcode: " << exitcode << " / output: " << output2 << ")" << std::endl;
Expand All @@ -696,29 +696,22 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
return 0; // TODO: report as failure?
}

const auto reportError = [this](const ErrorMessage& errorMessage) {
mErrorLogger.reportErr(errorMessage);
};

// Ensure there are not syntax errors...
std::vector<ErrorMessage> compilerWarnings;
if (!mSettings.buildDir.empty()) {
if (!clangStderr.empty()) {
std::ifstream fin(clangStderr);
auto reportError = [this](const ErrorMessage& errorMessage) {
mErrorLogger.reportErr(errorMessage);
};
if (reportClangErrors(fin, reportError, compilerWarnings))
return 0; // TODO: report as failure?
} else {
std::istringstream istr(output2);
auto reportError = [this](const ErrorMessage& errorMessage) {
mErrorLogger.reportErr(errorMessage);
};
if (reportClangErrors(istr, reportError, compilerWarnings))
return 0; // TODO: report as failure?
}

if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangAst);
fout << output2 << std::endl;
}

try {
Tokenizer tokenizer(mSettings, mErrorLogger);
tokenizer.list.appendFileIfNew(file.spath());
Expand Down
3 changes: 3 additions & 0 deletions lib/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
/** @brief Are we running from DACA script? */
bool daca{};

/** @brief Is --debug-clang-output given? */
bool debugClangOutput{};

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

Expand Down
58 changes: 58 additions & 0 deletions test/cli/clang-import_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,61 @@ def test_cmd_std_c_enforce_alias_2(tmp_path): # #13128/#13129/#13130

def test_cmd_std_cpp_enforce_alias(tmp_path): # #13128/#13129/#13130
__test_cmd(tmp_path, 'test.c',['--language=c++', '--std=gnu99', '--std=gnu++11'], '-x c++ -std=gnu++11')


def test_debug_clang_output(tmp_path):
test_file = tmp_path / 'test.c'
with open(test_file, 'wt') as f:
f.write(
"""
void f() {}
""")

args = [
'-q',
'--clang',
'--debug-clang-output',
str(test_file)
]

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0, stderr if not stdout else stdout
assert stderr == ''
assert stdout.startswith('TranslationUnitDecl'), stdout
assert stdout.find(str(test_file)) != -1, stdout


def test_debug_clang_output_failure_exitcode(tmp_path):
# the given code will cause clang to fail with an exitcode
#
# Failed to execute 'clang -fsyntax-only -Xclang -ast-dump -fno-color-diagnostics -x c++ a.cpp 2>&1' - (exitcode: 1 / output: a.cpp:3:12: error: indirection requires pointer operand ('int' invalid)
# 3 | (void)(*0);
# | ^~
# 1 error generated.
# TranslationUnitDecl 0x6127d5d9d4e8 <<invalid sloc>> <invalid sloc>
# ...
test_file = tmp_path / 'test.c'
with open(test_file, 'wt') as f:
f.write(
"""void f()
{
(void)(*0);
}
""")

args = [
'-q',
'--clang',
'--debug-clang-output',
'--no-cppcheck-build-dir', # TODO: test without this?
str(test_file)
]

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0, stderr if not stdout else stdout
stderr_lines = stderr.splitlines()
assert len(stderr_lines) > 5, stderr_lines
assert (stderr_lines[0] ==
"Failed to execute 'clang -fsyntax-only -Xclang -ast-dump -fno-color-diagnostics -x c {} 2>&1' - (exitcode: 1 / output: {}:3:12: error: indirection requires pointer operand ('int' invalid)".format(test_file, test_file))
assert stdout.find('TranslationUnitDecl') != -1, stdout
assert stdout.find(str(test_file)) != -1, stdout
8 changes: 8 additions & 0 deletions test/testcmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(maxTemplateRecursion);
TEST_CASE(maxTemplateRecursionMissingCount);
TEST_CASE(emitDuplicates);
TEST_CASE(debugClangOutput);

TEST_CASE(ignorepaths1);
TEST_CASE(ignorepaths2);
Expand Down Expand Up @@ -2907,6 +2908,13 @@ class TestCmdlineParser : public TestFixture {
ASSERT_EQUALS(true, settings->emitDuplicates);
}

void debugClangOutput() {
REDIRECT;
const char * const argv[] = {"cppcheck", "--debug-clang-output", "file.cpp"};
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv));
ASSERT_EQUALS(true, settings->debugClangOutput);
}

void ignorepaths1() {
REDIRECT;
const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};
Expand Down
Loading