diff options
Diffstat (limited to 'test/lint')
-rwxr-xr-x | test/lint/extended-lint-all.sh | 26 | ||||
-rwxr-xr-x | test/lint/extended-lint-cppcheck.sh | 88 | ||||
-rwxr-xr-x | test/lint/lint-assertions.py | 12 | ||||
-rwxr-xr-x | test/lint/lint-circular-dependencies.py | 16 | ||||
-rwxr-xr-x | test/lint/lint-format-strings.py | 2 | ||||
-rwxr-xr-x | test/lint/lint-includes.py | 5 | ||||
-rwxr-xr-x | test/lint/lint-locale-dependence.py | 8 | ||||
-rwxr-xr-x | test/lint/lint-shell.py | 93 | ||||
-rwxr-xr-x | test/lint/lint-shell.sh | 33 |
9 files changed, 112 insertions, 171 deletions
diff --git a/test/lint/extended-lint-all.sh b/test/lint/extended-lint-all.sh deleted file mode 100755 index be5d9db4a9..0000000000 --- a/test/lint/extended-lint-all.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2019-2020 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# -# This script runs all contrib/devtools/extended-lint-*.sh files, and fails if -# any exit with a non-zero status code. - -# This script is intentionally locale dependent by not setting "export LC_ALL=C" -# in order to allow for the executed lint scripts to opt in or opt out of locale -# dependence themselves. - -set -u - -SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") -LINTALL=$(basename "${BASH_SOURCE[0]}") - -for f in "${SCRIPTDIR}"/extended-lint-*.sh; do - if [ "$(basename "$f")" != "$LINTALL" ]; then - if ! "$f"; then - echo "^---- failure generated from $f" - exit 1 - fi - fi -done diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh deleted file mode 100755 index 2af39ed60a..0000000000 --- a/test/lint/extended-lint-cppcheck.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2019-2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# - -export LC_ALL=C - -ENABLED_CHECKS=( - "Class '.*' has a constructor with 1 argument that is not explicit." - "Struct '.*' has a constructor with 1 argument that is not explicit." -) - -IGNORED_WARNINGS=( - "src/arith_uint256.h:.* Class 'arith_uint256' has a constructor with 1 argument that is not explicit." - "src/arith_uint256.h:.* Class 'base_uint < 256 >' has a constructor with 1 argument that is not explicit." - "src/arith_uint256.h:.* Class 'base_uint' has a constructor with 1 argument that is not explicit." - "src/coins.h:.* Class 'CCoinsViewBacked' has a constructor with 1 argument that is not explicit." - "src/coins.h:.* Class 'CCoinsViewCache' has a constructor with 1 argument that is not explicit." - "src/coins.h:.* Class 'CCoinsViewCursor' has a constructor with 1 argument that is not explicit." - "src/net.h:.* Class 'CNetMessage' has a constructor with 1 argument that is not explicit." - "src/policy/feerate.h:.* Class 'CFeeRate' has a constructor with 1 argument that is not explicit." - "src/prevector.h:.* Class 'const_iterator' has a constructor with 1 argument that is not explicit." - "src/prevector.h:.* Class 'const_reverse_iterator' has a constructor with 1 argument that is not explicit." - "src/prevector.h:.* Class 'iterator' has a constructor with 1 argument that is not explicit." - "src/prevector.h:.* Class 'reverse_iterator' has a constructor with 1 argument that is not explicit." - "src/primitives/block.h:.* Class 'CBlock' has a constructor with 1 argument that is not explicit." - "src/primitives/transaction.h:.* Class 'CTransaction' has a constructor with 1 argument that is not explicit." - "src/protocol.h:.* Class 'CMessageHeader' has a constructor with 1 argument that is not explicit." - "src/qt/guiutil.h:.* Class 'ItemDelegate' has a constructor with 1 argument that is not explicit." - "src/rpc/util.h:.* Struct 'RPCResults' has a constructor with 1 argument that is not explicit." - "src/rpc/util.h:.* Struct 'UniValueType' has a constructor with 1 argument that is not explicit." - "src/rpc/util.h:.* style: Struct 'UniValueType' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'AddressDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'ComboDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'ConstPubkeyProvider' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'PKDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'PKHDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'RawDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'SHDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'WPKHDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/descriptor.cpp:.* Class 'WSHDescriptor' has a constructor with 1 argument that is not explicit." - "src/script/script.h:.* Class 'CScript' has a constructor with 1 argument that is not explicit." - "src/script/standard.h:.* Class 'CScriptID' has a constructor with 1 argument that is not explicit." - "src/span.h:.* Class 'Span < const CRPCCommand >' has a constructor with 1 argument that is not explicit." - "src/span.h:.* Class 'Span < const char >' has a constructor with 1 argument that is not explicit." - "src/span.h:.* Class 'Span < const std :: vector <unsigned char > >' has a constructor with 1 argument that is not explicit." - "src/span.h:.* Class 'Span < const uint8_t >' has a constructor with 1 argument that is not explicit." - "src/span.h:.* Class 'Span' has a constructor with 1 argument that is not explicit." - "src/support/allocators/secure.h:.* Struct 'secure_allocator < char >' has a constructor with 1 argument that is not explicit." - "src/support/allocators/secure.h:.* Struct 'secure_allocator < RNGState >' has a constructor with 1 argument that is not explicit." - "src/support/allocators/secure.h:.* Struct 'secure_allocator < unsigned char >' has a constructor with 1 argument that is not explicit." - "src/support/allocators/zeroafterfree.h:.* Struct 'zero_after_free_allocator < char >' has a constructor with 1 argument that is not explicit." - "src/test/checkqueue_tests.cpp:.* Struct 'FailingCheck' has a constructor with 1 argument that is not explicit." - "src/test/checkqueue_tests.cpp:.* Struct 'MemoryCheck' has a constructor with 1 argument that is not explicit." - "src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit." - "src/test/fuzz/util.h:.* Class 'FuzzedFileProvider' has a constructor with 1 argument that is not explicit." - "src/test/fuzz/util.h:.* Class 'FuzzedAutoFileProvider' has a constructor with 1 argument that is not explicit." - "src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit." -) - -if ! command -v cppcheck > /dev/null; then - echo "Skipping cppcheck linting since cppcheck is not installed. Install by running \"apt install cppcheck\"" - exit 0 -fi - -function join_array { - local IFS="$1" - shift - echo "$*" -} - -ENABLED_CHECKS_REGEXP=$(join_array "|" "${ENABLED_CHECKS[@]}") -IGNORED_WARNINGS_REGEXP=$(join_array "|" "${IGNORED_WARNINGS[@]}") -WARNINGS=$(git ls-files -- "*.cpp" "*.h" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/minisketch/" ":(exclude)src/univalue/" | \ - xargs cppcheck --enable=all -j "$(getconf _NPROCESSORS_ONLN)" --language=c++ --std=c++17 --template=gcc -D__cplusplus -DCLIENT_VERSION_BUILD -DCLIENT_VERSION_IS_RELEASE -DCLIENT_VERSION_MAJOR -DCLIENT_VERSION_MINOR -DCOPYRIGHT_YEAR -DDEBUG -I src/ -q 2>&1 | sort -u | \ - grep -E "${ENABLED_CHECKS_REGEXP}" | \ - grep -vE "${IGNORED_WARNINGS_REGEXP}") -if [[ ${WARNINGS} != "" ]]; then - echo "${WARNINGS}" - echo - echo "Advice not applicable in this specific case? Add an exception by updating" - echo "IGNORED_WARNINGS in $0" - # Uncomment to enforce the developer note policy "By default, declare single-argument constructors `explicit`" - # exit 1 -fi -exit 0 diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py index a8d2b3927c..195ff33d11 100755 --- a/test/lint/lint-assertions.py +++ b/test/lint/lint-assertions.py @@ -30,20 +30,20 @@ def main(): r"[^_]assert\(.*(\+\+|\-\-|[^=!<>]=[^=!<>]).*\);", "--", "*.cpp", - "*.h" + "*.h", ], "Assertions should not have side effects:") - # Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it - # is undesirable to crash the whole program. See: src/util/check.h + # Aborting the whole process is undesirable for RPC code. So nonfatal + # checks should be used over assert. See: src/util/check.h # src/rpc/server.cpp is excluded from this check since it's mostly meta-code. exit_code |= git_grep([ "-nE", - r"\<(A|a)ssert *\(.*\);", + r"\<(A|a)ss(ume|ert) *\(.*\);", "--", "src/rpc/", "src/wallet/rpc*", - ":(exclude)src/rpc/server.cpp" - ], "CHECK_NONFATAL(condition) should be used instead of assert for RPC code.") + ":(exclude)src/rpc/server.cpp", + ], "CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.") sys.exit(exit_code) diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index e04909c0a5..7ca2ec994b 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -6,7 +6,6 @@ # # Check for circular dependencies -import glob import os import re import subprocess @@ -32,17 +31,14 @@ CODE_DIR = "src" def main(): circular_dependencies = [] exit_code = 0 - os.chdir( - CODE_DIR - ) # We change dir before globbing since glob.glob's root_dir option is only available in Python 3.10 - # Using glob.glob since subprocess.run's globbing won't work without shell=True - files = [] - for path in ["*", "*/*", "*/*/*"]: - for extension in ["h", "cpp"]: - files.extend(glob.glob(f"{path}.{extension}")) + os.chdir(CODE_DIR) + files = subprocess.check_output( + ['git', 'ls-files', '--', '*.h', '*.cpp'], + universal_newlines=True, + ).splitlines() - command = ["python3", "../contrib/devtools/circular-dependencies.py", *files] + command = [sys.executable, "../contrib/devtools/circular-dependencies.py", *files] dependencies_output = subprocess.run( command, stdout=subprocess.PIPE, diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py index 5a36da11fd..28e7b1e4ff 100755 --- a/test/lint/lint-format-strings.py +++ b/test/lint/lint-format-strings.py @@ -36,7 +36,7 @@ RUN_LINT_FILE = 'test/lint/run-lint-format-strings.py' def check_doctest(): command = [ - 'python3', + sys.executable, '-m', 'doctest', RUN_LINT_FILE, diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py index b29c7f8b4d..ae62994642 100755 --- a/test/lint/lint-includes.py +++ b/test/lint/lint-includes.py @@ -21,10 +21,7 @@ EXCLUDED_DIRS = ["src/leveldb/", "src/minisketch/", "src/univalue/"] -EXPECTED_BOOST_INCLUDES = ["boost/algorithm/string.hpp", - "boost/algorithm/string/classification.hpp", - "boost/algorithm/string/replace.hpp", - "boost/algorithm/string/split.hpp", +EXPECTED_BOOST_INCLUDES = ["boost/algorithm/string/replace.hpp", "boost/date_time/posix_time/posix_time.hpp", "boost/multi_index/hashed_index.hpp", "boost/multi_index/ordered_index.hpp", diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py index 2abf1be6b3..9b2cf4587a 100755 --- a/test/lint/lint-locale-dependence.py +++ b/test/lint/lint-locale-dependence.py @@ -49,7 +49,9 @@ KNOWN_VIOLATIONS = [ "src/test/fuzz/locale.cpp:.*setlocale", "src/test/fuzz/string.cpp:.*strtol", "src/test/fuzz/string.cpp:.*strtoul", - "src/test/util_tests.cpp:.*strtoll" + "src/test/util_tests.cpp:.*strtoll", + "src/wallet/bdb.cpp:.*DbEnv::strerror", # False positive + "src/util/syserror.cpp:.*strerror", # Outside this function use `SysErrorString` ] REGEXP_EXTERNAL_DEPENDENCIES_EXCLUSIONS = [ @@ -144,7 +146,7 @@ LOCALE_DEPENDENT_FUNCTIONS = [ "strcasecmp", "strcasestr", "strcoll", # LC_COLLATE - #"strerror", + "strerror", "strfmon", "strftime", # LC_TIME "strncasecmp", @@ -218,7 +220,7 @@ LOCALE_DEPENDENT_FUNCTIONS = [ def find_locale_dependent_function_uses(): regexp_locale_dependent_functions = "|".join(LOCALE_DEPENDENT_FUNCTIONS) exclude_args = [":(exclude)" + excl for excl in REGEXP_EXTERNAL_DEPENDENCIES_EXCLUSIONS] - git_grep_command = ["git", "grep", "-E", "[^a-zA-Z0-9_\\`'\"<>](" + regexp_locale_dependent_functions + "(_r|_s)?)[^a-zA-Z0-9_\\`'\"<>]", "--", "*.cpp", "*.h"] + exclude_args + git_grep_command = ["git", "grep", "-E", "[^a-zA-Z0-9_\\`'\"<>](" + regexp_locale_dependent_functions + ")(_r|_s)?[^a-zA-Z0-9_\\`'\"<>]", "--", "*.cpp", "*.h"] + exclude_args git_grep_output = list() try: diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py new file mode 100755 index 0000000000..f1e4494350 --- /dev/null +++ b/test/lint/lint-shell.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2018-2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Check for shellcheck warnings in shell scripts. +""" + +import subprocess +import re +import sys + +# Disabled warnings: +DISABLED = [ + 'SC2162', # read without -r will mangle backslashes. +] + +def check_shellcheck_install(): + try: + subprocess.run(['shellcheck', '--version'], stdout=subprocess.DEVNULL, check=True) + except FileNotFoundError: + print('Skipping shell linting since shellcheck is not installed.') + sys.exit(0) + +def get_files(command): + output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True) + files = output.stdout.split('\n') + + # remove whitespace element + files = list(filter(None, files)) + return files + +def main(): + check_shellcheck_install() + + # build the `exclude` flag + exclude = '--exclude=' + ','.join(DISABLED) + + # build the `sourced files` list + sourced_files_cmd = [ + 'git', + 'grep', + '-El', + r'^# shellcheck shell=', + ] + sourced_files = get_files(sourced_files_cmd) + + # build the `guix files` list + guix_files_cmd = [ + 'git', + 'grep', + '-El', + r'^#!\/usr\/bin\/env bash', + '--', + 'contrib/guix', + 'contrib/shell', + ] + guix_files = get_files(guix_files_cmd) + + # build the other script files list + files_cmd = [ + 'git', + 'ls-files', + '--', + '*.sh', + ] + files = get_files(files_cmd) + # remove everything that doesn't match this regex + reg = re.compile(r'src/[leveldb,secp256k1,minisketch,univalue]') + files[:] = [file for file in files if not reg.match(file)] + + # build the `shellcheck` command + shellcheck_cmd = [ + 'shellcheck', + '--external-sources', + '--check-sourced', + '--source-path=SCRIPTDIR', + ] + shellcheck_cmd.append(exclude) + shellcheck_cmd.extend(sourced_files) + shellcheck_cmd.extend(guix_files) + shellcheck_cmd.extend(files) + + # run the `shellcheck` command + try: + subprocess.check_call(shellcheck_cmd) + except subprocess.CalledProcessError: + sys.exit(1) + +if __name__ == '__main__': + main() diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh deleted file mode 100755 index 5fa104fce6..0000000000 --- a/test/lint/lint-shell.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2018-2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -# -# Check for shellcheck warnings in shell scripts. - -export LC_ALL=C - -# Disabled warnings: -disabled=( - SC2162 # read without -r will mangle backslashes. -) - -EXIT_CODE=0 - -if ! command -v shellcheck > /dev/null; then - echo "Skipping shell linting since shellcheck is not installed." - exit $EXIT_CODE -fi - -SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced --source-path=SCRIPTDIR) -EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")" -# Check shellcheck directive used for sourced files -mapfile -t SOURCED_FILES < <(git ls-files | xargs gawk '/^# shellcheck shell=/ {print FILENAME} {nextfile}') -mapfile -t GUIX_FILES < <(git ls-files contrib/guix contrib/shell | xargs gawk '/^#!\/usr\/bin\/env bash/ {print FILENAME} {nextfile}') -mapfile -t FILES < <(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|minisketch|univalue)/') -if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${GUIX_FILES[@]}" "${FILES[@]}"; then - EXIT_CODE=1 -fi - -exit $EXIT_CODE |