diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..56d7f64 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,24 @@ +Checks: + -*, + readability-*, + -readability-braces-around-statements, + -readability-container-size-empty, + -readability-else-after-return, + -readability-implicit-bool-conversion, + -readability-function-cognitive-complexity, + -readability-magic-numbers, + -readability-named-parameter, + -readability-qualified-auto, + -readability-static-accessed-through-instance, + +CheckOptions: + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.ConstexprVariableCase, value: lower_case } + - { key: readability-identifier-naming.FunctionCase, value: lower_case } + - { key: readability-identifier-naming.LocalVariableIgnoredRegexp, value: "^[a-z][a-z_]+" } + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readability-identifier-naming.PrivateMemberPrefix, value: m } + - { key: readability-identifier-naming.StructCase, value: lower_case } + - { key: readability-identifier-naming.VariableCase, value: camelBack } + +HeaderFilterRegex: '.*' diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml new file mode 100644 index 0000000..d5a2e50 --- /dev/null +++ b/.github/workflows/static_analysis.yml @@ -0,0 +1,42 @@ + +name: Static Analysis + +on: pull_request_target + +jobs: + + static_analysis: + + name: ${{ matrix.toolchain }} + runs-on: ${{ matrix.os }} + + strategy: + + matrix: + + toolchain: + - ubuntu-latest + + include: + - toolchain: ubuntu-latest + os: ubuntu-latest + compiler: clang + + steps: + + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Analyze + uses: JacobDomagala/StaticAnalysis@master + with: + clang_tidy_args: >- + --config-file=$GITHUB_WORKSPACE/.clang-tidy + --extra-arg=-I$GITHUB_WORKSPACE/include --extra-arg=-std=c++17 + cppcheck_args: >- + --enable=all --inconclusive --inline-suppr + -i$GITHUB_WORKSPACE/test/main.cpp + -i$GITHUB_WORKSPACE/test/test_*.cpp + --suppress=missingInclude + --suppress='*:$GITHUB_WORKSPACE/test/doctest.hpp' + init_script: tools/static_analysis_setup.sh diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index aa5f959..2aa06fd 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -453,7 +453,7 @@ public: mUsedName = usedName; if (mNumArgs == 0) { mValues.emplace_back(mImplicitValue); - std::visit([](auto &aAction) { aAction({}); }, mAction); + std::visit([](const auto &aAction) { aAction({}); }, mAction); return start; } else if (mNumArgs <= std::distance(start, end)) { if (auto expected = maybe_nargs()) { @@ -857,6 +857,9 @@ public: ArgumentParser(const ArgumentParser &other) : mProgramName(other.mProgramName), + mVersion(other.mVersion), + mDescription(other.mDescription), + mEpilog(other.mEpilog), mIsParsed(other.mIsParsed), mPositionalArguments(other.mPositionalArguments), mOptionalArguments(other.mOptionalArguments) { @@ -999,39 +1002,37 @@ public: // Print help message friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) -> std::ostream & { - if (auto sen = std::ostream::sentry(stream)) { - stream.setf(std::ios_base::left); - stream << "Usage: " << parser.mProgramName << " [options] "; - std::size_t tLongestArgumentLength = parser.get_length_of_longest_argument(); + stream.setf(std::ios_base::left); + stream << "Usage: " << parser.mProgramName << " [options] "; + std::size_t tLongestArgumentLength = parser.get_length_of_longest_argument(); - for (const auto &argument : parser.mPositionalArguments) { - stream << argument.mNames.front() << " "; - } - stream << "\n\n"; - - if (!parser.mDescription.empty()) - stream << parser.mDescription << "\n\n"; - - if (!parser.mPositionalArguments.empty()) - stream << "Positional arguments:\n"; - - for (const auto &mPositionalArgument : parser.mPositionalArguments) { - stream.width(tLongestArgumentLength); - stream << mPositionalArgument; - } - - if (!parser.mOptionalArguments.empty()) - stream << (parser.mPositionalArguments.empty() ? "" : "\n") - << "Optional arguments:\n"; - - for (const auto &mOptionalArgument : parser.mOptionalArguments) { - stream.width(tLongestArgumentLength); - stream << mOptionalArgument; - } - - if (!parser.mEpilog.empty()) - stream << parser.mEpilog << "\n\n"; + for (const auto &argument : parser.mPositionalArguments) { + stream << argument.mNames.front() << " "; } + stream << "\n\n"; + + if (!parser.mDescription.empty()) + stream << parser.mDescription << "\n\n"; + + if (!parser.mPositionalArguments.empty()) + stream << "Positional arguments:\n"; + + for (const auto &mPositionalArgument : parser.mPositionalArguments) { + stream.width(tLongestArgumentLength); + stream << mPositionalArgument; + } + + if (!parser.mOptionalArguments.empty()) + stream << (parser.mPositionalArguments.empty() ? "" : "\n") + << "Optional arguments:\n"; + + for (const auto &mOptionalArgument : parser.mOptionalArguments) { + stream.width(tLongestArgumentLength); + stream << mOptionalArgument; + } + + if (!parser.mEpilog.empty()) + stream << parser.mEpilog << "\n\n"; return stream; } @@ -1046,7 +1047,7 @@ public: // Printing the one and only help message // I've stuck with a simple message format, nothing fancy. [[deprecated("Use cout << program; instead. See also help().")]] std::string - print_help() { + print_help() const { auto out = help(); std::cout << out.rdbuf(); return out.str(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3c502d9..02572a0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -57,3 +57,10 @@ set_property(TARGET ARGPARSE PROPERTY CXX_STANDARD 17) # Set ${PROJECT_NAME} as the startup project set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ARGPARSE) + +file(GLOB ARGPARSE_LINT_SOURCES + tidy-base.cpp +) +ADD_EXECUTABLE(ARGPARSE_LINT ${ARGPARSE_LINT_SOURCES}) +set_target_properties(ARGPARSE_LINT PROPERTIES OUTPUT_NAME tidy-base) +set_property(TARGET ARGPARSE_LINT PROPERTY CXX_STANDARD 17) diff --git a/test/tidy-base.cpp b/test/tidy-base.cpp new file mode 100644 index 0000000..87b47a1 --- /dev/null +++ b/test/tidy-base.cpp @@ -0,0 +1,4 @@ + +#include "argparse/argparse.hpp" + +int main(int argc, const char* argv[]) {} diff --git a/tools/static_analysis_setup.sh b/tools/static_analysis_setup.sh new file mode 100755 index 0000000..cd0dc06 --- /dev/null +++ b/tools/static_analysis_setup.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Change to the "test" subdir before "build" subdir is made. +cd test