diff --git a/.arclint b/.arclint index fea307a14..ba251eae6 100644 --- a/.arclint +++ b/.arclint @@ -1,64 +1,60 @@ { "linters": { "generated": { "type": "generated" }, "clang-format": { "type": "clang-format", "version": "7.0", "bin": ["clang-format-7", "clang-format"], "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ] }, "autopep8": { "type": "autopep8", "version": ">=1.3.4", "include": "(\\.py$)" }, "flake8": { "type": "flake8", "include": "(\\.py$)", "flags": [ "--select=F401,F403,F405" ] }, "lint-format-strings": { "type": "script-and-regex", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)" ], "script-and-regex.script": "test/lint/lint-format-strings.sh", "script-and-regex.regex": "/^(?P.+): (?P.+:.+)$/m" }, "check-doc": { "type": "check-doc", "include": "(^src/.*\\.(h|c|cpp)$)" }, "lint-tests": { "type": "lint-tests", "include": "(^src/(rpc/|wallet/)?test/.*\\.(cpp)$)" }, "lint-python-format": { "type": "lint-python-format", "include": "(\\.py$)", "exclude": [ "(^test/lint/lint-python-format\\.py$)" ] }, - "lint-locale-dependence": { - "type": "lint-locale-dependence", - "include": "(^src/.*\\.(h|cpp)$)" - }, "phpcs": { "type": "phpcs", "include": "(\\.php$)", "exclude": [ "(^arcanist/__phutil_library_.+\\.php$)" ], "phpcs.standard": "arcanist/linter/phpcs_ruleset.xml" } } } diff --git a/arcanist/.phutil_module_cache b/arcanist/.phutil_module_cache index 221d6f0b3..ff60f64e1 100644 --- a/arcanist/.phutil_module_cache +++ b/arcanist/.phutil_module_cache @@ -1 +1 @@ -{"__symbol_cache_version__":11,"d60c8224f471e0ecddc2a6f3c6839cd1":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"id":1317},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1324,"Filesystem":1168,"ArcanistLinter":1431,"ArcanistLintSeverity":1509}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"213c3145da34ed6dfc0d70d628a2a086":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":323,"id":1868},"class":{"ArcanistExternalLinter":129,"ArcanistLintMessage":1875,"Filesystem":737,"ArcanistLinter":1923,"ArcanistLintSeverity":2009}},"xmap":{"CheckDocLinter":["ArcanistExternalLinter"]}},"7bab1f879b8a86dd9977b8c0d075935f":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":787,"id":1664},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":1671,"Filesystem":1515,"ArcanistLinter":1778,"ArcanistLintSeverity":1856}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"ea2beb1668dfbdd87488f18fbb20178f":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2676},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2683,"Filesystem":791,"ArcanistLinter":2731,"ArcanistLintSeverity":2839}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"d8eaa2e7c86750dc3ee35036b5fd8bfc":{"have":{"class":{"LocaleDependenceLinter":137}},"need":{"function":{"pht":375,"id":2052},"class":{"ArcanistExternalLinter":168,"ArcanistLintMessage":2059,"Filesystem":816,"ArcanistLinter":2107,"ArcanistLintSeverity":2227}},"xmap":{"LocaleDependenceLinter":["ArcanistExternalLinter"]}},"e3132d407656d565ce80d359f4f0fe5f":{"have":{"class":{"PythonFormatLinter":124}},"need":{"function":{"pht":354,"id":1845},"class":{"ArcanistExternalLinter":151,"ArcanistLintMessage":1852,"Filesystem":777,"ArcanistLinter":1977,"ArcanistLintSeverity":2060}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}}} \ No newline at end of file +{"__symbol_cache_version__":11,"d60c8224f471e0ecddc2a6f3c6839cd1":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"id":1317},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1324,"Filesystem":1168,"ArcanistLinter":1431,"ArcanistLintSeverity":1509}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"213c3145da34ed6dfc0d70d628a2a086":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":323,"id":1868},"class":{"ArcanistExternalLinter":129,"ArcanistLintMessage":1875,"Filesystem":737,"ArcanistLinter":1923,"ArcanistLintSeverity":2009}},"xmap":{"CheckDocLinter":["ArcanistExternalLinter"]}},"7bab1f879b8a86dd9977b8c0d075935f":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":787,"id":1664},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":1671,"Filesystem":1515,"ArcanistLinter":1778,"ArcanistLintSeverity":1856}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"0e068a1116ed03e86a2388020a821983":{"have":{"class":{"PythonFormatLinter":75}},"need":{"function":{"pht":305,"id":1614},"class":{"ArcanistExternalLinter":102,"ArcanistLintMessage":1621,"Filesystem":733,"ArcanistLinter":1752,"ArcanistLintSeverity":1835}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"ea2beb1668dfbdd87488f18fbb20178f":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2676},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2683,"Filesystem":791,"ArcanistLinter":2731,"ArcanistLintSeverity":2839}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}}} \ No newline at end of file diff --git a/arcanist/__phutil_library_map__.php b/arcanist/__phutil_library_map__.php index 66e297767..82f69981f 100644 --- a/arcanist/__phutil_library_map__.php +++ b/arcanist/__phutil_library_map__.php @@ -1,28 +1,26 @@ 2, 'class' => array( 'AutoPEP8FormatLinter' => 'linter/AutoPEP8Linter.php', 'CheckDocLinter' => 'linter/CheckDocLinter.php', 'ClangFormatLinter' => 'linter/ClangFormatLinter.php', - 'LocaleDependenceLinter' => 'linter/LocalDependenceLinter.php', 'PythonFormatLinter' => 'linter/PythonFormatLinter.php', 'TestsLinter' => 'linter/TestsLinter.php', ), 'function' => array(), 'xmap' => array( 'AutoPEP8FormatLinter' => 'ArcanistExternalLinter', 'CheckDocLinter' => 'ArcanistExternalLinter', 'ClangFormatLinter' => 'ArcanistExternalLinter', - 'LocaleDependenceLinter' => 'ArcanistExternalLinter', 'PythonFormatLinter' => 'ArcanistExternalLinter', 'TestsLinter' => 'ArcanistExternalLinter', ), )); diff --git a/arcanist/linter/LocalDependenceLinter.php b/arcanist/linter/LocalDependenceLinter.php deleted file mode 100644 index f81b7645d..000000000 --- a/arcanist/linter/LocalDependenceLinter.php +++ /dev/null @@ -1,139 +0,0 @@ -getProjectRoot()); - } - - public function shouldUseInterpreter() { - return true; - } - - public function getDefaultInterpreter() { - return "bash"; - } - - public function getInstallInstructions() { - return pht('The test/lint/lint-locale-dependence.sh script is part of the '. - 'bitcoin-abc project. Requires git >= 2.6.5.'); - } - - public function shouldExpectCommandErrors() { - return false; - } - - protected function getMandatoryFlags() { - return array(); - } - - protected function parseLinterOutput($path, $err, $stdout, $stderr) { - /* - * Stdout contains 2 sections: - * 1/ The locale dependent function in a sentence: - * The locale dependent function (...) appears to be used - * Followed by the file and the corresponding code lines - * : - * 2/ Section with a general warning, will not be used by Arcanist. Instead - * we define our own advice message. - * - * First a list of the locale dependent functions will be determined, then - * the code lines containing these functions. - * A linting error message is generated for each line of code. - */ - - /* - * Extract infos from the path - */ - $pathinfo = pathinfo($path); - $fileName = $pathinfo['basename']; - - $messages = []; - - /* Find the functions */ - $pattern = '/The locale dependent function (\w+)\(...\)/'; - if (!preg_match_all( - $pattern, - $stdout, - $matches, - $flags = PREG_SET_ORDER - )) { - return $messages; - } - - $functions = []; - foreach ($matches as $match) { - $functions[] = $match[1]; - } - - /* Find the code lines */ - $pattern = '/'.$fileName.':(\d+): (.+)/'; - if (preg_match_all( - $pattern, - $stdout, - $matches, - $flags = PREG_SET_ORDER - )) { - foreach ($matches as $match) { - list(, $lineNumber, $codeSnippet) = $match; - - /* Determine which function is used */ - $functionUsed = ''; - foreach ($functions as $function) { - if (strpos($codeSnippet, $function) !== false) { - $functionUsed = $function; - break; - } - } - - $messages[] = id(new ArcanistLintMessage()) - ->setGranularity(ArcanistLinter::GRANULARITY_FILE) - ->setCode('LOCALE_DEPENDENCE') - ->setPath($path) - ->setLine($lineNumber) - ->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR) - ->setName('Locale dependent function '.$functionUsed) - ->setDescription(self::ADVICE_MESSAGE); - } - } - - return $messages; - } -} diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index f3b813ead..c99370c68 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -1,223 +1,223 @@ #!/usr/bin/env bash KNOWN_VIOLATIONS=( "src/bitcoin-tx.cpp.*stoul" "src/bitcoin-tx.cpp.*trim_right" "src/bitcoin-tx.cpp:.*atoi" "src/core_read.cpp.*is_digit" "src/dbwrapper.cpp:.*vsnprintf" "src/httprpc.cpp.*trim" "src/init.cpp:.*atoi" "src/netbase.cpp.*to_lower" "src/qt/rpcconsole.cpp:.*atoi" "src/qt/rpcconsole.cpp:.*isdigit" "src/rest.cpp:.*strtol" "src/rpc/server.cpp.*to_upper" "src/test/dbwrapper_tests.cpp:.*snprintf" "src/test/getarg_tests.cpp.*split" "src/torcontrol.cpp:.*atoi" "src/uint256.cpp:.*tolower" "src/util.cpp:.*atoi" "src/util.cpp:.*tolower" "src/utilmoneystr.cpp:.*isdigit" "src/utilstrencodings.cpp:.*atoi" # Append the opening parenthesis to avoid shadowing strtoll with grep "src/utilstrencodings.cpp:.*strtol\(" "src/utilstrencodings.cpp:.*strtoll" # Append the opening parenthesis to avoid shadowing strtoull with grep "src/utilstrencodings.cpp:.*strtoul\(" "src/utilstrencodings.cpp:.*strtoull" "src/utilstrencodings.h:.*atoi" ) REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="src/(crypto/ctaes/|leveldb/|secp256k1/|seeder/|tinyformat.h|univalue/)" LOCALE_DEPENDENT_FUNCTIONS=( alphasort # LC_COLLATE (via strcoll) asctime # LC_TIME (directly) asprintf # (via vasprintf) atof # LC_NUMERIC (via strtod) atoi # LC_NUMERIC (via strtol) atol # LC_NUMERIC (via strtol) atoll # (via strtoll) atoq btowc # LC_CTYPE (directly) ctime # (via asctime or localtime) dprintf # (via vdprintf) fgetwc fgetws fold_case # boost::locale::fold_case # fprintf # (via vfprintf) fputwc fputws fscanf # (via __vfscanf) fwprintf # (via __vfwprintf) getdate # via __getdate_r => isspace // __localtime_r getwc getwchar is_digit # boost::algorithm::is_digit is_space # boost::algorithm::is_space isalnum # LC_CTYPE isalpha # LC_CTYPE isblank # LC_CTYPE iscntrl # LC_CTYPE isctype # LC_CTYPE isdigit # LC_CTYPE isgraph # LC_CTYPE islower # LC_CTYPE isprint # LC_CTYPE ispunct # LC_CTYPE isspace # LC_CTYPE isupper # LC_CTYPE iswalnum # LC_CTYPE iswalpha # LC_CTYPE iswblank # LC_CTYPE iswcntrl # LC_CTYPE iswctype # LC_CTYPE iswdigit # LC_CTYPE iswgraph # LC_CTYPE iswlower # LC_CTYPE iswprint # LC_CTYPE iswpunct # LC_CTYPE iswspace # LC_CTYPE iswupper # LC_CTYPE iswxdigit # LC_CTYPE isxdigit # LC_CTYPE localeconv # LC_NUMERIC + LC_MONETARY mblen # LC_CTYPE mbrlen mbrtowc mbsinit mbsnrtowcs mbsrtowcs mbstowcs # LC_CTYPE mbtowc # LC_CTYPE mktime normalize # boost::locale::normalize # printf # LC_NUMERIC putwc putwchar scanf # LC_NUMERIC setlocale snprintf sprintf sscanf stod stof stoi stol stold stoll stoul stoull strcasecmp strcasestr strcoll # LC_COLLATE # strerror strfmon strftime # LC_TIME strncasecmp strptime strtod # LC_NUMERIC strtof strtoimax strtol # LC_NUMERIC strtold strtoll strtoq strtoul # LC_NUMERIC strtoull strtoumax strtouq strxfrm # LC_COLLATE swprintf to_lower # boost::locale::to_lower to_title # boost::locale::to_title to_upper # boost::locale::to_upper tolower # LC_CTYPE toupper # LC_CTYPE towctrans towlower # LC_CTYPE towupper # LC_CTYPE trim # boost::algorithm::trim trim_left # boost::algorithm::trim_left trim_right # boost::algorithm::trim_right ungetwc vasprintf vdprintf versionsort vfprintf vfscanf vfwprintf vprintf vscanf vsnprintf vsprintf vsscanf vswprintf vwprintf wcrtomb wcscasecmp wcscoll # LC_COLLATE wcsftime # LC_TIME wcsncasecmp wcsnrtombs wcsrtombs wcstod # LC_NUMERIC wcstof wcstoimax wcstol # LC_NUMERIC wcstold wcstoll wcstombs # LC_CTYPE wcstoul # LC_NUMERIC wcstoull wcstoumax wcswidth wcsxfrm # LC_COLLATE wctob wctomb # LC_CTYPE wctrans wctype wcwidth wprintf ) function join_array { local IFS="$1" shift echo "$*" } REGEXP_IGNORE_KNOWN_VIOLATIONS=$(join_array "|" "${KNOWN_VIOLATIONS[@]}") # Invoke "git grep" only once in order to minimize run-time REGEXP_LOCALE_DEPENDENT_FUNCTIONS=$(join_array "|" "${LOCALE_DEPENDENT_FUNCTIONS[@]}") -GIT_GREP_OUTPUT=$(git grep -nE "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(_r|_s)?)[^a-zA-Z0-9_\`'\"<>]" -- "$1") +GIT_GREP_OUTPUT=$(git grep -nE "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(_r|_s)?)[^a-zA-Z0-9_\`'\"<>]" -- ":/*.cpp" ":/*.h") -FUNCTION_FOUND=0 +EXIT_CODE=0 for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \ grep -vE "\.(c|cpp|h):[0-9]+:\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}") if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then MATCHES=$(grep -vE "${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}" <<< "${MATCHES}") fi if [[ ${REGEXP_IGNORE_KNOWN_VIOLATIONS} != "" ]]; then MATCHES=$(grep -vE "${REGEXP_IGNORE_KNOWN_VIOLATIONS}" <<< "${MATCHES}") fi if [[ ${MATCHES} != "" ]]; then echo "The locale dependent function ${LOCALE_DEPENDENT_FUNCTION}(...) appears to be used:" echo "${MATCHES}" echo - FUNCTION_FOUND=1 + EXIT_CODE=1 fi done -if [[ ${FUNCTION_FOUND} != 0 ]]; then +if [[ ${EXIT_CODE} != 0 ]]; then echo "Unnecessary locale dependence can cause bugs that are very" echo "tricky to isolate and fix. Please avoid using locale dependent" echo "functions if possible." echo echo "Advice not applicable in this specific case? Add an exception" echo "by updating the ignore list in $0" fi -exit 0 +exit ${EXIT_CODE}