diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f75eba40ec30..4c9f1927230a 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -547,8 +547,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } - else if (std::strcmp(argv[i], "--cpp-probe") == 0) { - mSettings.cppProbe = true; + else if (std::strcmp(argv[i], "--cpp-header-probe") == 0) { + mSettings.cppHeaderProbe = true; } // Show --debug output after the first simplifications @@ -894,8 +894,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } - else if (std::strcmp(argv[i], "--no-cpp-probe") == 0) { - mSettings.cppProbe = false; + else if (std::strcmp(argv[i], "--no-cpp-header-probe") == 0) { + mSettings.cppHeaderProbe = false; } // Write results in file diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 1f02bf38fe6b..c5d65ca68c78 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -182,7 +182,7 @@ static void createDumpFile(const Settings& settings, case Standards::Language::None: { // TODO: error out on unknown language? - const Standards::Language lang = Path::identify(filename, settings.cppProbe); + const Standards::Language lang = Path::identify(filename, settings.cppHeaderProbe); if (lang == Standards::Language::CPP) language = " language=\"cpp\""; else if (lang == Standards::Language::C) @@ -420,7 +420,7 @@ unsigned int CppCheck::checkClang(const std::string &path) mErrorLogger.reportOut(std::string("Checking ") + path + " ...", Color::FgGreen); // TODO: this ignores the configured language - const bool isCpp = Path::identify(path, mSettings.cppProbe) == Standards::Language::CPP; + const bool isCpp = Path::identify(path, mSettings.cppHeaderProbe) == Standards::Language::CPP; const std::string langOpt = isCpp ? "-x c++" : "-x c"; const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, emptyString); const std::string clangcmd = analyzerInfo + ".clang-cmd"; diff --git a/lib/path.cpp b/lib/path.cpp index 84a28c9b49d6..dfeef2eec468 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -252,16 +251,23 @@ bool Path::isHeader(const std::string &path) static bool hasEmacsCppMarker(const char* path) { // TODO: identify is called three times for each file + // Preprocessor::loadFiles() -> createDUI() + // Preprocessor::preprocess() -> createDUI() + // TokenList::createTokens() -> TokenList::determineCppC() std::cout << path << '\n'; FILE *fp = fopen(path, "rt"); if (!fp) return false; - std::unique_ptr fp_deleter(fp, fclose); std::string buf(1024, '\0'); - // TODO: read first line only - if (fgets(const_cast(buf.data()), buf.size(), fp) == nullptr) - return false; // failed to read file + { + // TODO: read first line only + const char * const res = fgets(const_cast(buf.data()), buf.size(), fp); + fclose(fp); + fp = nullptr; + if (!res) + return false; // failed to read file + } // TODO: replace with regular expression const auto pos1 = buf.find("-*-"); if (pos1 == std::string::npos) @@ -301,7 +307,7 @@ static bool hasEmacsCppMarker(const char* path) return false; // marker is not a C++ one } -Standards::Language Path::identify(const std::string &path, bool cppProbe, bool *header) +Standards::Language Path::identify(const std::string &path, bool cppHeaderProbe, bool *header) { // cppcheck-suppress uninitvar - TODO: FP if (header) @@ -309,7 +315,7 @@ Standards::Language Path::identify(const std::string &path, bool cppProbe, bool std::string ext = getFilenameExtension(path); // standard library headers have no extension - if (cppProbe && ext.empty()) { + if (cppHeaderProbe && ext.empty()) { if (hasEmacsCppMarker(path.c_str())) { if (header) *header = true; @@ -326,7 +332,7 @@ Standards::Language Path::identify(const std::string &path, bool cppProbe, bool if (ext == ".h") { if (header) *header = true; - if (cppProbe && hasEmacsCppMarker(path.c_str())) + if (cppHeaderProbe && hasEmacsCppMarker(path.c_str())) return Standards::Language::CPP; return Standards::Language::C; } diff --git a/lib/path.h b/lib/path.h index a468134c8e34..3015c8da8899 100644 --- a/lib/path.h +++ b/lib/path.h @@ -187,11 +187,11 @@ class CPPCHECKLIB Path { /** * @brief Identify the language based on the file extension * @param path filename to check. path info is optional - * @param cppProbe check optional Emacs marker to idengtify headers as C++ + * @param cppHeaderProbe check optional Emacs marker to identify extension-less and *.h files as C++ * @param header if provided indicates if the file is a header * @return the language type */ - static Standards::Language identify(const std::string &path, bool cppProbe, bool *header = nullptr); + static Standards::Language identify(const std::string &path, bool cppHeaderProbe, bool *header = nullptr); /** * @brief Get filename without a directory path part. diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index c87898718ba7..bbd0f67ea573 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -684,7 +684,7 @@ static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cf dui.includes = mSettings.userIncludes; // --include // TODO: use mSettings.standards.stdValue instead // TODO: error out on unknown language? - const Standards::Language lang = Path::identify(filename, mSettings.cppProbe); + const Standards::Language lang = Path::identify(filename, mSettings.cppHeaderProbe); if (lang == Standards::Language::CPP) { dui.std = mSettings.standards.getCPP(); splitcfg(mSettings.platform.getLimitsDefines(Standards::getCPP(dui.std)), dui.defines, ""); diff --git a/lib/settings.h b/lib/settings.h index 3935a2f34970..2ec4df0453a0 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -167,8 +167,8 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** cppcheck.cfg: About text */ std::string cppcheckCfgAbout; - /** @brief check Emacs marker to detect header files as C++ */ - bool cppProbe{}; + /** @brief check Emacs marker to detect extension-less and *.h files as C++ */ + bool cppHeaderProbe{}; /** @brief Are we running from DACA script? */ bool daca{}; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index e900b3af528c..8f368b3157ff 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -96,7 +96,7 @@ void TokenList::determineCppC() // only try to determine if it wasn't enforced if (mLang == Standards::Language::None) { ASSERT_LANG(!getSourceFilePath().empty()); - mLang = Path::identify(getSourceFilePath(), mSettings ? mSettings->cppProbe : false); + mLang = Path::identify(getSourceFilePath(), mSettings ? mSettings->cppHeaderProbe : false); // TODO: cannot enable assert as this might occur for unknown extensions //ASSERT_LANG(mLang != Standards::Language::None); if (mLang == Standards::Language::None) { diff --git a/releasenotes.txt b/releasenotes.txt index a04d884e540b..f992096acd85 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -16,4 +16,5 @@ Deprecations: - Other: +- added command-line option `--cpp-header-probe` (and `--no-cpp-header-probe`) to probe headers and extension-less files for Emacs marker (see https://trac.cppcheck.net/ticket/10692 for more details) - diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 47b81d0d99d4..a922d0f4576f 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -1437,7 +1437,7 @@ def test_cpp_probe(tmpdir): 'class A {};' ]) - args = ['-q', '--template=simple', '--cpp-probe', test_file] + args = ['-q', '--template=simple', '--cpp-header-probe', test_file] err_lines = [ "{}:1:1: error: Code 'classA{{' is invalid C code. Use --std or --language to configure the language. [syntaxError]".format(test_file) ] @@ -1453,7 +1453,6 @@ def test_cpp_probe_2(tmpdir): 'class A {};' ]) - # TODO: the probing is performed twice - args = ['-q', '--template=simple', '--cpp-probe', test_file] + args = ['-q', '--template=simple', '--cpp-header-probe', test_file] assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=[]) diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 017ddb74c5a3..f544830ba6b0 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -387,10 +387,10 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(checkLevelNormal); TEST_CASE(checkLevelExhaustive); TEST_CASE(checkLevelUnknown); - TEST_CASE(cppProbe); - TEST_CASE(cppProbe2); - TEST_CASE(noCppProbe); - TEST_CASE(noCppProbe2); + TEST_CASE(cppHeaderProbe); + TEST_CASE(cppHeaderProbe2); + TEST_CASE(noCppHeaderProbe); + TEST_CASE(noCppHeaderProbe2); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -2607,32 +2607,32 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: unknown '--check-level' value 'default'.\n", logger->str()); } - void cppProbe() { + void cppHeaderProbe() { REDIRECT; - const char * const argv[] = {"cppcheck", "--cpp-probe", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--cpp-header-probe", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); - ASSERT_EQUALS(true, settings->cppProbe); + ASSERT_EQUALS(true, settings->cppHeaderProbe); } - void cppProbe2() { + void cppHeaderProbe2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--no-cpp-probe", "--cpp-probe", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--no-cpp-header-probe", "--cpp-header-probe", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(4, argv)); - ASSERT_EQUALS(true, settings->cppProbe); + ASSERT_EQUALS(true, settings->cppHeaderProbe); } - void noCppProbe() { + void noCppHeaderProbe() { REDIRECT; - const char * const argv[] = {"cppcheck", "--no-cpp-probe", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--no-cpp-header-probe", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); - ASSERT_EQUALS(false, settings->cppProbe); + ASSERT_EQUALS(false, settings->cppHeaderProbe); } - void noCppProbe2() { + void noCppHeaderProbe2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--cpp-probe", "--no-cpp-probe", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--cpp-header-probe", "--no-cpp-header-probe", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(4, argv)); - ASSERT_EQUALS(false, settings->cppProbe); + ASSERT_EQUALS(false, settings->cppHeaderProbe); } void ignorepaths1() {