# - Run cppcheck on c++ source files as a custom target
# Simplification of
# https://github.com/rpavlik/cmake-modules/blob/master/CppcheckTargets.cmake

if(__add_cppcheck)
    return()
endif()
set(__add_cppcheck YES)

if(NOT CPPCHECK_FOUND)
    find_package(cppcheck QUIET)
endif()

if(NOT CPPCHECK_FOUND)
    add_custom_target(all_cppcheck
        COMMENT "cppcheck executable not found")
    set_target_properties(all_cppcheck PROPERTIES EXCLUDE_FROM_ALL TRUE)
elseif(CPPCHECK_VERSION VERSION_LESS 1.53.0)
    add_custom_target(all_cppcheck
        COMMENT "Need at least cppcheck 1.53, found ${CPPCHECK_VERSION}")
    set_target_properties(all_cppcheck PROPERTIES EXCLUDE_FROM_ALL TRUE)
    set(CPPCHECK_FOUND)
endif()

if(NOT TARGET all_cppcheck)
  add_custom_target(all_cppcheck)
endif()

set(CPPCHECK_FOLDER "${PROJECT_SOURCE_DIR}/cppcheck")
set(CPP_SUPP_FILE ${CPPCHECK_FOLDER}/cppcheck-supp.txt)
set(CPPCHECK_XML "${CPPCHECK_FOLDER}/xml")
file(MAKE_DIRECTORY ${CPPCHECK_XML})

add_custom_target(cppcheck_xml_report
    COMMAND
    "./merge_xml.py"
    WORKING_DIRECTORY
    "${CPPCHECK_FOLDER}"
    COMMENT
    "creating XML report"
    VERBATIM)
add_custom_target(cppcheck_html_report
    COMMAND
    "cppcheck-htmlreport"
    "--file=report.xml"
    "--report-dir=html"
    "--source-dir=.."
    WORKING_DIRECTORY
    "${CPPCHECK_FOLDER}"
    COMMENT
    "creating HTML report"
    VERBATIM)
add_custom_target(cppcheck_exit
    COMMAND
    "./analyse_xml.py"
    WORKING_DIRECTORY
    "${CPPCHECK_FOLDER}"
    COMMENT
    "analyzing XML report"
    VERBATIM)

add_dependencies(cppcheck_html_report cppcheck_xml_report)
add_dependencies(cppcheck_exit cppcheck_html_report)
add_dependencies(all_cppcheck cppcheck_exit)

function(add_cppcheck _name)
    if(NOT TARGET ${_name})
        message(FATAL_ERROR
            "add_cppcheck given a target name that does not exist: '${_name}' !")
    endif()
    if(CPPCHECK_FOUND)
        set(_cppcheck_args -I ${CMAKE_SOURCE_DIR} ${CPPCHECK_EXTRA_ARGS})

        list(FIND ARGN UNUSED_FUNCTIONS _unused_func)
        if("${_unused_func}" GREATER "-1")
            list(APPEND _cppcheck_args ${CPPCHECK_UNUSEDFUNC_ARG})
        endif()

        list(FIND ARGN STYLE _style)
        if("${_style}" GREATER "-1")
            list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG})
        endif()

        list(FIND ARGN POSSIBLE_ERROR _poss_err)
        if("${_poss_err}" GREATER "-1")
            list(APPEND _cppcheck_args ${CPPCHECK_POSSIBLEERROR_ARG})
        endif()

        list(FIND ARGN FORCE _force)
        if("${_force}" GREATER "-1")
            list(APPEND _cppcheck_args "--force")
        endif()

        list(FIND ARGN VS _vs)
        if("${_vs}" GREATER "-1")
            list(APPEND _cppcheck_args "--force")
            list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG})
            list(APPEND _cppcheck_args ${CPPCHECK_INFORMATION_ARG})
            list(APPEND _cppcheck_args ${CPPCHECK_MISSINGINCLUDE_ARG})
            list(APPEND _cppcheck_args ${CPPCHECK_WARNING_ARG})
            list(APPEND _cppcheck_args ${CPPCHECK_PERF_ARG})
            list(APPEND _cppcheck_args ${CPPCHECK_PORTABILITY_ARG})
            list(APPEND _cppcheck_args "${CPPCHECK_JOBS_ARG}8")
            list(APPEND _cppcheck_args "--std=c++11")
            list(APPEND _cppcheck_args "--suppressions-list=${CPP_SUPP_FILE}")
            list(APPEND _cppcheck_args "--suppress=unmatchedSuppression")
        endif()

        get_target_property(_cppcheck_includes "${_name}" INCLUDE_DIRECTORIES)
        set(_includes)
        foreach(_include ${_cppcheck_includes})
            list(APPEND _includes "-I${_include}")
        endforeach()

        get_target_property(_cppcheck_sources "${_name}" SOURCES)
        set(_files)
        foreach(_source ${_cppcheck_sources})
            if(NOT "${_source}" MATCHES ".*TARGET_OBJECTS.*")
                get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE)
                get_source_file_property(_cppcheck_loc "${_source}" LOCATION)
                if(("${_cppcheck_lang}" STREQUAL "C") OR ("${_cppcheck_lang}" STREQUAL "CXX"))
                    list(APPEND _files "${_cppcheck_loc}")
                endif()
            endif()
        endforeach()

        add_custom_target(${_name}_cppcheck
            COMMAND
            ${CPPCHECK_EXECUTABLE}
            ${CPPCHECK_QUIET_ARG}
            ${CPPCHECK_TEMPLATE_ARG}
            ${_cppcheck_args}
            ${_includes}
            ${_files}
            "--xml"
            "--xml-version=2"
            "2>" "${CPPCHECK_XML}/${_name}.xml"
            WORKING_DIRECTORY
            "${CMAKE_CURRENT_SOURCE_DIR}"
            COMMENT
            "${_name}_cppcheck: Running cppcheck on target ${_name}..."
            VERBATIM)
        add_dependencies(all_cppcheck ${_name}_cppcheck)
        add_dependencies(cppcheck_xml_report ${_name}_cppcheck)
    endif()

endfunction()