diff options
Diffstat (limited to 'test/lint')
-rwxr-xr-x | test/lint/lint-includes.sh | 89 | ||||
-rwxr-xr-x | test/lint/lint-locale-dependence.sh | 229 |
2 files changed, 317 insertions, 1 deletions
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index f54be46b52..f5daf4f9ac 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -5,12 +5,17 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # # Check for duplicate includes. +# Guard against accidental introduction of new Boost dependencies. +# Check includes: Check for duplicate includes. Enforce bracket syntax includes. + +IGNORE_REGEXP="/(leveldb|secp256k1|univalue)/" filter_suffix() { - git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "/(leveldb|secp256k1|univalue)/" + git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "${IGNORE_REGEXP}" } EXIT_CODE=0 + for HEADER_FILE in $(filter_suffix h); do DUPLICATE_INCLUDES_IN_HEADER_FILE=$(grep -E "^#include " < "${HEADER_FILE}" | sort | uniq -d) if [[ ${DUPLICATE_INCLUDES_IN_HEADER_FILE} != "" ]]; then @@ -20,6 +25,7 @@ for HEADER_FILE in $(filter_suffix h); do EXIT_CODE=1 fi done + for CPP_FILE in $(filter_suffix cpp); do DUPLICATE_INCLUDES_IN_CPP_FILE=$(grep -E "^#include " < "${CPP_FILE}" | sort | uniq -d) if [[ ${DUPLICATE_INCLUDES_IN_CPP_FILE} != "" ]]; then @@ -29,4 +35,85 @@ for CPP_FILE in $(filter_suffix cpp); do EXIT_CODE=1 fi done + +INCLUDED_CPP_FILES=$(git grep -E "^#include [<\"][^>\"]+\.cpp[>\"]" -- "*.cpp" "*.h") +if [[ ${INCLUDED_CPP_FILES} != "" ]]; then + echo "The following files #include .cpp files:" + echo "${INCLUDED_CPP_FILES}" + echo + EXIT_CODE=1 +fi + +EXPECTED_BOOST_INCLUDES=( + boost/algorithm/string.hpp + boost/algorithm/string/case_conv.hpp + boost/algorithm/string/classification.hpp + boost/algorithm/string/join.hpp + boost/algorithm/string/predicate.hpp + boost/algorithm/string/replace.hpp + boost/algorithm/string/split.hpp + boost/assign/std/vector.hpp + boost/bind.hpp + boost/chrono/chrono.hpp + boost/date_time/posix_time/posix_time.hpp + boost/filesystem.hpp + boost/filesystem/detail/utf8_codecvt_facet.hpp + boost/filesystem/fstream.hpp + boost/interprocess/sync/file_lock.hpp + boost/multi_index/hashed_index.hpp + boost/multi_index/ordered_index.hpp + boost/multi_index/sequenced_index.hpp + boost/multi_index_container.hpp + boost/optional.hpp + boost/preprocessor/cat.hpp + boost/preprocessor/stringize.hpp + boost/program_options/detail/config_file.hpp + boost/scoped_array.hpp + boost/signals2/connection.hpp + boost/signals2/last_value.hpp + boost/signals2/signal.hpp + boost/test/unit_test.hpp + boost/thread.hpp + boost/thread/condition_variable.hpp + boost/thread/mutex.hpp + boost/thread/thread.hpp + boost/variant.hpp + boost/variant/apply_visitor.hpp + boost/variant/static_visitor.hpp +) + +for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do + IS_EXPECTED_INCLUDE=0 + for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do + if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then + IS_EXPECTED_INCLUDE=1 + break + fi + done + if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then + EXIT_CODE=1 + echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:" + git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h" + echo + fi +done + +for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do + if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then + echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used." + echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0" + echo "to make sure this dependency is not accidentally reintroduced." + echo + EXIT_CODE=1 + fi +done + +QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}") +if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then + echo "Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:" + echo "${QUOTE_SYNTAX_INCLUDES}" + echo + EXIT_CODE=1 +fi + exit ${EXIT_CODE} diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh new file mode 100755 index 0000000000..3144f2c841 --- /dev/null +++ b/test/lint/lint-locale-dependence.sh @@ -0,0 +1,229 @@ +#!/bin/bash + +KNOWN_VIOLATIONS=( + "src/base58.cpp:.*isspace" + "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.*stoul" + "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/torcontrol.cpp:.*strtol" + "src/uint256.cpp:.*isspace" + "src/uint256.cpp:.*tolower" + "src/util.cpp:.*atoi" + "src/util.cpp:.*fprintf" + "src/util.cpp:.*tolower" + "src/utilmoneystr.cpp:.*isdigit" + "src/utilmoneystr.cpp:.*isspace" + "src/utilstrencodings.cpp:.*atoi" + "src/utilstrencodings.cpp:.*isspace" + "src/utilstrencodings.cpp:.*strtol" + "src/utilstrencodings.cpp:.*strtoll" + "src/utilstrencodings.cpp:.*strtoul" + "src/utilstrencodings.cpp:.*strtoull" + "src/utilstrencodings.h:.*atoi" +) + +REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|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 -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(|_r|_s))[^a-zA-Z0-9_\`'\"<>]" -- "*.cpp" "*.h") + +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):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}" | \ + grep -vE 'fprintf\(.*(stdout|stderr)') + 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 + EXIT_CODE=1 + fi +done +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 ${EXIT_CODE} |