diff --git a/build/static-checkers/add_cppcheck_for_target.cmake b/build/static-checkers/add_cppcheck_for_target.cmake index bd764d436..c3d1e5e46 100644 --- a/build/static-checkers/add_cppcheck_for_target.cmake +++ b/build/static-checkers/add_cppcheck_for_target.cmake @@ -13,7 +13,7 @@ # limitations under the License. # Cppcheck launcher - set(CMAKE_CPPCHECK ${CMAKE_SOURCE_DIR}/tools/cppcheck.sh) + set(CMAKE_CPPCHECK ${CMAKE_SOURCE_DIR}/tools/cppcheck/cppcheck.sh) # Definition of cppcheck targets add_custom_target(cppcheck) diff --git a/tools/cppcheck.sh b/tools/cppcheck/cppcheck.sh similarity index 74% rename from tools/cppcheck.sh rename to tools/cppcheck/cppcheck.sh index 9e36dc0df..7e2755f57 100755 --- a/tools/cppcheck.sh +++ b/tools/cppcheck/cppcheck.sh @@ -14,14 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -BASE=$(dirname $0)/../third-party/tools/cppcheck +REPOSITORY_DIR=$(dirname $0)/../.. +CPPCHECK=$REPOSITORY_DIR/third-party/cppcheck/cppcheck +SUPPRESSIONS_LIST=$(dirname $0)/suppressions-list -if [ ! -x $BASE/$(uname -m)/cppcheck ] +if [ ! -x $CPPCHECK ] then exit 1; fi -$BASE/$(uname -m)/cppcheck "$@" "--exitcode-suppressions=$BASE/cfg/suppressions-list" +$CPPCHECK "$@" "--exitcode-suppressions=$SUPPRESSIONS_LIST" status_code=$? exit $status_code diff --git a/tools/cppcheck/suppressions-list b/tools/cppcheck/suppressions-list new file mode 100644 index 000000000..b02af84f1 --- /dev/null +++ b/tools/cppcheck/suppressions-list @@ -0,0 +1 @@ +operatorEqVarError diff --git a/tools/precommit.sh b/tools/precommit.sh index 654a24ba0..d631ee83c 100755 --- a/tools/precommit.sh +++ b/tools/precommit.sh @@ -23,27 +23,18 @@ shift TARGETS="$1" shift -PARSE_ONLY_TESTING_PATHS="./tests/benchmarks/jerry" -FULL_TESTING_PATHS="./tests/jerry ./tests/jerry-test-suite/precommit_test_list" +VERA_DIRECTORIES_EXCLUDE_LIST="-path ./third-party -o -path tests" +VERA_CONFIGURATION_PATH="./tools/vera++" -VERA=`which vera++` -if [ -x "$VERA" ] +SOURCES_AND_HEADERS_LIST=`find . -type d \( $VERA_DIRECTORIES_EXCLUDE_LIST \) -prune -or -name "*.c" -or -name "*.cpp" -or -name "*.h"` +./tools/vera++/vera.sh -r $VERA_CONFIGURATION_PATH -p jerry $SOURCES_AND_HEADERS_LIST -e --no-duplicate +STATUS_CODE=$? + +if [ $STATUS_CODE -ne 0 ] then - VERA_DIRECTORIES_EXCLUDE_LIST="-path ./third-party -o -path tests" - VERA_SCRIPTS_PATH="./tools/vera++" + echo -e "\e[1;33m vera++ static checks failed. See output above for details. \e[0m\n" - SOURCES_AND_HEADERS_LIST=`find . -type d \( $VERA_DIRECTORIES_EXCLUDE_LIST \) -prune -or -name "*.c" -or -name "*.cpp" -or -name "*.h"` - vera++ -r $VERA_SCRIPTS_PATH -p jerry $SOURCES_AND_HEADERS_LIST -e --no-duplicate - STATUS_CODE=$? - - if [ $STATUS_CODE -ne 0 ] - then - echo -e "\e[1;33m vera++ static checks failed. See output above for details. \e[0m\n" - - exit $STATUS_CODE - fi -else - echo -e "\e[1;33m Warning: vera++ not installed, skipping corresponding static checks. \e[0m\n" + exit $STATUS_CODE fi echo -e "\nBuilding...\n\n" diff --git a/tools/vera++/profiles/jerry b/tools/vera++/profiles/jerry new file mode 100644 index 000000000..3865531f9 --- /dev/null +++ b/tools/vera++/profiles/jerry @@ -0,0 +1,4 @@ +set rules { + jerry_indentation + jerry_switch_case +} diff --git a/tools/vera++/scripts/rules/jerry_indentation.tcl b/tools/vera++/scripts/rules/jerry_indentation.tcl new file mode 100644 index 000000000..96a60fd37 --- /dev/null +++ b/tools/vera++/scripts/rules/jerry_indentation.tcl @@ -0,0 +1,106 @@ +#!/usr/bin/tclsh + +# Copyright 2014-2015 Samsung Electronics Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Indentation + +foreach fileName [getSourceFileNames] { + set indent 0 + set lastCheckedLineNumber -1 + set is_in_comment "no" + set is_in_pp_define "no" + set is_in_class "no" + set parentheses_level 0 + + foreach token [getTokens $fileName 1 0 -1 -1 {}] { + set type [lindex $token 3] + set lineNumber [lindex $token 1] + + if {$is_in_comment == "yes"} { + set is_in_comment "no" + } + + if {$type == "newline"} { + set is_in_pp_define "no" + } elseif {$type == "class"} { + set is_in_class "yes" + } elseif {$is_in_class == "yes" && $type == "semicolon" && $indent == 0} { + set is_in_class "no" + } elseif {$type == "ccomment"} { + set is_in_comment "yes" + } elseif {[string first "pp_" $type] == 0} { + if {$type == "pp_define"} { + set is_in_pp_define "yes" + } + + set lastCheckedLineNumber $lineNumber + } elseif {$type == "space"} { + } elseif {$type != "eof"} { + if {$type == "rightbrace"} { + incr indent -2 + } + + if {$is_in_pp_define == "no" && $is_in_comment == "no" && $is_in_class == "no" && $parentheses_level == 0} { + set line [getLine $fileName $lineNumber] + + if {$lineNumber != $lastCheckedLineNumber} { + if {[string length $line] == 0} { + } + + if {[regexp {^[[:blank:]]*} $line match]} { + set real_indent [string length $match] + if {$indent != $real_indent} { + if {![regexp {^[[:alnum:]_]{1,}:$} $line] || $real_indent != 0} { + report $fileName $lineNumber "Indentation: $real_indent -> $indent. Line: '$line'" + } + } + } + } + + if {$lineNumber == $lastCheckedLineNumber} { + if {$type == "leftbrace"} { + if {![regexp {^[[:blank:]]*\{[[:blank:]]*$} $line] + && ![regexp {[^\{=]=[^\{=]\{.*\},?} $line]} { + report $fileName $lineNumber "Left brace is not the only non-space character in the line: '$line'" + } + } + if {$type == "rightbrace"} { + if {![regexp {^.* = .*\{.*\}[,;]?$} $line] + && ![regexp {[^\{=]=[^\{=]\{.*\}[,;]?} $line]} { + report $fileName $lineNumber "Right brace is not first non-space character in the line: '$line'" + } + } + } + if {$type == "rightbrace"} { + if {![regexp {^[[:blank:]]*\}((( [a-z_\(][a-z0-9_\(\)]{0,}){1,})?;| /\*.*\*/| //.*)?$} $line] + && ![regexp {[^\{=]=[^\{=]\{.*\}[,;]?} $line]} { + report $fileName $lineNumber "Right brace is not the only non-space character in the line and \ + is not single right brace followed by \[a-z0-9_() \] string and single semicolon character: '$line'" + } + } + } + + if {$type == "leftbrace"} { + incr indent 2 + } elseif {$type == "leftparen"} { + incr parentheses_level 1 + } elseif {$type == "rightparen"} { + incr parentheses_level -1 + } + + set lastCheckedLineNumber $lineNumber + } + } +} diff --git a/tools/vera++/scripts/rules/jerry_switch_case.tcl b/tools/vera++/scripts/rules/jerry_switch_case.tcl new file mode 100644 index 000000000..30cfb27a5 --- /dev/null +++ b/tools/vera++/scripts/rules/jerry_switch_case.tcl @@ -0,0 +1,273 @@ +#!/usr/bin/tclsh + +# Copyright 2014-2015 Samsung Electronics Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# switch-case + +foreach fileName [getSourceFileNames] { + set is_in_comment "no" + set is_in_pp_define "no" + + foreach token [getTokens $fileName 1 0 -1 -1 {}] { + set type [lindex $token 3] + set lineNumber [lindex $token 1] + + if {$is_in_comment == "yes"} { + set is_in_comment "no" + } + + if {$type == "newline"} { + set is_in_pp_define "no" + } elseif {$type == "ccomment"} { + set is_in_comment "yes" + } elseif {[string first "pp_" $type] == 0} { + if {$type == "pp_define"} { + set is_in_pp_define "yes" + } + } elseif {$type == "space"} { + } elseif {$type != "eof"} { + if {$is_in_pp_define == "no" && $type == "switch"} { + set next_token_start [lindex $token 2] + incr next_token_start 1 + set line_num 0 + set state "switch" + set case_block "no" + set seen_braces 0 + foreach next_token [getTokens $fileName $lineNumber $next_token_start -1 -1 {}] { + set next_token_type [lindex $next_token 3] + set next_token_value [lindex $next_token 0] + if {$state == "switch"} { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "leftbrace"} { + set state "first-case" + continue + } else { + # TODO: check switch + continue + } + } elseif {$state == "first-case"} { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "case"} { + set state "case" + continue + } elseif {$next_token_type == "default"} { + set state "default" + continue + } else { + # Macros magic: give up + break + } + } elseif {$state == "case"} { + if {$next_token_type == "space"} { + set state "space-after-case" + continue + } else { + report $fileName [lindex $next_token 1] "There should be single space character after 'case' keyword (state $state)" + } + } elseif {$state == "space-after-case"} { + if {$next_token_type != "identifier" && $next_token_type != "intlit" && $next_token_type != "charlit" && $next_token_type != "sizeof"} { + report $fileName [lindex $next_token 1] "There should be single space character after 'case' keyword (state $state, next_token_type $next_token_type)" + } else { + set state "case-label" + continue + } + } elseif {$state == "case-label" || $state == "default"} { + set case_block "no" + if {$next_token_type != "colon"} { + continue + } else { + set state "colon" + continue + } + } elseif {$state == "after-colon-preprocessor"} { + if {$next_token_type == "newline"} { + set state "colon" + } + } elseif {$state == "colon"} { + if {$next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "ccomment"} { + if {[string match "*FALL*" $next_token_value]} { + set state "fallthru" + set line_num [lindex $next_token 1] + continue + } else { + continue + } + } elseif {$next_token_type == "case"} { + set state "case" + continue + } elseif {$next_token_type == "default"} { + set state "default" + continue + } elseif {$next_token_type == "leftbrace"} { + set case_block "yes" + set state "wait-for-break" + continue + } elseif {$next_token_type == "identifier"} { + if {[string compare "JERRY_UNREACHABLE" $next_token_value] == 0 + || [string first "JERRY_UNIMPLEMENTED" $next_token_value] == 0} { + set state "wait-for-semicolon" + continue + } else { + set state "wait-for-break" + continue + } + } elseif {$next_token_type == "break" || $next_token_type == "return"} { + set state "wait-for-semicolon" + continue + } elseif {[string first "pp_" $next_token_type] == 0} { + set state "after-colon-preprocessor" + } else { + set state "wait-for-break" + continue + } + } elseif {$state == "wait-for-semicolon"} { + if {$next_token_type == "semicolon"} { + set state "break" + } + continue + } elseif {$state == "wait-for-break"} { + if {$next_token_type == "case" || $next_token_type == "default"} { + report $fileName [lindex $next_token 1] "Missing break or FALLTHRU comment before case (state $state)" + } elseif {$next_token_type == "leftbrace"} { + set state "inside-braces" + incr seen_braces 1 + continue + } elseif {$next_token_type == "rightbrace"} { + if {$case_block == "yes"} { + set state "case-blocks-end" + continue + } else { + break + } + } elseif {[string compare "JERRY_UNREACHABLE" $next_token_value] == 0 + || [string first "JERRY_UNIMPLEMENTED" $next_token_value] == 0} { + set state "wait-for-semicolon" + continue + } elseif {$next_token_type == "ccomment" && [string match "*FALL*" $next_token_value]} { + set state "fallthru" + set line_num [lindex $next_token 1] + continue + } elseif {$next_token_type == "break" || $next_token_type == "return" || $next_token_type == "goto"} { + set state "wait-for-semicolon" + continue + } + continue + } elseif {$state == "break" || $state == "fallthru"} { + if {$case_block == "no"} { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "case"} { + set state "case" + continue + } elseif {$next_token_type == "default"} { + set state "default" + continue + } elseif {$next_token_type == "leftbrace"} { + set state "inside-braces" + incr seen_braces 1 + continue + } elseif {$next_token_type == "rightbrace"} { + lappend switch_ends [lindex $next_token 1] + break + } elseif {$next_token_type == "break" || $next_token_type == "return"} { + set state "wait-for-semicolon" + continue + } else { + set state "wait-for-break" + continue + } + } else { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "case"} { + set state "case" + continue + } elseif {$next_token_type == "default"} { + set state "default" + continue + } elseif {$next_token_type == "leftbrace"} { + set state "inside-braces" + incr seen_braces 1 + continue + } elseif {$next_token_type == "rightbrace"} { + set state "after-rightbrace" + continue + } elseif {$next_token_type == "break" || $next_token_type == "return"} { + set state "wait-for-semicolon" + continue + } else { + set state "wait-for-break" + continue + } + } + } elseif {$state == "inside-braces"} { + if {$next_token_type == "rightbrace"} { + incr seen_braces -1 + if {$seen_braces == 0} { + set state "wait-for-break" + continue + } + } elseif {$next_token_type == "leftbrace"} { + incr seen_braces 1 + } + continue + } elseif {$state == "after-rightbrace-preprocessor"} { + if {$next_token_type == "newline"} { + set state "after-rightbrace" + } + } elseif {$state == "after-rightbrace"} { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "case"} { + set state "case" + continue + } elseif {$next_token_type == "default"} { + set state "default" + continue + } elseif {$next_token_type == "rightbrace"} { + lappend switch_ends [lindex $next_token 1] + break + } elseif {[string first "pp_" $next_token_type] == 0} { + set state "after-rightbrace-preprocessor" + } else { + report $fileName [lindex $next_token 1] "There should be 'case' or 'default' (state $state)" + } + } elseif {$state == "case-blocks-end-preprocessor"} { + if {$next_token_type == "newline"} { + set state "case-blocks-end" + } + } elseif {$state == "case-blocks-end"} { + if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { + continue + } elseif {$next_token_type == "rightbrace"} { + lappend switch_ends [lindex $next_token 1] + break + } elseif {[string first "pp_" $next_token_type] == 0} { + set state "case-blocks-end-preprocessor" + } else { + report $fileName [lindex $next_token 1] "Missing break or FALLTHRU comment before rightbrace (state $state)" + } + } else { + report $fileName [lindex $next_token 1] "Unknown state: $state" + } + } + } + } + } +} diff --git a/tools/vera++/vera.sh b/tools/vera++/vera.sh new file mode 100755 index 000000000..397b690dc --- /dev/null +++ b/tools/vera++/vera.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Copyright 2015 Samsung Electronics Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +REPOSITORY_DIR=$(dirname $0)/../.. +VERA=$REPOSITORY_DIR/third-party/vera++/bin/vera++ + +if [ ! -x $VERA ] +then + exit 1; +fi + +$VERA "$@" +status_code=$? + +exit $status_code