diff --git a/.arclint b/.arclint --- a/.arclint +++ b/.arclint @@ -199,6 +199,13 @@ "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] + }, + "lint-cppcheck": { + "type": "lint-cppcheck", + "include": "(^src/.*\\.(h|c|cpp)$)", + "exclude": [ + "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)" + ] } } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,7 +131,7 @@ On Ubuntu (>= 18.04+updates) or Debian (>= 10): ``` -sudo apt-get install clang-format-8 clang-tidy-8 clang-tools-8 python-autopep8 flake8 php-codesniffer shellcheck +sudo apt-get install clang-format-8 clang-tidy-8 clang-tools-8 cppcheck python-autopep8 flake8 php-codesniffer shellcheck ``` If not available in the distribution, `clang-format-8` and `clang-tidy` can be diff --git a/arcanist/.phutil_module_cache b/arcanist/.phutil_module_cache --- a/arcanist/.phutil_module_cache +++ b/arcanist/.phutil_module_cache @@ -1 +1 @@ -{"__symbol_cache_version__":11,"9780c82e3cf1cde0c46662563f00444f":{"have":{"class":{"ArcanistBitcoinABCConfiguration":13}},"need":{"function":{"pht":242},"class":{"ArcanistConfiguration":53,"ArcanistLintWorkflow":1652},"class\/interface":{"ArcanistWorkflow":385,"ArcanistNoEffectException":1371}},"xmap":{"ArcanistBitcoinABCConfiguration":["ArcanistConfiguration"]}},"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"c9e595b23560664866ed4d6f2cbdb117":{"have":{"class":{"WhitespaceLinter":59}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":84,"ArcanistLintSeverity":545,"Filesystem":791}},"xmap":{"WhitespaceLinter":["ArcanistLinter"]}},"377eb7a4b08b962d2987624c96b99e5d":{"have":{"class":{"LocaleDependenceLinter":160}},"need":{"function":{"pht":5445},"class":{"ArcanistLinter":191,"ArcanistLintSeverity":5948,"Filesystem":6194}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}},"146347e1ef63e514a6634ada8de5b5c9":{"have":{"class":{"Qt5Linter":70}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":88,"ArcanistLintSeverity":609,"Filesystem":836}},"xmap":{"Qt5Linter":["ArcanistLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"4c4adcac26dddfa5e350b85a40097755":{"have":{"class":{"BashShebangLinter":82}},"need":{"function":{"pht":281},"class":{"ArcanistLinter":108,"ArcanistLintSeverity":597,"Filesystem":837}},"xmap":{"BashShebangLinter":["ArcanistLinter"]}},"c5bb63c97d3e04f6e0906d001bd3f8a2":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":921,"id":2137},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":2144,"ArcanistLintSeverity":646,"ArcanistLinter":2192}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"40c4038155ed0fcad9047f0f6efd62a1":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":368},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":721,"Filesystem":970}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"24f5f28d739120159e375f587d3a68e4":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2235},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2242,"Filesystem":2086,"ArcanistLinter":2349,"ArcanistLintSeverity":2427}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"85936cbfc0decd1aae05001717b359da":{"have":{"class":{"LogLinter":116}},"need":{"function":{"pht":297},"class":{"ArcanistLinter":134,"ArcanistLintSeverity":580,"Filesystem":875}},"xmap":{"LogLinter":["ArcanistLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"1dabcf7e27dc93d597d5cdc705efc279":{"have":{"class":{"PythonFileEncodingLinter":111}},"need":{"function":{"pht":321},"class":{"ArcanistLinter":144,"ArcanistLintSeverity":685,"Filesystem":990}},"xmap":{"PythonFileEncodingLinter":["ArcanistLinter"]}},"09a933fbbf135320585be52750d93831":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":280},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":589,"Filesystem":897}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"2f99c841a569f2029d13ea030dee007c":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2638},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2645,"Filesystem":776,"ArcanistLinter":2693,"ArcanistLintSeverity":2801}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"729e2f379c278258d8040e156ba9da29":{"have":{"class":{"ShellLocaleLinter":107}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":133,"ArcanistLintSeverity":734,"Filesystem":1044}},"xmap":{"ShellLocaleLinter":["ArcanistLinter"]}},"75579a609dd975aa0226add52700c622":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":307},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":662,"Filesystem":968}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"e4678dca551a849892aff414d3c4e24e":{"have":{"class":{"DoxygenLinter":91}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":113,"ArcanistLintSeverity":695,"Filesystem":943}},"xmap":{"DoxygenLinter":["ArcanistLinter"]}},"9c6223f7b59509a61f43d02842cc4bbc":{"have":{"class":{"CppVoidParameterLinter":119}},"need":{"function":{"pht":333},"class":{"ArcanistLinter":150,"ArcanistLintSeverity":648,"Filesystem":895}},"xmap":{"CppVoidParameterLinter":["ArcanistLinter"]}},"f7c056513a5968ea5076a3e75b36df61":{"have":{"class":{"ArcanistLandBotWorkflow":91}},"need":{"function":{"phutil_console_format":265,"pht":1577,"execx":2181},"class":{"ArcanistWorkflow":123,"ArcanistUsageException":2251}},"xmap":{"ArcanistLandBotWorkflow":["ArcanistWorkflow"]}}} \ No newline at end of file +{"__symbol_cache_version__":11,"f7c056513a5968ea5076a3e75b36df61":{"have":{"class":{"ArcanistLandBotWorkflow":91}},"need":{"function":{"phutil_console_format":265,"pht":1577,"execx":2181},"class":{"ArcanistWorkflow":123,"ArcanistUsageException":2251}},"xmap":{"ArcanistLandBotWorkflow":["ArcanistWorkflow"]}},"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"c9e595b23560664866ed4d6f2cbdb117":{"have":{"class":{"WhitespaceLinter":59}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":84,"ArcanistLintSeverity":545,"Filesystem":791}},"xmap":{"WhitespaceLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"e4678dca551a849892aff414d3c4e24e":{"have":{"class":{"DoxygenLinter":91}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":113,"ArcanistLintSeverity":695,"Filesystem":943}},"xmap":{"DoxygenLinter":["ArcanistLinter"]}},"4c4adcac26dddfa5e350b85a40097755":{"have":{"class":{"BashShebangLinter":82}},"need":{"function":{"pht":281},"class":{"ArcanistLinter":108,"ArcanistLintSeverity":597,"Filesystem":837}},"xmap":{"BashShebangLinter":["ArcanistLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"85936cbfc0decd1aae05001717b359da":{"have":{"class":{"LogLinter":116}},"need":{"function":{"pht":297},"class":{"ArcanistLinter":134,"ArcanistLintSeverity":580,"Filesystem":875}},"xmap":{"LogLinter":["ArcanistLinter"]}},"729e2f379c278258d8040e156ba9da29":{"have":{"class":{"ShellLocaleLinter":107}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":133,"ArcanistLintSeverity":734,"Filesystem":1044}},"xmap":{"ShellLocaleLinter":["ArcanistLinter"]}},"09a933fbbf135320585be52750d93831":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":280},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":589,"Filesystem":897}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"75579a609dd975aa0226add52700c622":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":307},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":662,"Filesystem":968}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"146347e1ef63e514a6634ada8de5b5c9":{"have":{"class":{"Qt5Linter":70}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":88,"ArcanistLintSeverity":609,"Filesystem":836}},"xmap":{"Qt5Linter":["ArcanistLinter"]}},"2f99c841a569f2029d13ea030dee007c":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2638},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2645,"Filesystem":776,"ArcanistLinter":2693,"ArcanistLintSeverity":2801}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"24f5f28d739120159e375f587d3a68e4":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2235},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2242,"Filesystem":2086,"ArcanistLinter":2349,"ArcanistLintSeverity":2427}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"c5bb63c97d3e04f6e0906d001bd3f8a2":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":921,"id":2137},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":2144,"ArcanistLintSeverity":646,"ArcanistLinter":2192}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"40c4038155ed0fcad9047f0f6efd62a1":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":368},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":721,"Filesystem":970}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"9c6223f7b59509a61f43d02842cc4bbc":{"have":{"class":{"CppVoidParameterLinter":119}},"need":{"function":{"pht":333},"class":{"ArcanistLinter":150,"ArcanistLintSeverity":648,"Filesystem":895}},"xmap":{"CppVoidParameterLinter":["ArcanistLinter"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"1dabcf7e27dc93d597d5cdc705efc279":{"have":{"class":{"PythonFileEncodingLinter":111}},"need":{"function":{"pht":321},"class":{"ArcanistLinter":144,"ArcanistLintSeverity":685,"Filesystem":990}},"xmap":{"PythonFileEncodingLinter":["ArcanistLinter"]}},"377eb7a4b08b962d2987624c96b99e5d":{"have":{"class":{"LocaleDependenceLinter":160}},"need":{"function":{"pht":5445},"class":{"ArcanistLinter":191,"ArcanistLintSeverity":5948,"Filesystem":6194}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"9780c82e3cf1cde0c46662563f00444f":{"have":{"class":{"ArcanistBitcoinABCConfiguration":13}},"need":{"function":{"pht":242},"class":{"ArcanistConfiguration":53,"ArcanistLintWorkflow":1652},"class\/interface":{"ArcanistWorkflow":385,"ArcanistNoEffectException":1371}},"xmap":{"ArcanistBitcoinABCConfiguration":["ArcanistConfiguration"]}},"2a7aaa0cc93af907a5e3272b7f186514":{"have":{"class":{"CppCheckLinter":92}},"need":{"function":{"pht":5078,"execx":5443},"class":{"ArcanistExternalLinter":115,"ArcanistLintMessage":7071,"ArcanistLintSeverity":7472}},"xmap":{"CppCheckLinter":["ArcanistExternalLinter"]}}} \ No newline at end of file diff --git a/arcanist/__phutil_library_map__.php b/arcanist/__phutil_library_map__.php --- a/arcanist/__phutil_library_map__.php +++ b/arcanist/__phutil_library_map__.php @@ -19,6 +19,7 @@ 'CheckDocLinter' => 'linter/CheckDocLinter.php', 'CheckRpcMappingsLinter' => 'linter/CheckRpcMappingsLinter.php', 'ClangFormatLinter' => 'linter/ClangFormatLinter.php', + 'CppCheckLinter' => 'linter/CppCheckLinter.php', 'CppVoidParameterLinter' => 'linter/CppVoidParameterLinter.php', 'DoxygenLinter' => 'linter/DoxygenLinter.php', 'ExtendedConfigurationDrivenLintEngine' => 'engine/ExtendedConfigurationDrivenLintEngine.php', @@ -53,6 +54,7 @@ 'CheckDocLinter' => 'GlobalExternalLinter', 'CheckRpcMappingsLinter' => 'GlobalExternalLinter', 'ClangFormatLinter' => 'ArcanistExternalLinter', + 'CppCheckLinter' => 'ArcanistExternalLinter', 'CppVoidParameterLinter' => 'ArcanistLinter', 'DoxygenLinter' => 'ArcanistLinter', 'ExtendedConfigurationDrivenLintEngine' => 'ArcanistLintEngine', diff --git a/arcanist/linter/CppCheckLinter.php b/arcanist/linter/CppCheckLinter.php new file mode 100644 --- /dev/null +++ b/arcanist/linter/CppCheckLinter.php @@ -0,0 +1,237 @@ + [messages]> to whitelist. */ + const CPPCHECK_IGNORED_WARNINGS = array( + "src/arith_uint256.h" => array( + "Class 'arith_uint256' has a constructor with 1 argument that is not explicit.", + "Class 'base_uint < 256 >' has a constructor with 1 argument that is not explicit.", + "Class 'base_uint' has a constructor with 1 argument that is not explicit.", + ), + "src/coins.h" => array( + "Class 'CCoinsViewBacked' has a constructor with 1 argument that is not explicit.", + "Class 'CCoinsViewCache' has a constructor with 1 argument that is not explicit.", + "Class 'CCoinsViewCursor' has a constructor with 1 argument that is not explicit.", + ), + "src/cuckoocache.h" => array( + "Struct 'KeyOnly' has a constructor with 1 argument that is not explicit.", + ), + "src/net.h" => array( + "Class 'CNetMessage' has a constructor with 1 argument that is not explicit.", + ), + "src/policy/feerate.h" => array( + "Class 'CFeeRate' has a constructor with 1 argument that is not explicit.", + ), + "src/prevector.h" => array( + "Class 'const_iterator' has a constructor with 1 argument that is not explicit.", + "Class 'const_reverse_iterator' has a constructor with 1 argument that is not explicit.", + "Class 'iterator' has a constructor with 1 argument that is not explicit.", + "Class 'reverse_iterator' has a constructor with 1 argument that is not explicit.", + ), + "src/primitives/block.h" => array( + "Class 'CBlock' has a constructor with 1 argument that is not explicit.", + ), + "src/primitives/transaction.h" => array( + "Class 'CTransaction' has a constructor with 1 argument that is not explicit.", + ), + "src/protocol.h" => array( + "Class 'CMessageHeader' has a constructor with 1 argument that is not explicit.", + ), + "src/qt/guiutil.h" => array( + "Class 'ItemDelegate' has a constructor with 1 argument that is not explicit.", + ), + "src/rpc/util.h" => array( + "Struct 'RPCResults' has a constructor with 1 argument that is not explicit.", + "Struct 'UniValueType' has a constructor with 1 argument that is not explicit.", + ), + "src/script/descriptor.cpp" => array( + "Class 'AddressDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'ComboDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'ConstPubkeyProvider' has a constructor with 1 argument that is not explicit.", + "Class 'PKDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'PKHDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'RawDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'SHDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'WPKHDescriptor' has a constructor with 1 argument that is not explicit.", + "Class 'WSHDescriptor' has a constructor with 1 argument that is not explicit.", + ), + "src/script/script.h" => array( + "Class 'CScript' has a constructor with 1 argument that is not explicit.", + ), + "src/script/standard.h" => array( + "Class 'CScriptID' has a constructor with 1 argument that is not explicit.", + ), + "src/support/allocators/secure.h" => array( + "Struct 'secure_allocator < char >' has a constructor with 1 argument that is not explicit.", + "Struct 'secure_allocator < RNGState >' has a constructor with 1 argument that is not explicit.", + "Struct 'secure_allocator < unsigned char >' has a constructor with 1 argument that is not explicit.", + ), + "src/support/allocators/zeroafterfree.h" => array( + "Struct 'zero_after_free_allocator < char >' has a constructor with 1 argument that is not explicit.", + ), + "src/test/checkqueue_tests.cpp" => array( + "Struct 'FailingCheck' has a constructor with 1 argument that is not explicit.", + "Struct 'MemoryCheck' has a constructor with 1 argument that is not explicit.", + "Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit.", + ), + "src/test/cuckoocache_tests.cpp" => array( + "Struct 'KeyType' has a constructor with 1 argument that is not explicit.", + "Struct 'TestMapElement' has a constructor with 1 argument that is not explicit." + ), + "src/wallet/db.h" => array( + "Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit.", + ), + ); + // phpcs:enable + + const CPPCHECK_OPTIONS = array( + '-j2', + '--enable=all', + '--language=c++', + '--std=c++14', + ); + + const CPPCHECK_DEFINITIONS = array( + '-D__cplusplus', + '-DCLIENT_VERSION_BUILD', + '-DCLIENT_VERSION_IS_RELEASE', + '-DCLIENT_VERSION_MAJOR', + '-DCLIENT_VERSION_MINOR', + '-DCLIENT_VERSION_REVISION', + '-DCOPYRIGHT_YEAR', + '-DDEBUG', + ); + + public function getInfoName() { + return 'cppcheck'; + } + + public function getInfoURI() { + return 'http://cppcheck.sourceforge.net'; + } + + public function getInfoDescription() { + return pht( + 'Use `%s` to perform static analysis on C/C++ code.', + 'cppcheck'); + } + + public function getLinterName() { + return 'lint-cppcheck'; + } + + public function getLinterConfigurationName() { + return 'lint-cppcheck'; + } + + public function getDefaultBinary() { + return 'cppcheck'; + } + + public function getVersion() { + list($stdout) = execx('%C --version', $this->getExecutableCommand()); + + $matches = array(); + $regex = '/^Cppcheck (?P\d+\.\d+)$/'; + if (preg_match($regex, $stdout, $matches)) { + return $matches['version']; + } + + return false; + } + + public function getInstallInstructions() { + return pht( + 'Install Cppcheck using `%s` or similar.', + 'apt-get install cppcheck'); + } + + protected function getDefaultFlags() { + return array_merge( + self::CPPCHECK_OPTIONS, + self::CPPCHECK_DEFINITIONS, + ); + } + + protected function getMandatoryFlags() { + return array( + '--quiet', + '--inline-suppr', + '--xml', + '--xml-version=2', + ); + } + + public function shouldExpectCommandErrors() { + return false; + } + + private function isWhitelisted($path, $errorId, $errorDescription) { + return !in_array($errorId, self::CPPCHECK_ENABLED_CHECKS) || + (array_key_exists($path, self::CPPCHECK_IGNORED_WARNINGS) && + in_array($errorDescription, self::CPPCHECK_IGNORED_WARNINGS[$path])); + } + + protected function parseLinterOutput($path, $err, $stdout, $stderr) { + $dom = new DOMDocument(); + $ok = @$dom->loadXML($stderr); + + if (!$ok) { + return false; + } + + $errors = $dom->getElementsByTagName('error'); + $messages = array(); + foreach ($errors as $error) { + foreach ($error->getElementsByTagName('location') as $location) { + $errorPath = Filesystem::readablePath( + $location->getAttribute('file'), $this->getProjectRoot()); + $errorId = $error->getAttribute('id'); + $errorDescription = $error->getAttribute('msg'); + + /* + * Only raise errors related to the actual source file. + * This prevents from printing tons of duplicates. + */ + if ($errorPath !== $path || $this->isWhitelisted( + $errorPath, $errorId, $errorDescription)) { + continue; + } + + $message = new ArcanistLintMessage(); + $message->setPath($errorPath); + $message->setLine($location->getAttribute('line')); + $message->setCode('CPPCHECK'); + $message->setName($errorId); + $message->setDescription($errorDescription); + + switch ($error->getAttribute('severity')) { + case 'error': + $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR); + break; + + default: + if ($error->getAttribute('inconclusive')) { + $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE); + } else { + $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING); + } + break; + } + + $messages[] = $message; + } + } + + return $messages; + } +} diff --git a/arcanist/phpcs.xml b/arcanist/phpcs.xml --- a/arcanist/phpcs.xml +++ b/arcanist/phpcs.xml @@ -27,6 +27,7 @@ + diff --git a/src/addrdb.h b/src/addrdb.h --- a/src/addrdb.h +++ b/src/addrdb.h @@ -81,7 +81,7 @@ const CChainParams &chainParams; public: - CAddrDB(const CChainParams &chainParams); + explicit CAddrDB(const CChainParams &chainParams); bool Write(const CAddrMan &addr); bool Read(CAddrMan &addr); bool Read(CAddrMan &addr, CDataStream &ssPeers); diff --git a/src/avalanche.h b/src/avalanche.h --- a/src/avalanche.h +++ b/src/avalanche.h @@ -90,7 +90,7 @@ std::array nodeFilter{{0, 0, 0, 0, 0, 0, 0, 0}}; public: - VoteRecord(bool accepted) : confidence(accepted) {} + explicit VoteRecord(bool accepted) : confidence(accepted) {} /** * Copy semantic @@ -331,7 +331,7 @@ EventLoop eventLoop; public: - AvalancheProcessor(CConnman *connmanIn); + explicit AvalancheProcessor(CConnman *connmanIn); ~AvalancheProcessor(); void setQueryTimeoutDuration(std::chrono::milliseconds d) { diff --git a/src/blockencodings.h b/src/blockencodings.h --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -162,7 +162,7 @@ // Dummy for deserialization CBlockHeaderAndShortTxIDs() {} - CBlockHeaderAndShortTxIDs(const CBlock &block); + explicit CBlockHeaderAndShortTxIDs(const CBlock &block); uint64_t GetShortID(const TxHash &txhash) const; diff --git a/src/cashaddrenc.cpp b/src/cashaddrenc.cpp --- a/src/cashaddrenc.cpp +++ b/src/cashaddrenc.cpp @@ -68,7 +68,7 @@ // Implements encoding of CTxDestination using cashaddr. class CashAddrEncoder : public boost::static_visitor { public: - CashAddrEncoder(const CChainParams &p) : params(p) {} + explicit CashAddrEncoder(const CChainParams &p) : params(p) {} std::string operator()(const PKHash &id) const { std::vector data = PackAddrData(id, PUBKEY_TYPE); diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -52,8 +52,8 @@ class DummyConfig : public Config { public: DummyConfig(); - DummyConfig(std::string net); - DummyConfig(std::unique_ptr chainParamsIn); + explicit DummyConfig(std::string net); + explicit DummyConfig(std::unique_ptr chainParamsIn); bool SetMaxBlockSize(uint64_t maxBlockSize) override { return false; } uint64_t GetMaxBlockSize() const override { return 0; } diff --git a/src/qt/test/addressbooktests.h b/src/qt/test/addressbooktests.h --- a/src/qt/test/addressbooktests.h +++ b/src/qt/test/addressbooktests.h @@ -10,7 +10,7 @@ class AddressBookTests : public QObject { public: - AddressBookTests(interfaces::Node &node) : m_node(node) {} + explicit AddressBookTests(interfaces::Node &node) : m_node(node) {} interfaces::Node &m_node; Q_OBJECT diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h --- a/src/qt/test/rpcnestedtests.h +++ b/src/qt/test/rpcnestedtests.h @@ -14,7 +14,7 @@ class RPCNestedTests : public QObject { public: - RPCNestedTests(interfaces::Node &node) : m_node(node) {} + explicit RPCNestedTests(interfaces::Node &node) : m_node(node) {} interfaces::Node &m_node; Q_OBJECT diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h --- a/src/qt/test/wallettests.h +++ b/src/qt/test/wallettests.h @@ -10,7 +10,7 @@ class WalletTests : public QObject { public: - WalletTests(interfaces::Node &node) : m_node(node) {} + explicit WalletTests(interfaces::Node &node) : m_node(node) {} interfaces::Node &m_node; Q_OBJECT diff --git a/src/rcu.h b/src/rcu.h --- a/src/rcu.h +++ b/src/rcu.h @@ -60,7 +60,7 @@ class RCULock : public boost::noncopyable { RCUInfos *infos; - RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); } + explicit RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); } friend class RCUInfos; public: diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -62,7 +62,7 @@ // BOOST_CHECK_EXCEPTION predicates to check the exception message class HasReason { public: - HasReason(const std::string &reason) : m_reason(reason) {} + explicit HasReason(const std::string &reason) : m_reason(reason) {} bool operator()(const std::exception &e) const { return std::string(e.what()).find(m_reason) != std::string::npos; }; diff --git a/src/test/rpc_server_tests.cpp b/src/test/rpc_server_tests.cpp --- a/src/test/rpc_server_tests.cpp +++ b/src/test/rpc_server_tests.cpp @@ -20,7 +20,7 @@ class ArgsTestRPCCommand : public RPCCommandWithArgsContext { public: - ArgsTestRPCCommand(const std::string &nameIn) + explicit ArgsTestRPCCommand(const std::string &nameIn) : RPCCommandWithArgsContext(nameIn) {} UniValue Execute(const UniValue &args) const override { @@ -59,7 +59,8 @@ class RequestContextRPCCommand : public RPCCommand { public: - RequestContextRPCCommand(const std::string &nameIn) : RPCCommand(nameIn) {} + explicit RequestContextRPCCommand(const std::string &nameIn) + : RPCCommand(nameIn) {} // Sanity check that Execute(JSONRPCRequest) is called correctly from // RPCServer diff --git a/src/test/sigcache_tests.cpp b/src/test/sigcache_tests.cpp --- a/src/test/sigcache_tests.cpp +++ b/src/test/sigcache_tests.cpp @@ -32,7 +32,7 @@ CachingTransactionSignatureChecker *pchecker; public: - TestCachingTransactionSignatureChecker( + explicit TestCachingTransactionSignatureChecker( CachingTransactionSignatureChecker &checkerarg) { pchecker = &checkerarg; } diff --git a/src/test/util/logging.h b/src/test/util/logging.h --- a/src/test/util/logging.h +++ b/src/test/util/logging.h @@ -20,7 +20,7 @@ void check_found(); public: - DebugLogHelper(std::string message); + explicit DebugLogHelper(std::string message); ~DebugLogHelper() { check_found(); } }; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -232,7 +232,7 @@ Optional> list_value; const char *error = nullptr; - Expect(util::SettingsValue s) : setting(std::move(s)) {} + explicit Expect(util::SettingsValue s) : setting(std::move(s)) {} Expect &DefaultString() { default_string = true; return *this; diff --git a/src/tinyformat.h b/src/tinyformat.h --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -167,7 +167,7 @@ class format_error : public std::runtime_error { public: - format_error(const std::string &what) : std::runtime_error(what) {} + explicit format_error(const std::string &what) : std::runtime_error(what) {} }; //------------------------------------------------------------------------------ diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -250,9 +250,10 @@ public: // Do full validation by default - BlockValidationOptions(const Config &config); - BlockValidationOptions(uint64_t _excessiveBlockSize, bool _checkPow = true, - bool _checkMerkleRoot = true) + explicit BlockValidationOptions(const Config &config); + explicit BlockValidationOptions(uint64_t _excessiveBlockSize, + bool _checkPow = true, + bool _checkMerkleRoot = true) : excessiveBlockSize(_excessiveBlockSize), checkPoW(_checkPow), checkMerkleRoot(_checkMerkleRoot) {} @@ -427,7 +428,7 @@ std::atomic remaining; public: - CheckInputsLimiter(int64_t limit) : remaining(limit) {} + explicit CheckInputsLimiter(int64_t limit) : remaining(limit) {} bool consume_and_check(int consumed) { auto newvalue = (remaining -= consumed);