Skip to content

Commit a1a415d

Browse files
authored
refs #13532 - removed unnecessary temporary output files with --clang (#7216)
1 parent 6b471b5 commit a1a415d

File tree

5 files changed

+87
-21
lines changed

5 files changed

+87
-21
lines changed

Diff for: cli/cmdlineparser.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
614614
mSettings.cppHeaderProbe = true;
615615
}
616616

617+
// Show debug warnings for lookup for configuration files
618+
else if (std::strcmp(argv[i], "--debug-clang-output") == 0)
619+
mSettings.debugClangOutput = true;
620+
617621
// Show --debug output after the first simplifications
618622
else if (std::strcmp(argv[i], "--debug") == 0 ||
619623
std::strcmp(argv[i], "--debug-normal") == 0)

Diff for: lib/cppcheck.cpp

+14-21
Original file line numberDiff line numberDiff line change
@@ -658,10 +658,10 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
658658
mErrorLogger.reportOut(std::string("Checking ") + file.spath() + " ...", Color::FgGreen);
659659

660660
// TODO: get language from FileWithDetails object
661-
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "");
662-
const std::string clangcmd = analyzerInfo + ".clang-cmd";
663-
const std::string clangStderr = analyzerInfo + ".clang-stderr";
664-
const std::string clangAst = analyzerInfo + ".clang-ast";
661+
std::string clangStderr;
662+
if (!mSettings.buildDir.empty())
663+
clangStderr = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, file.spath(), "") + ".clang-stderr";
664+
665665
std::string exe = mSettings.clangExecutable;
666666
#ifdef _WIN32
667667
// append .exe if it is not a path
@@ -673,17 +673,17 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file)
673673
const std::string args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " +
674674
getClangFlags(Path::identify(file.spath(), mSettings.cppHeaderProbe)) +
675675
file.spath();
676-
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
677-
if (!mSettings.buildDir.empty()) {
678-
std::ofstream fout(clangcmd);
679-
fout << exe << " " << args2 << " " << redirect2 << std::endl;
680-
}
676+
const std::string redirect2 = clangStderr.empty() ? "2>&1" : ("2> " + clangStderr);
681677
if (mSettings.verbose && !mSettings.quiet) {
682678
mErrorLogger.reportOut(exe + " " + args2);
683679
}
684680

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

699+
const auto reportError = [this](const ErrorMessage& errorMessage) {
700+
mErrorLogger.reportErr(errorMessage);
701+
};
702+
699703
// Ensure there are not syntax errors...
700704
std::vector<ErrorMessage> compilerWarnings;
701-
if (!mSettings.buildDir.empty()) {
705+
if (!clangStderr.empty()) {
702706
std::ifstream fin(clangStderr);
703-
auto reportError = [this](const ErrorMessage& errorMessage) {
704-
mErrorLogger.reportErr(errorMessage);
705-
};
706707
if (reportClangErrors(fin, reportError, compilerWarnings))
707708
return 0; // TODO: report as failure?
708709
} else {
709710
std::istringstream istr(output2);
710-
auto reportError = [this](const ErrorMessage& errorMessage) {
711-
mErrorLogger.reportErr(errorMessage);
712-
};
713711
if (reportClangErrors(istr, reportError, compilerWarnings))
714712
return 0; // TODO: report as failure?
715713
}
716714

717-
if (!mSettings.buildDir.empty()) {
718-
std::ofstream fout(clangAst);
719-
fout << output2 << std::endl;
720-
}
721-
722715
try {
723716
Tokenizer tokenizer(mSettings, mErrorLogger);
724717
tokenizer.list.appendFileIfNew(file.spath());

Diff for: lib/settings.h

+3
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
178178
/** @brief Are we running from DACA script? */
179179
bool daca{};
180180

181+
/** @brief Is --debug-clang-output given? */
182+
bool debugClangOutput{};
183+
181184
/** @brief Internal: Is --debug-lookup or --debug-lookup=all given? */
182185
bool debuglookup{};
183186

Diff for: test/cli/clang-import_test.py

+58
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,61 @@ def test_cmd_std_c_enforce_alias_2(tmp_path): # #13128/#13129/#13130
239239

240240
def test_cmd_std_cpp_enforce_alias(tmp_path): # #13128/#13129/#13130
241241
__test_cmd(tmp_path, 'test.c',['--language=c++', '--std=gnu99', '--std=gnu++11'], '-x c++ -std=gnu++11')
242+
243+
244+
def test_debug_clang_output(tmp_path):
245+
test_file = tmp_path / 'test.c'
246+
with open(test_file, 'wt') as f:
247+
f.write(
248+
"""
249+
void f() {}
250+
""")
251+
252+
args = [
253+
'-q',
254+
'--clang',
255+
'--debug-clang-output',
256+
str(test_file)
257+
]
258+
259+
exitcode, stdout, stderr = cppcheck(args)
260+
assert exitcode == 0, stderr if not stdout else stdout
261+
assert stderr == ''
262+
assert stdout.startswith('TranslationUnitDecl'), stdout
263+
assert stdout.find(str(test_file)) != -1, stdout
264+
265+
266+
def test_debug_clang_output_failure_exitcode(tmp_path):
267+
# the given code will cause clang to fail with an exitcode
268+
#
269+
# 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)
270+
# 3 | (void)(*0);
271+
# | ^~
272+
# 1 error generated.
273+
# TranslationUnitDecl 0x6127d5d9d4e8 <<invalid sloc>> <invalid sloc>
274+
# ...
275+
test_file = tmp_path / 'test.c'
276+
with open(test_file, 'wt') as f:
277+
f.write(
278+
"""void f()
279+
{
280+
(void)(*0);
281+
}
282+
""")
283+
284+
args = [
285+
'-q',
286+
'--clang',
287+
'--debug-clang-output',
288+
'--no-cppcheck-build-dir', # TODO: test without this?
289+
str(test_file)
290+
]
291+
292+
exitcode, stdout, stderr = cppcheck(args)
293+
assert exitcode == 0, stderr if not stdout else stdout
294+
stderr_lines = stderr.splitlines()
295+
assert len(stderr_lines) > 5, stderr_lines
296+
assert (stderr_lines[0] ==
297+
"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))
298+
assert stdout.find('TranslationUnitDecl') != -1, stdout
299+
assert stdout.find(str(test_file)) != -1, stdout

Diff for: test/testcmdlineparser.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ class TestCmdlineParser : public TestFixture {
422422
TEST_CASE(maxTemplateRecursion);
423423
TEST_CASE(maxTemplateRecursionMissingCount);
424424
TEST_CASE(emitDuplicates);
425+
TEST_CASE(debugClangOutput);
425426

426427
TEST_CASE(ignorepaths1);
427428
TEST_CASE(ignorepaths2);
@@ -2907,6 +2908,13 @@ class TestCmdlineParser : public TestFixture {
29072908
ASSERT_EQUALS(true, settings->emitDuplicates);
29082909
}
29092910

2911+
void debugClangOutput() {
2912+
REDIRECT;
2913+
const char * const argv[] = {"cppcheck", "--debug-clang-output", "file.cpp"};
2914+
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv));
2915+
ASSERT_EQUALS(true, settings->debugClangOutput);
2916+
}
2917+
29102918
void ignorepaths1() {
29112919
REDIRECT;
29122920
const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};

0 commit comments

Comments
 (0)