Mercurial > malikania
changeset 54:0edaba9986ba
CMake: add vera++, closes 602
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 16 Dec 2016 13:59:55 +0100 |
parents | fe7e3524e571 |
children | 576c35ccdff6 |
files | CMakeLists.txt cmake/MalikaniaOptions.cmake cmake/function/MalikaniaDefineExecutable.cmake cmake/function/MalikaniaDefineLibrary.cmake cmake/function/MalikaniaDefineTest.cmake cmake/function/MalikaniaVeraCheck.cmake vera/profiles/default vera/rules/L001.tcl vera/rules/L002.tcl vera/rules/L003.tcl vera/rules/L004.tcl vera/rules/L005.tcl vera/rules/T003.tcl vera/rules/T004.tcl vera/rules/T005.tcl vera/rules/T006.tcl vera/rules/T008.tcl vera/rules/T017.tcl vera/rules/T018.tcl vera/rules/T019.tcl |
diffstat | 20 files changed, 425 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Fri Dec 16 13:07:44 2016 +0100 +++ b/CMakeLists.txt Fri Dec 16 13:59:55 2016 +0100 @@ -35,6 +35,7 @@ include(cmake/function/MalikaniaDefineExecutable.cmake) include(cmake/function/MalikaniaDefineTest.cmake) include(cmake/function/MalikaniaSetg.cmake) +include(cmake/function/MalikaniaVeraCheck.cmake) include(cmake/MalikaniaVersion.cmake) include(cmake/MalikaniaOptions.cmake) include(cmake/MalikaniaSystem.cmake) @@ -71,3 +72,4 @@ message("") message("Documentation:") message(" Doxygen: ${WITH_DOXYGEN_MSG}") +message(" Vera: ${WITH_VERA_MSG}")
--- a/cmake/MalikaniaOptions.cmake Fri Dec 16 13:07:44 2016 +0100 +++ b/cmake/MalikaniaOptions.cmake Fri Dec 16 13:59:55 2016 +0100 @@ -68,6 +68,26 @@ endif () # +# Options for development. +# ------------------------------------------------------------------- +# + +option(WITH_VERA "Enable vera++ analyzer" On) + +find_program(VERA_EXECUTABLE vera++) + +if (VERA_EXECUTABLE) + if (WITH_VERA) + malikania_setg(WITH_VERA_MSG "Yes") + else () + malikania_setg(WITH_MSG Off) + malikania_setg(WITH_VERA_MSG "No (vera++ not found)") + endif () +else () + malikania_setg(WITH_VERA_MSG "No (disabled by user)") +endif () + +# # Options for unit tests # ------------------------------------------------------------------- #
--- a/cmake/function/MalikaniaDefineExecutable.cmake Fri Dec 16 13:07:44 2016 +0100 +++ b/cmake/function/MalikaniaDefineExecutable.cmake Fri Dec 16 13:59:55 2016 +0100 @@ -34,6 +34,8 @@ include(CMakeParseArguments) +include(${CMAKE_CURRENT_LIST_DIR}/MalikaniaVeraCheck.cmake) + function(malikania_define_executable) set(singleArgs TARGET) set(multiArgs SOURCES FLAGS INCLUDES LIBRARIES) @@ -64,4 +66,6 @@ RUNTIME_OUTPUT_DIRECTORY_${c} ${WITH_FAKEROOT_DIR}/bin ) endforeach() + + malikania_vera_check(${EXE_TARGET} ${EXE_SOURCES}) endfunction()
--- a/cmake/function/MalikaniaDefineLibrary.cmake Fri Dec 16 13:07:44 2016 +0100 +++ b/cmake/function/MalikaniaDefineLibrary.cmake Fri Dec 16 13:59:55 2016 +0100 @@ -37,6 +37,7 @@ include(CMakeParseArguments) include(${CMAKE_CURRENT_LIST_DIR}/MalikaniaBuildAssets.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/MalikaniaVeraCheck.cmake) function(malikania_define_library) set(singleArgs TARGET) @@ -69,4 +70,6 @@ ${LIB_PUBLIC_INCLUDES} ) target_compile_definitions(${LIB_TARGET} PRIVATE ${LIB_FLAGS}) + + malikania_vera_check(${LIB_TARGET} ${LIB_SOURCES}) endfunction()
--- a/cmake/function/MalikaniaDefineTest.cmake Fri Dec 16 13:07:44 2016 +0100 +++ b/cmake/function/MalikaniaDefineTest.cmake Fri Dec 16 13:59:55 2016 +0100 @@ -33,6 +33,8 @@ include(CMakeParseArguments) +include(${CMAKE_CURRENT_LIST_DIR}/MalikaniaVeraCheck.cmake) + function(malikania_create_test) set(singleArgs NAME) set(multiArgs LIBRARIES SOURCES RESOURCES) @@ -98,4 +100,6 @@ ) add_dependencies(tests test-${TEST_NAME}) + + malikania_vera_check(test-${TEST_NAME} ${TEST_SOURCES}) endfunction()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/function/MalikaniaVeraCheck.cmake Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,29 @@ +# +# MalikaniaVeraCheck.cmake -- CMake build system for malikania +# +# Copyright (c) 2013-2016 Malikania Authors +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +function(malikania_vera_check target sources) + if (WITH_VERA) + add_custom_command( + TARGET ${target} + COMMAND + ${VERA_EXECUTABLE} -w --root ${CMAKE_SOURCE_DIR}/vera ${sources} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM + ) + endif () +endfunction()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/profiles/default Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,15 @@ +rule=L001 +rule=L002 +rule=L003 +rule=L004 +parameter=max-line-length=120 +rule=L005 +parameter=max-consecutive-empty-lines=1 +rule=T003 +rule=T004 +rule=T005 +rule=T006 +rule=T008 +rule=T017 +rule=T018 +rule=T019
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/L001.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,24 @@ +#!/usr/bin/tclsh +# No trailing whitespace + +set strictMode [getParameter "strict-trailing-space" 0] + +foreach f [getSourceFileNames] { + set lineNumber 1 + set previousIndent "" + foreach line [getAllLines $f] { + + if [regexp {^.*\r$} $line] { + report $f $lineNumber "CRLF line ending" + set line [string range $line 0 end-1] + } + if [regexp {^.*[[:space:]]+$} $line] { + if {$strictMode || [string trim $line] != "" || $line != $previousIndent} { + report $f $lineNumber "trailing whitespace" + } + } + + regexp {^([[:space:]]*).*$} $line dummy previousIndent + incr lineNumber + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/L002.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,14 @@ +#!/usr/bin/tclsh +# Don't use tab characters + +foreach f [getSourceFileNames] { + set lineNumber 1 + foreach line [getAllLines $f] { + + if [regexp {\t} $line] { + report $f $lineNumber "horizontal tab used" + } + + incr lineNumber + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/L003.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,17 @@ +#!/usr/bin/tclsh +# No leading and no trailing empty lines + +foreach f [getSourceFileNames] { + set lineCount [getLineCount $f] + if {$lineCount > 0} { + set firstLine [getLine $f 1] + if {[string trim $firstLine] == ""} { + report $f 1 "leading empty line(s)" + } + + set lastLine [getLine $f $lineCount] + if {[string trim $lastLine] == ""} { + report $f $lineCount "trailing empty line(s)" + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/L004.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,14 @@ +#!/usr/bin/tclsh +# Line cannot be too long + +set maxLength [getParameter "max-line-length" 100] + +foreach f [getSourceFileNames] { + set lineNumber 1 + foreach line [getAllLines $f] { + if {[string length $line] > $maxLength} { + report $f $lineNumber "line is longer than ${maxLength} characters" + } + incr lineNumber + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/L005.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,23 @@ +#!/usr/bin/tclsh +# There should not be too many consecutive empty lines + +set maxEmptyLines [getParameter "max-consecutive-empty-lines" 2] + +foreach f [getSourceFileNames] { + set lineNumber 1 + set emptyCount 0 + set reported false + foreach line [getAllLines $f] { + if {[string trim $line] == ""} { + incr emptyCount + if {$emptyCount > $maxEmptyLines && $reported == "false"} { + report $f $lineNumber "too many consecutive empty lines" + set reported true + } + } else { + set emptyCount 0 + set reported false + } + incr lineNumber + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T003.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,47 @@ +#!/usr/bin/tclsh +# Some keywords should be followed by a single space + +set keywords { + case + class + enum + explicit + extern + goto + new + struct + union + using +} + +proc isKeyword {s} { + global keywords + return [expr [lsearch $keywords $s] != -1] +} + +set state "other" +foreach f [getSourceFileNames] { + foreach t [getTokens $f 1 0 -1 -1 {}] { + set tokenValue [lindex $t 0] + set tokenName [lindex $t 3] + if {$state == "keyword"} { + if {$tokenName == "space" && $tokenValue == " "} { + set state "space" + } else { + report $f $lineNumber "keyword \'${keywordValue}\' not followed by a single space" + set state "other" + } + } elseif {$state == "space"} { + if {$tokenName == "newline"} { + report $f $lineNumber "keyword \'${keywordValue}\' not followed by a single space" + } + set state "other" + } else { + if [isKeyword $tokenName] { + set state "keyword" + set lineNumber [lindex $t 1] + set keywordValue [lindex $t 0] + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T004.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,51 @@ +#!/usr/bin/tclsh +# Some keywords should be immediately followed by a colon + +set keywords { + default + private + protected + public +} + +proc isKeyword {s} { + global keywords + return [expr [lsearch $keywords $s] != -1] +} + +foreach f [getSourceFileNames] { + set lastKeywordLine 0 + set lastKeywordColumn 0 + set lastKeywordValue "" + set last "" + foreach t [getTokens $f 1 0 -1 -1 [concat $keywords colon]] { + set tokenValue [lindex $t 0] + set tokenName [lindex $t 3] + if {$tokenName == "colon"} { + if {$last == "keyword" && $lastKeywordLine != 0} { + set line [lindex $t 1] + set column [lindex $t 2] + if {$line != $lastKeywordLine || + $column != [expr $lastKeywordColumn + [string length $lastKeywordValue]]} { + set nonWhiteFound "false" + foreach tb [getTokens $f $lastKeywordLine [expr $lastKeywordColumn + 1] $line $column {}] { + set tbName [lindex $tb 3] + if {[lsearch {space newline ccomment cppcomment} $tbName] == -1} { + set nonWhiteFound "true" + break + } + } + if {$nonWhiteFound == "false"} { + report $f $line "colon not immediately after the \'$lastKeywordValue\' keyword" + } + } + } + set last "colon" + } else { + set lastKeywordLine [lindex $t 1] + set lastKeywordColumn [lindex $t 2] + set lastKeywordValue $tokenValue + set last "keyword" + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T005.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,19 @@ +#!/usr/bin/tclsh +# Keywords break and continue should be immediately followed by a semicolon + +foreach f [getSourceFileNames] { + foreach t [getTokens $f 1 0 -1 -1 {break continue}] { + set keyword [lindex $t 0] + set line [lindex $t 1] + set column [lindex $t 2] + set semicolons [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] 0 {semicolon}] + if {$semicolons == {}} { + report $f $line "keyword '${keyword}' not immediately followed by a semicolon" + } else { + set semColumn [lindex [lindex $semicolons 0] 2] + if {$semColumn != $column + [string length $keyword]} { + report $f $line "keyword '${keyword}' not immediately followed by a semicolon" + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T006.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,21 @@ +#!/usr/bin/tclsh +# Keywords return and throw should be immediately followed by a semicolon or a single space + +foreach f [getSourceFileNames] { + foreach t [getTokens $f 1 0 -1 -1 {return throw}] { + set keyword [lindex $t 0] + set line [lindex $t 1] + set column [lindex $t 2] + set followingTokens [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] 0 {}] + if {$followingTokens == {}} { + report $f $line "keyword '${keyword}' not immediately followed by a semicolon or a single space" + } else { + set first [lindex [lindex $followingTokens 0] 0] + if {$first != ";" && $first != " "} { + if {!([llength $followingTokens] >= 2 && $keyword == "throw" && $first == "(" && [lindex [lindex $followingTokens 1] 0] == ")")} { + report $f $line "keyword '${keyword}' not immediately followed by a semicolon or a single space" + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T008.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,24 @@ +#!/usr/bin/tclsh +# Keywords catch, for, if and while should be followed by a single space + +foreach f [getSourceFileNames] { + set pp_pragma_line -1 + foreach t [getTokens $f 1 0 -1 -1 {catch for if switch while pp_pragma}] { + set keyword [lindex $t 0] + set line [lindex $t 1] + set column [lindex $t 2] + set type [lindex $t 3] + if {$type == "pp_pragma"} { + set pp_pragma_line $line + } elseif {$pp_pragma_line != $line} { + set followingTokens [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] -1 {}] + if {[llength $followingTokens] < 2} { + report $f $line "keyword '${keyword}' not followed by a single space" + } else { + if {[list [lindex [lindex $followingTokens 0] 0] [lindex [lindex $followingTokens 1] 0]] != [list " " "("]} { + report $f $line "keyword '${keyword}' not followed by a single space" + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T017.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,23 @@ +#!/usr/bin/tclsh +# Unnamed namespaces are not allowed in header files + +foreach fileName [getSourceFileNames] { + set extension [file extension $fileName] + if {[lsearch {.h .hh .hpp .hxx .ipp} $extension] != -1} { + + set state "start" + foreach token [getTokens $fileName 1 0 -1 -1 {namespace identifier leftbrace}] { + set type [lindex $token 3] + + if {$state == "namespace" && $type == "leftbrace"} { + report $fileName $namespaceLine "unnamed namespace not allowed in header file" + } + + if {$type == "namespace"} { + set namespaceLine [lindex $token 1] + } + + set state $type + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T018.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,23 @@ +#!/usr/bin/tclsh +# using namespace are not allowed in header files + +foreach fileName [getSourceFileNames] { + set extension [file extension $fileName] + if {[lsearch {.h .hh .hpp .hxx .ipp} $extension] != -1} { + + set state "start" + foreach token [getTokens $fileName 1 0 -1 -1 {using namespace identifier}] { + set type [lindex $token 3] + + if {$state == "using" && $type == "namespace"} { + report $fileName $usingLine "using namespace not allowed in header file" + } + + if {$type == "using"} { + set usingLine [lindex $token 1] + } + + set state $type + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vera/rules/T019.tcl Fri Dec 16 13:59:55 2016 +0100 @@ -0,0 +1,48 @@ +#!/usr/bin/tclsh +# control structures should have complete curly-braced block of code + +foreach fileName [getSourceFileNames] { + + set state "start" + set prev "" + set pp_pragma_line -1 + foreach token [getTokens $fileName 1 0 -1 -1 {for if while do else leftparen rightparen leftbrace rightbrace semicolon pp_pragma}] { + set type [lindex $token 3] + set line [lindex $token 1] + + if {$state == "control"} { + if {$type == "leftparen"} { + incr parenCount + } elseif {$type == "rightparen"} { + incr parenCount -1 + if {$parenCount == 0} { + set state "expectedblock" + } + } + + } elseif {$state == "expectedblock"} { + if {$prev == "else" && $type == "if" } { + # skip + } elseif {$type != "leftbrace"} { + set line [lindex $token 1] + report $fileName $line "full block {} expected in the control structure" + } + set state "block" + } + + if {$type == "pp_pragma"} { + set pp_pragma_line $line + } elseif {$pp_pragma_line != $line} { + if {$type == "for" || $type == "if"} { + set parenCount 0 + set state "control" + } elseif {$type == "do" || $type == "else"} { + set state "expectedblock" + } elseif {$type == "while" && $prev != "rightbrace"} { + set parenCount 0 + set state "control" + } + } + set prev $type + } +}