diff --git a/.github/workflows/CI-cygwin.yml b/.github/workflows/CI-cygwin.yml index c0ac55709..b640a38f4 100644 --- a/.github/workflows/CI-cygwin.yml +++ b/.github/workflows/CI-cygwin.yml @@ -43,7 +43,7 @@ jobs: - name: Extra test for misra run: | C:\tools\cygwin\bin\bash.exe -l -c cd %GITHUB_WORKSPACE%\addons\test - ..\..\cppcheck --dump --suppress=uninitvar --inline-suppr misra\misra-test.c --std=c89 --platform=unix64 && python3 ..\misra.py -verify misra\misra-test.c.dump + ..\..\cppcheck --dump -DDUMMY --suppress=uninitvar --inline-suppr misra\misra-test.c --std=c89 --platform=unix64 && python3 ..\misra.py -verify misra\misra-test.c.dump C:\tools\cygwin\bin\bash.exe -l -c cd %GITHUB_WORKSPACE% .\cppcheck --addon=misra --inline-suppr --enable=information --error-exitcode=1 addons\test\misra\misra-ctu-*-test.c diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 96b97179b..f32c0c50b 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -127,7 +127,7 @@ jobs: ./cppcheck --addon=threadsafety --std=c++03 addons/test/threadsafety ./cppcheck --addon=misra --inline-suppr --enable=information --error-exitcode=1 addons/test/misra/misra-ctu-*-test.c cd addons/test - ../../cppcheck --dump --suppress=uninitvar --inline-suppr misra/misra-test.c --std=c89 --platform=unix64 && python3 ../misra.py -verify misra/misra-test.c.dump + ../../cppcheck --dump -DDUMMY --suppress=uninitvar --inline-suppr misra/misra-test.c --std=c89 --platform=unix64 && python3 ../misra.py -verify misra/misra-test.c.dump - name: Build GUI on ubuntu if: contains(matrix.os, 'ubuntu') diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 4abd0dfcf..739815f83 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -137,5 +137,5 @@ jobs: run: | .\cppcheck.exe --addon=misra --inline-suppr --enable=information --error-exitcode=1 addons\test\misra\misra-ctu-*-test.c cd addons\test - ..\..\cppcheck.exe --dump --suppress=uninitvar --inline-suppr misra\misra-test.c --std=c89 --platform=unix64 && python3 ..\misra.py -verify misra\misra-test.c.dump + ..\..\cppcheck.exe --dump -DDUMMY --suppress=uninitvar --inline-suppr misra\misra-test.c --std=c89 --platform=unix64 && python3 ..\misra.py -verify misra\misra-test.c.dump diff --git a/.travis.yml b/.travis.yml index d22cfc4af..6a7951252 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,8 +73,8 @@ matrix: - cd addons/test # We'll force C89 standard to enable an additional verification for # rules 5.4 and 5.5 which have standard-dependent options. - - ${CPPCHECK} --dump --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.c - - ${CPPCHECK} --dump --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.h + - ${CPPCHECK} --dump -DDUMMY --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.c + - ${CPPCHECK} --dump -DDUMMY --suppress=uninitvar --suppress=uninitStructMember --std=c89 misra/misra-test.h - python3 ../misra.py -verify misra/misra-test.c.dump - ${CPPCHECK} --dump misra/misra-test.cpp - python3 ../misra.py -verify misra/misra-test.cpp.dump diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index c583d7d57..66f66a8dc 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -94,6 +94,29 @@ class MacroUsage: ) +class PreprocessorIfCondition: + """ + Information about #if/#elif conditions + """ + + file = None + linenr = None + column = None + E = None + result = None + + def __init__(self, element): + _load_location(self, element) + self.E = element.get('E') + self.result = int(element.get('result')) + + def __repr__(self): + attrs = ["file", "linenr", "column", "E", "result"] + return "{}({})".format( + "PreprocessorIfCondition", + ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs)) + ) + class ValueType: """ @@ -759,6 +782,7 @@ class Configuration: name Name of the configuration, "" for default directives List of Directive items macro_usage List of used macros + preprocessor_if_conditions List of preprocessor if conditions that was evaluated during preprocessing tokenlist List of Token items scopes List of Scope items functions List of Function items @@ -770,6 +794,7 @@ class Configuration: name = '' directives = [] macro_usage = [] + preprocessor_if_conditions = [] tokenlist = [] scopes = [] functions = [] @@ -782,6 +807,7 @@ class Configuration: self.name = name self.directives = [] self.macro_usage = [] + self.preprocessor_if_conditions = [] self.tokenlist = [] self.scopes = [] self.functions = [] @@ -1045,6 +1071,10 @@ class CppcheckData: elif node.tag == 'macro' and event == 'start': cfg.macro_usage.append(MacroUsage(node)) + # Preprocessor #if/#elif condition + elif node.tag == "if-cond" and event == 'start': + cfg.preprocessor_if_conditions.append(PreprocessorIfCondition(node)) + # Parse tokens elif node.tag == 'tokenlist' and event == 'start': continue diff --git a/addons/misra.py b/addons/misra.py index 061367695..28b879807 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -3209,6 +3209,12 @@ class MisraChecker: self.reportError(directive, 20, 7) break + def misra_20_8(self, cfg): + for cond in cfg.preprocessor_if_conditions: + #print(cond) + if cond.result and cond.result not in (0,1): + self.reportError(cond, 20, 8) + def misra_20_10(self, data): for directive in data.directives: d = Define(directive) @@ -3884,7 +3890,8 @@ class MisraChecker: self.executeCheck(2003, self.misra_20_3, cfg) self.executeCheck(2004, self.misra_20_4, cfg) self.executeCheck(2005, self.misra_20_5, cfg) - self.executeCheck(2006, self.misra_20_7, cfg) + self.executeCheck(2007, self.misra_20_7, cfg) + self.executeCheck(2008, self.misra_20_8, cfg) self.executeCheck(2010, self.misra_20_10, cfg) self.executeCheck(2013, self.misra_20_13, cfg) self.executeCheck(2014, self.misra_20_14, cfg) diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 7148c9f3f..c623b4697 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -1,6 +1,6 @@ // To test: // ~/cppcheck/cppcheck --dump misra/misra-test.h --std=c89 -// ~/cppcheck/cppcheck --dump --suppress=uninitvar --inline-suppr misra/misra-test.c --std=c89 --platform=unix64 && python3 ../misra.py -verify misra/misra-test.c.dump +// ~/cppcheck/cppcheck --dump -DDUMMY --suppress=uninitvar --inline-suppr misra/misra-test.c --std=c89 --platform=unix64 && python3 ../misra.py -verify misra/misra-test.c.dump #include "path\file.h" // 20.2 #include "file//.h" // 20.2 @@ -1558,6 +1558,9 @@ struct { int a; } struct_20_7_s; #define MUL(a ,b ) ( a * b ) // 20.7 +#if __LINE__ // 20.8 +#endif + #define M_20_10(a) (#a) // 20.10 #else1 // 20.13 diff --git a/addons/test/util.py b/addons/test/util.py index 21dd345bb..9413a2d0c 100644 --- a/addons/test/util.py +++ b/addons/test/util.py @@ -20,7 +20,7 @@ def find_cppcheck_binary(): def dump_create(fpath, *argv): cppcheck_binary = find_cppcheck_binary() - cmd = [cppcheck_binary, "--dump", "--quiet", fpath] + list(argv) + cmd = [cppcheck_binary, "--dump", "-DDUMMY", "--quiet", fpath] + list(argv) p = subprocess.Popen(cmd) p.communicate() if p.returncode != 0: diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 1ec1f75dd..c6be44a0f 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -738,9 +738,11 @@ simplecpp::TokenList Preprocessor::preprocess(const simplecpp::TokenList &tokens simplecpp::OutputList outputList; std::list macroUsage; + std::list ifCond; simplecpp::TokenList tokens2(files); - simplecpp::preprocess(tokens2, tokens1, files, mTokenLists, dui, &outputList, ¯oUsage); + simplecpp::preprocess(tokens2, tokens1, files, mTokenLists, dui, &outputList, ¯oUsage, &ifCond); mMacroUsage = macroUsage; + mIfCond = ifCond; handleErrors(outputList, throwError); @@ -800,6 +802,9 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string std::string ret; try { ret = getcode(tokens1, cfg, files, filedata.find("#file") != std::string::npos); + // Since "files" is a local variable the tracking info must be cleared.. + mMacroUsage.clear(); + mIfCond.clear(); } catch (const simplecpp::Output &) { ret.clear(); } @@ -961,7 +966,7 @@ void Preprocessor::dump(std::ostream &out) const if (!mMacroUsage.empty()) { out << " " << std::endl; for (const simplecpp::MacroUsage ¯oUsage: mMacroUsage) { - out << " " << std::endl; + << " is-known-value=\"" << (macroUsage.macroValueKnown ? "true" : "false") << "\"" + << "/>" << std::endl; } out << " " << std::endl; } + + if (!mIfCond.empty()) { + out << " " << std::endl; + for (const simplecpp::IfCond &ifCond: mIfCond) { + out << " " << std::endl; + } + out << " " << std::endl; + } } static const std::uint32_t crc32Table[] = { diff --git a/lib/preprocessor.h b/lib/preprocessor.h index 9b7d61301..9cf5504a2 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -223,7 +223,9 @@ private: /** filename for cpp/c file - useful when reporting errors */ std::string mFile0; + /** simplecpp tracking info */ std::list mMacroUsage; + std::list mIfCond; }; /// @}