Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cppcheck. #23

Merged
merged 2 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/style_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ jobs:
python3 -m pip install --upgrade pip
pip install cpplint==1.4.5

- name: Install cppcheck
run: |
cd /tmp
git clone --depth 1 https://github.com/danmar/cppcheck.git
cd cppcheck
mkdir build
cd build
cmake ..
make -j
sudo make install

- name: Create Build Directory
run: cmake -E make_directory ${{runner.workspace}}/build

Expand All @@ -42,7 +53,12 @@ jobs:
working-directory: ${{runner.workspace}}/build
run: cmake -DCMAKE_CXX_CPPLINT=cpplint $GITHUB_WORKSPACE

- name: Check style
- name: Check style with cpplint
shell: bash
working-directory: ${{github.workspace}}
run: ./scripts/check_style_cpplint.sh ${{runner.workspace}}/build 1

- name: Run cppcheck
shell: bash
working-directory: ${{github.workspace}}
run: ./scripts/run_cppcheck.sh ${{runner.workspace}}/build
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(k2)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

option(BUILD_SHARED_LIBS "Whether to build shared or static lib" ON)

set(k2_THIRD_PARTY_DIR "${CMAKE_BINARY_DIR}/third_party" CACHE STRING
Expand Down
2 changes: 1 addition & 1 deletion k2/csrc/fsa_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ int32_t StringToInt(const std::string &s, bool *is_ok = nullptr) {
char *p = nullptr;
// std::strtol requires a `long` type
long n = std::strtol(s.c_str(), &p, 10); // NOLINT
if (*p == 0) ok = true;
if (*p == '\0') ok = true;

int32_t res = static_cast<int32_t>(n);
if (n != res) ok = false; // out of range
Expand Down
4 changes: 4 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

## googletest.cfg

It is downloaded from https://github.com/danmar/cppcheck/blob/master/cfg/googletest.cfg
19 changes: 4 additions & 15 deletions scripts/check_style_cpplint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,12 @@
# cmake ..
# make check_style

default='\033[0m'
bold='\033[1m'
red='\033[31m'
green='\033[32m'

cur_dir=$(cd $(dirname $BASH_SOURCE) && pwd)
k2_dir=$(cd $cur_dir/.. && pwd)

if [ $# -ge 1 ]; then
build_dir=$1
build_dir=$(cd $1 && pwd)
shift
else
# we assume that the build dir is "./build"; cpplint
Expand All @@ -37,14 +33,7 @@ else
fi
cpplint_src=$build_dir/_deps/cpplint-src/cpplint.py

function ok() {
printf "${bold}${green}[OK]${default} $1\n"
}

function error() {
printf "${bold}${red}[FAILED]${default} $1\n"
exit 1
}
source $k2_dir/scripts/utils.sh

# return true if the given file is a c++ source file
# return false otherwise
Expand All @@ -58,7 +47,7 @@ function is_source_code_file() {
}

function check_style() {
python3 $cpplint_src $1 || error $1
python3 $cpplint_src $1 || abort $1
}

function check_last_commit() {
Expand Down Expand Up @@ -97,7 +86,7 @@ function do_check() {

function main() {
if [ ! -f $cpplint_src ]; then
error "\n$cpplint_src does not exist.\n\
abort "\n$cpplint_src does not exist.\n\
Please run
mkdir build
cd build
Expand Down
58 changes: 58 additions & 0 deletions scripts/googletest.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0"?>
<def format="2">
<!-- see https://github.com/google/googletest/blob/master/googletest/docs/primer.md -->
<define name="ASSERT_TRUE(cond)" value="assert(cond)"/>
<define name="EXPECT_TRUE(cond)" value="(void)(cond)"/>
<define name="ASSERT_FALSE(cond)" value="assert(!cond)"/>
<define name="EXPECT_FALSE(cond)" value="(void)(cond)"/>
<define name="ASSERT_EQ(val1,val2)" value="assert((val1)==(val2))"/>
<define name="EXPECT_EQ(val1,val2)" value="(void)((val1)==(val2))"/>
<define name="ASSERT_NE(val1,val2)" value="assert((val1)!=(val2))"/>
<define name="EXPECT_NE(val1,val2)" value="(void)((val1)!=(val2))"/>
<define name="ASSERT_LT(val1,val2)" value="assert((val1)&lt;(val2))"/>
<define name="EXPECT_LT(val1,val2)" value="(void)((val1)&lt;(val2))"/>
<define name="ASSERT_LE(val1,val2)" value="assert((val1)&lt;=(val2))"/>
<define name="EXPECT_LE(val1,val2)" value="(void)((val1)&lt;=(val2))"/>
<define name="ASSERT_GT(val1,val2)" value="assert((val1)&gt;(val2))"/>
<define name="EXPECT_GT(val1,val2)" value="(void)((val1)&gt;(val2))"/>
<define name="ASSERT_GE(val1,val2)" value="assert((val1)&gt;=(val2))"/>
<define name="EXPECT_GE(val1,val2)" value="(void)((val1)&gt;=(val2))"/>
<define name="ASSERT_STREQ(str1,str2)" value="assert(strcmp(str1, str2) == 0)"/>
<define name="EXPECT_STREQ(str1,str2)" value="(void)(*(str1)==*(str2))"/>
<define name="ASSERT_STRNE(str1,str2)" value="assert(strcmp(str1, str2) != 0)"/>
<define name="EXPECT_STRNE(str1,str2)" value="(void)(*(str1)!=*(str2))"/>
<define name="ASSERT_STRCASEEQ(str1,str2)" value="assert(stricmp(str1, str2) == 0)"/>
<define name="EXPECT_STRCASEEQ(str1,str2)" value="(void)(*(str1)==*(str2))"/>
<define name="ASSERT_STRCASENE(str1,str2)" value="assert(stricmp(str1, str2) != 0)"/>
<define name="EXPECT_STRCASENE(str1,str2)" value="(void)(*(str1)!=*(str2))"/>
<define name="ASSERT_THROW(code, e)" value="try{code}catch(e){}"/>
<define name="EXPECT_THROW(code, e)" value="try{code}catch(e){}"/>
<define name="TEST(A,B)" value="void __ ## A ## _ ## B ( )"/>
<define name="TEST_F(A,B)" value="void __ ## A ## _ ## B ( )"/>
<define name="TEST_P(A,B)" value="void __ ## A ## _ ## B ( )"/>
<define name="GTEST_API_" value=""/>
<define name="GTEST_FLAG(name)" value="FLAGS_gtest_##name"/>
<define name="GTEST_DECLARE_bool_(name)" value="GTEST_API_ extern bool GTEST_FLAG(name)"/>
<define name="GTEST_DECLARE_int32_(name)" value="GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)"/>
<define name="GTEST_DECLARE_string_(name)" value="GTEST_API_ extern ::std::string GTEST_FLAG(name)"/>
<define name="GTEST_DEFINE_bool_(name, default_val, doc)" value="GTEST_API_ bool GTEST_FLAG(name) = (default_val)"/>
<define name="GTEST_DEFINE_int32_(name, default_val, doc)" value="GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)"/>
<define name="GTEST_DEFINE_string_(name, default_val, doc)" value="GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)"/>
<define name="GTEST_CONCAT_TOKEN_(foo, bar)" value="GTEST_CONCAT_TOKEN_IMPL_(foo, bar)"/>
<define name="GTEST_CONCAT_TOKEN_IMPL_(foo, bar)" value="foo ## bar"/>
<define name="GTEST_STRINGIFY_(name)" value="#name"/>
<define name="GTEST_REFERENCE_TO_CONST_(T)" value="typename ::testing::internal::ConstRef&lt;T&gt;::type"/>
<define name="GTEST_ATTRIBUTE_UNUSED_" value="__attribute__ ((unused))"/>
<define name="MATCHER(name, description,...)" value="bool name##Matcher&lt;_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain( GTEST_REFERENCE_TO_CONST_(arg_type) arg, ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P(name, p0, description)" value="bool name##MatcherP&lt;p0##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain( GTEST_REFERENCE_TO_CONST_(arg_type) arg, ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P2(name, p0, p1, description)" value="bool name##MatcherP2&lt;p0##_type, p1##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P3(name, p0, p1, p2, description)" value="bool name##MatcherP3&lt;p0##_type, p1##_type, p2##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P4(name, p0, p1, p2, p3, description)" value="bool name##MatcherP4&lt;p0##_type, p1##_type, p2##_type, p3##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P5(name, p0, p1, p2, p3, p4, description)" value="bool name##MatcherP5&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)" value="bool name##MatcherP6&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)" value="bool name##MatcherP7&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, p6##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)" value="bool name##MatcherP8&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, p6##_type, p7##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)" value="bool name##MatcherP9&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, p6##_type, p7##_type, p8##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)" value="bool name##MatcherP10&lt;p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type&gt;::gmock_Impl&lt;arg_type&gt;::MatchAndExplain(GTEST_REFERENCE_TO_CONST_(arg_type) arg,::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) const"/>
<define name="MOCK_METHOD(...)" value=""/>
</def>
93 changes: 93 additions & 0 deletions scripts/run_cppcheck.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash

# Copyright 2020 Fangjun Kuang (csukuangfj@gmail.com)

# See ../LICENSE for clarification regarding multiple authors

# Usage:
# ./scripts/run_cppcheck.sh
# Use the default build dir `build`
#
# ./scripts/run_cppcheck.sh /path/to/build
# Use the specified build dir `/path/to/build`
#
# Before running this scripts, you have to install `cppcheck`.
# You can use one of the following methods to install it.
#
# (1) Ubuntu
#
# sudo apt-get install cppcheck
#
# (2) macOS
#
# brew install cppcheck
#
# (3) Install from source
#
# git clone https://github.com/danmar/cppcheck.git
# cd cppcheck
# mkdir build
# cd build
# cmake ..
# make
# make install

if ! command -v cppcheck > /dev/null 2>&1; then
echo "Please install cppcheck first"
exit 1
fi

cur_dir=$(cd $(dirname $BASH_SOURCE) && pwd)
k2_dir=$(cd $cur_dir/.. && pwd)

if [ $# -ge 1 ]; then
build_dir=$(cd $1 && pwd)
shift
else
build_dir=$k2_dir/build
fi

if [ ! -f $build_dir/compile_commands.json ]; then
echo "$build_dir/compile_commands.json is missing"
echo "Did you forget to configure the project?"
echo "Please run: "
echo " cd build"
echo " cmake .."
echo "before running this script."
exit 1
fi

suppression_file="$k2_dir/scripts/suppressions.txt"

tmpfile=$(mktemp)
trap "{ rm $tmpfile; }" EXIT

cat $suppression_file |
sed -e "s:build_dir:$build_dir:g" \
-e "s:k2_dir:$k2_dir:g" > $tmpfile

cfg="$k2_dir/scripts/googletest.cfg"

echo "Running cppcheck ......"

source $k2_dir/scripts/utils.sh

cppcheck \
-q \
--enable=style \
-i $build_dir/_deps \
--library="$cfg" \
--suppressions-list="$tmpfile" \
--project=$build_dir/compile_commands.json \
--error-exitcode=1 \
--template='{file}:{line},{severity},{id},{message}'

if [ $? -ne 0 ]; then
error "cppcheck failed, please check the error message."
else
ok "Great! cppcheck passed!"
fi

# cppcheck is optional.
# we always return 0.
exit 0
3 changes: 3 additions & 0 deletions scripts/suppressions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*:build_dir/_deps/*
unusedFunction:k2_dir/k2/csrc/*_test.cc
useStlAlgorithm:k2_dir/k2/csrc/properties.cc
19 changes: 19 additions & 0 deletions scripts/utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

default='\033[0m'
bold='\033[1m'
red='\033[31m'
green='\033[32m'

function ok() {
printf "${bold}${green}[OK]${default} $1\n"
}

function error() {
printf "${bold}${red}[FAILED]${default} $1\n"
}

function abort() {
printf "${bold}${red}[FAILED]${default} $1\n"
exit 1
}