From 51208ac4f53df154da70befe2c5beee66c3645b5 Mon Sep 17 00:00:00 2001 From: Arne Morten Kvarving Date: Fri, 9 Jun 2017 13:29:06 +0200 Subject: [PATCH] add static analysis support --- applications/CMakeLists.txt | 11 +++++ cmake/Modules/FindClangCheck.cmake | 11 +++++ cmake/Modules/FindCppCheck.cmake | 12 ++++++ cmake/Modules/UseStaticAnalysis.cmake | 52 +++++++++++++++++++++++ cmake/Scripts/clang-check-test.sh.in | 23 +++++++++++ cmake/Scripts/cppcheck-test.sh | 31 ++++++++++++++ src/opm/parser/eclipse/CMakeLists.txt | 59 +++++++++++++++++---------- 7 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 cmake/Modules/FindClangCheck.cmake create mode 100644 cmake/Modules/FindCppCheck.cmake create mode 100644 cmake/Modules/UseStaticAnalysis.cmake create mode 100755 cmake/Scripts/clang-check-test.sh.in create mode 100755 cmake/Scripts/cppcheck-test.sh diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt index 5aaf320d2..a6f263712 100644 --- a/applications/CMakeLists.txt +++ b/applications/CMakeLists.txt @@ -3,3 +3,14 @@ project(opm-parser-applications CXX) add_executable(opmi opmi.cpp) target_link_libraries(opmi opmparser) install(TARGETS opmi DESTINATION ${CMAKE_INSTALL_BINDIR}) + +set(app_src ${PROJECT_SOURCE_DIR}/opmi.cpp) +get_property(app_includes_all TARGET opmparser PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +foreach(prop ${app_includes_all}) + string(REGEX REPLACE "^.*BUILD_INTERFACE:([^>]*)>.*" "\\1" incl "${prop}") + if(NOT incl MATCHES "<") + list(APPEND app_includes ${incl}) + endif() +endforeach() + +add_static_analysis_tests(app_src app_includes) diff --git a/cmake/Modules/FindClangCheck.cmake b/cmake/Modules/FindClangCheck.cmake new file mode 100644 index 000000000..10a7ac02a --- /dev/null +++ b/cmake/Modules/FindClangCheck.cmake @@ -0,0 +1,11 @@ +# Find clang-check. +# +# This module defines: +# CLANGCHECK_PROGRAM, the clang-check executable. +# CLANGHCECK_FOUND, If false, do not try to use cppcheck. +# +find_program(CLANGCHECK_PROGRAM NAMES clang-check clang-check-3.8) + +find_package_handle_standard_args(ClangCheck DEFAULT_MSG CLANGCHECK_PROGRAM) + +mark_as_advanced(CLANGCHECK_PROGRAM) diff --git a/cmake/Modules/FindCppCheck.cmake b/cmake/Modules/FindCppCheck.cmake new file mode 100644 index 000000000..541830fe7 --- /dev/null +++ b/cmake/Modules/FindCppCheck.cmake @@ -0,0 +1,12 @@ +# Find CppCheck. +# +# This module defines: +# CPPCHECK_PROGRAM, the cppcheck executable. +# CPPCHECK_FOUND, If false, do not try to use cppcheck. +# +find_program(CPPCHECK_PROGRAM NAMES cppcheck) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CppCheck DEFAULT_MSG CPPCHECK_PROGRAM) + +mark_as_advanced(CPPCHECK_PROGRAM) diff --git a/cmake/Modules/UseStaticAnalysis.cmake b/cmake/Modules/UseStaticAnalysis.cmake new file mode 100644 index 000000000..18af0d766 --- /dev/null +++ b/cmake/Modules/UseStaticAnalysis.cmake @@ -0,0 +1,52 @@ +# Add static analysis tests for a given source file + +macro(setup_static_analysis_tools) + find_package(CppCheck) + if(CMAKE_EXPORT_COMPILE_COMMANDS) + find_package(ClangCheck) + else() + message(STATUS "Disabling clang-check as CMAKE_EXPORT_COMPILE_COMMANDS is not enabled") + endif() + if(OPM_COMMON_ROOT) + set(DIR ${OPM_COMMON_ROOT}) + elseif(OPM_MACROS_ROOT) + set(DIR ${OPM_MACROS_ROOT}) + else() + set(DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + if(CPPCHECK_FOUND) + file(COPY ${DIR}/cmake/Scripts/cppcheck-test.sh + DESTINATION bin + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + endif() + if(CLANGCHECK_FOUND AND CMAKE_EXPORT_COMPILE_COMMANDS) + configure_file(${DIR}/cmake/Scripts/clang-check-test.sh.in + ${CMAKE_BINARY_DIR}/CMakeFiles/clang-check-test.sh) + file(COPY ${CMAKE_BINARY_DIR}/CMakeFiles/clang-check-test.sh + DESTINATION bin + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + endif() + set(CPPCHECK_SCRIPT ${PROJECT_BINARY_DIR}/bin/cppcheck-test.sh) + set(CLANGCHECK_SCRIPT ${PROJECT_BINARY_DIR}/bin/clang-check-test.sh) +endmacro() + +function(add_static_analysis_tests sources includes) + if(CPPCHECK_FOUND OR (CLANGCHECK_FOUND AND CMAKE_EXPORT_COMPILE_COMMANDS)) + foreach(dep ${${includes}}) + list(APPEND IPATHS -I ${dep}) + endforeach() + foreach(src ${${sources}}) + file(RELATIVE_PATH name ${PROJECT_SOURCE_DIR} ${src}) + if(CPPCHECK_FOUND AND UNIX) + add_test(NAME cppcheck+${name} + COMMAND ${CPPCHECK_SCRIPT} ${CPPCHECK_PROGRAM} ${src} ${IPATHS} + CONFIGURATIONS analyze cppcheck) + endif() + if(CLANGCHECK_FOUND AND CMAKE_EXPORT_COMPILE_COMMANDS AND UNIX) + add_test(NAME clang-check+${name} + COMMAND ${CLANGCHECK_SCRIPT} ${CLANGCHECK_PROGRAM} ${src} + CONFIGURATIONS analyze clang-check) + endif() + endforeach() + endif() +endfunction() diff --git a/cmake/Scripts/clang-check-test.sh.in b/cmake/Scripts/clang-check-test.sh.in new file mode 100755 index 000000000..5312a451f --- /dev/null +++ b/cmake/Scripts/clang-check-test.sh.in @@ -0,0 +1,23 @@ +#!/bin/bash + +# This script performs a single analysis using clang-check +# It is used by the 'make test' target in the buildsystems +# Usually you should use 'ctest -C clang-check' rather than calling this script directly +# +# Parameters: $1 = Application binary +# $2 = Source file to process + +clangcheck_cmd=$1 +source_file=$2 + +tmpfil=$(mktemp) +$clangcheck_cmd -p @CMAKE_BINARY_DIR@ -analyze $source_file &> $tmpfil +cat $tmpfil +if test -s $tmpfil +then + rm $tmpfil + exit 1 +fi + +rm $tmpfil +exit 0 diff --git a/cmake/Scripts/cppcheck-test.sh b/cmake/Scripts/cppcheck-test.sh new file mode 100755 index 000000000..5c8821729 --- /dev/null +++ b/cmake/Scripts/cppcheck-test.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# This script performs a single analysis using cppcheck +# It is used by the 'make test' target in the buildsystems +# Usually you should use 'ctest -C cppcheck' rather than calling this script directly +# +# Parameters: $1 = Application binary +# $2 = Source file to process +# $3..$N = include path parameters (-I dir1 -I dir2 ...) + +cppcheck_cmd=$1 +source_file=$2 +shift 2 + +tmpfil=$(mktemp) +$cppcheck_cmd $@ --inline-suppr --enable=all --suppress=unusedFunction $source_file &> $tmpfil + +declare -a ignorere +ignorere=(\\[/usr.*\\] + \\[\\*\\] + \\[.*Too.many.\#ifdef) + +nmatch=$(cat $tmpfil | grep "\[.*\]" | wc -l) +for RE in ${ignorere[*]} +do + nign=$(cat $tmpfil | grep "$RE" | wc -l) + let "nmatch=$nmatch-$nign" +done +cat $tmpfil +rm $tmpfil +test $nmatch -eq 0 || exit 1 diff --git a/src/opm/parser/eclipse/CMakeLists.txt b/src/opm/parser/eclipse/CMakeLists.txt index c5eb76b74..ae2b49797 100644 --- a/src/opm/parser/eclipse/CMakeLists.txt +++ b/src/opm/parser/eclipse/CMakeLists.txt @@ -1,25 +1,26 @@ project(opm-parser-eclipse CXX) -add_executable(genkw Parser/createDefaultKeywordList.cpp - Deck/Deck.cpp - Deck/DeckItem.cpp - Deck/DeckKeyword.cpp - Deck/DeckRecord.cpp - Generator/KeywordGenerator.cpp - Generator/KeywordLoader.cpp - Parser/MessageContainer.cpp - Parser/ParseContext.cpp - Parser/ParserEnums.cpp - Parser/ParserItem.cpp - Parser/ParserKeyword.cpp - Parser/ParserRecord.cpp - RawDeck/RawKeyword.cpp - RawDeck/RawRecord.cpp - RawDeck/StarToken.cpp - Units/Dimension.cpp - Units/UnitSystem.cpp - Utility/Stringview.cpp +set(genkw_SOURCES Parser/createDefaultKeywordList.cpp + Deck/Deck.cpp + Deck/DeckItem.cpp + Deck/DeckKeyword.cpp + Deck/DeckRecord.cpp + Generator/KeywordGenerator.cpp + Generator/KeywordLoader.cpp + Parser/MessageContainer.cpp + Parser/ParseContext.cpp + Parser/ParserEnums.cpp + Parser/ParserItem.cpp + Parser/ParserKeyword.cpp + Parser/ParserRecord.cpp + RawDeck/RawKeyword.cpp + RawDeck/RawRecord.cpp + RawDeck/StarToken.cpp + Units/Dimension.cpp + Units/UnitSystem.cpp + Utility/Stringview.cpp ) +add_executable(genkw ${genkw_SOURCES}) target_link_libraries(genkw opmjson ecl boost_regex) target_include_directories(genkw PRIVATE include) @@ -42,8 +43,7 @@ add_custom_command( ) #----------------------------------------------------------------- - -add_library(opmparser Deck/Deck.cpp +set(opmparser_SOURCES Deck/Deck.cpp Deck/DeckItem.cpp Deck/DeckKeyword.cpp Deck/DeckRecord.cpp @@ -124,6 +124,8 @@ add_library(opmparser Deck/Deck.cpp ${CMAKE_CURRENT_BINARY_DIR}/ParserKeywords.cpp ) +add_library(opmparser ${opmparser_SOURCES}) + target_link_libraries(opmparser PUBLIC opmjson ecl boost_filesystem @@ -138,6 +140,21 @@ target_include_directories(opmparser PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include ) +set(opmparser_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include + ${Boost_INCLUDE_DIRS}) + +list(APPEND opmparser_SOURCES ${genkw_SOURCES}) +list(REMOVE_DUPLICATES opmparser_SOURCES) +foreach(src ${opmparser_SOURCES}) + if (src MATCHES "^/") + list(APPEND opmparser_SRC ${src}) + else() + list(APPEND opmparser_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${src}) + endif() +endforeach() +add_static_analysis_tests(opmparser_SRC opmparser_INCLUDES) + install(TARGETS opmparser EXPORT opm-parser-config ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}