ci: Check that #include "*.h" works as a single include

Lesser form of include-what-you-use: at least guarantees that header
file did not forget to include something through some other included
file.

Activate run_single_includes_tests on CI.
Fix some IWYU violations.

References #5321
This commit is contained in:
Eiichi NISHINA
2017-02-12 02:10:53 +09:00
committed by Justin M. Keyes
parent 7bc37ffb22
commit 62774e4356
13 changed files with 153 additions and 33 deletions

View File

@@ -109,6 +109,10 @@ run_oldtests() {
check_core_dumps check_core_dumps
} }
run_single_includes_tests() {
${MAKE_CMD} -C "${BUILD_DIR}" check-single-includes
}
install_nvim() { install_nvim() {
${MAKE_CMD} -C "${BUILD_DIR}" install ${MAKE_CMD} -C "${BUILD_DIR}" install

View File

@@ -10,6 +10,7 @@ source "${CI_DIR}/common/test.sh"
check_core_dumps --delete quiet check_core_dumps --delete quiet
prepare_build prepare_build
run_single_includes_tests
build_nvim build_nvim
if [ "$CLANG_SANITIZER" != "TSAN" ]; then if [ "$CLANG_SANITIZER" != "TSAN" ]; then

View File

@@ -134,4 +134,7 @@ clint:
lint: clint testlint lint: clint testlint
check-single-includes: build/.ran-cmake
+$(BUILD_CMD) -C build check-single-includes
.PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install .PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install

View File

@@ -48,6 +48,7 @@ file(MAKE_DIRECTORY ${GENERATED_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
file(GLOB NEOVIM_SOURCES *.c) file(GLOB NEOVIM_SOURCES *.c)
file(GLOB NEOVIM_HEADERS *.h)
foreach(subdir foreach(subdir
os os
@@ -65,10 +66,11 @@ foreach(subdir
file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
file(GLOB sources ${subdir}/*.c) file(GLOB sources ${subdir}/*.c)
file(GLOB headers ${subdir}/*.h)
list(APPEND NEOVIM_SOURCES ${sources}) list(APPEND NEOVIM_SOURCES ${sources})
list(APPEND NEOVIM_HEADERS ${headers})
endforeach() endforeach()
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
# Sort file lists to ensure generated files are created in the same order from # Sort file lists to ensure generated files are created in the same order from
@@ -152,6 +154,19 @@ separate_arguments(C_FLAGS_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS})
separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}}) separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}})
set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY}) set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY})
function(get_preproc_output varname iname)
if(MSVC)
set(${varname} /P /Fi${iname} PARENT_SCOPE)
else()
set(${varname} -E -o ${iname} PARENT_SCOPE)
endif()
endfunction()
# NEOVIM_GENERATED_FOR_HEADERS: header files generated to be included in headers
# NEOVIM_GENERATED_FOR_SOURCES: header files generated to be included in sources
# NEOVIM_GENERATED_SOURCES: generated source files
# These lists should be mutually exclusive
foreach(sfile ${NEOVIM_SOURCES} foreach(sfile ${NEOVIM_SOURCES}
"${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c" "${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c"
${GENERATED_API_DISPATCH}) ${GENERATED_API_DISPATCH})
@@ -166,26 +181,22 @@ foreach(sfile ${NEOVIM_SOURCES}
set(f "${d}/${f}") set(f "${d}/${f}")
set(r "${d}/${r}") set(r "${d}/${r}")
endif() endif()
set(gf1 "${GENERATED_DIR}/${r}.c.generated.h") set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h")
set(gf2 "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h") set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
set(gf3 "${GENERATED_DIR}/${r}.i") set(gf_i "${GENERATED_DIR}/${r}.i")
if(MSVC) get_preproc_output(PREPROC_OUTPUT ${gf_i})
set(PREPROC_OUTPUT /P /Fi${gf3})
else()
set(PREPROC_OUTPUT -E -o ${gf3})
endif()
add_custom_command( add_custom_command(
OUTPUT "${gf1}" "${gf2}" OUTPUT "${gf_c_h}" "${gf_h_h}"
COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} ${C_FLAGS_ARRAY} COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} ${C_FLAGS_ARRAY}
COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf1}" "${gf2}" "${gf3}" COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}"
DEPENDS "${HEADER_GENERATOR}" "${sfile}" DEPENDS "${HEADER_GENERATOR}" "${sfile}"
) )
list(APPEND NEOVIM_GENERATED_SOURCES "${gf1}") list(APPEND NEOVIM_GENERATED_FOR_SOURCES "${gf_c_h}")
list(APPEND NEOVIM_GENERATED_SOURCES "${gf2}") list(APPEND NEOVIM_GENERATED_FOR_HEADERS "${gf_h_h}")
if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$") if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$")
list(APPEND API_HEADERS ${gf2}) list(APPEND API_HEADERS ${gf_h_h})
endif() endif()
endforeach() endforeach()
@@ -210,17 +221,23 @@ add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA}
${CMAKE_CURRENT_LIST_DIR}/api/dispatch_deprecated.lua ${CMAKE_CURRENT_LIST_DIR}/api/dispatch_deprecated.lua
) )
list(APPEND NEOVIM_GENERATED_SOURCES list(APPEND NEOVIM_GENERATED_FOR_HEADERS
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_ENUM}" "${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_ENUM}" "${GENERATED_EVENTS_ENUM}"
)
list(APPEND NEOVIM_GENERATED_FOR_SOURCES
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_NAMES_MAP}" "${GENERATED_EVENTS_NAMES_MAP}"
"${GENERATED_OPTIONS}" "${GENERATED_OPTIONS}"
"${GENERATED_UNICODE_TABLES}" "${GENERATED_UNICODE_TABLES}"
) )
list(APPEND NEOVIM_GENERATED_SOURCES
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
)
add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS} add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR} COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR} ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
@@ -237,7 +254,7 @@ add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA}
${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS} ${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS}
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA} DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA}
) )
list(APPEND NEOVIM_GENERATED_SOURCES list(APPEND NEOVIM_GENERATED_FOR_SOURCES
"${GENERATED_FUNCS}") "${GENERATED_FUNCS}")
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
@@ -252,6 +269,15 @@ add_custom_command(OUTPUT ${GENERATED_OPTIONS}
DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE} DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE}
) )
# Check that NEOVIM_GENERATED_FOR_SOURCES and NEOVIM_GENERATED_FOR_HEADERS are mutually exclusive
foreach(hfile ${NEOVIM_GENERATED_FOR_HEADERS})
list(FIND NEOVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx)
if(NOT ${hfile_idx} EQUAL -1)
message(FATAL_ERROR "File included in both NEOVIM_GENERATED_FOR_HEADERS and NEOVIM_GENERATED_FOR_SOURCES")
endif()
endforeach()
# Our dependencies come first. # Our dependencies come first.
if (LibIntl_FOUND) if (LibIntl_FOUND)
@@ -286,8 +312,8 @@ if(JEMALLOC_FOUND)
list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES}) list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
endif() endif()
add_executable(nvim ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES} add_executable(nvim ${NEOVIM_GENERATED_FOR_SOURCES} ${NEOVIM_GENERATED_FOR_HEADERS}
${NEOVIM_HEADERS}) ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES} ${NEOVIM_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES}) target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim) install_helper(TARGETS nvim)
@@ -361,17 +387,97 @@ elseif(CLANG_TSAN)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ") set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ")
endif() endif()
add_library(libnvim STATIC EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES} add_library(libnvim STATIC EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_FOR_SOURCES} ${NEOVIM_GENERATED_FOR_HEADERS}
${NEOVIM_SOURCES} ${NEOVIM_HEADERS}) ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES} ${NEOVIM_HEADERS})
target_link_libraries(libnvim ${NVIM_LINK_LIBRARIES}) target_link_libraries(libnvim ${NVIM_LINK_LIBRARIES})
set_target_properties(libnvim PROPERTIES set_target_properties(libnvim PROPERTIES
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON
OUTPUT_NAME nvim) OUTPUT_NAME nvim)
set_property(TARGET libnvim APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB ") set_property(TARGET libnvim APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB ")
add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES} add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_FOR_SOURCES} ${NEOVIM_GENERATED_FOR_HEADERS}
${NEOVIM_SOURCES} ${UNIT_TEST_FIXTURES} ${NEOVIM_HEADERS}) ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES} ${UNIT_TEST_FIXTURES} ${NEOVIM_HEADERS})
target_link_libraries(nvim-test ${NVIM_LINK_LIBRARIES}) target_link_libraries(nvim-test ${NVIM_LINK_LIBRARIES})
set_property(TARGET nvim-test APPEND_STRING PROPERTY COMPILE_FLAGS -DUNIT_TESTING) set_property(TARGET nvim-test APPEND_STRING PROPERTY COMPILE_FLAGS -DUNIT_TESTING)
set(NO_SINGLE_CHECK_HEADERS
buffer
charset
cursor_shape
diff
digraph
ex_cmds
ex_getln
file_search
fold
getchar
hardcopy
if_cscope
if_cscope_defs
mark
mbyte
memfile_defs
memline
memline_defs
menu
misc2
move
msgpack_rpc/server
ops
option
os/shell
os_unix
os/win_defs
popupmnu
quickfix
regexp
regexp_defs
screen
search
sha256
sign_defs
spell
syntax
syntax_defs
tag
terminal
tui/tui
ugrid
ui
ui_bridge
undo
undo_defs
version
window
)
foreach(hfile ${NEOVIM_HEADERS})
get_filename_component(full_d ${hfile} PATH)
file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
if(${d} MATCHES "^[.][.]")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif()
get_filename_component(r ${hfile} NAME_WE)
if(NOT ${d} EQUAL ".")
set(r "${d}/${r}")
endif()
if(NOT ${hfile} MATCHES "[.]c[.]h$")
set(tsource "${GENERATED_DIR}/${r}.test-include.c")
set(tresult "${GENERATED_DIR}/${r}.test-include.i")
string(REPLACE "/" "-" texe "${r}-test")
write_file("${tsource}" "#include \"${hfile}\"\nint main(int argc, char **argv) { return 0; }")
get_preproc_output(PREPROC_OUTPUT ${tresult})
add_executable(
${texe}
EXCLUDE_FROM_ALL
${tsource} ${NEOVIM_HEADERS} ${NEOVIM_GENERATED_FOR_HEADERS})
list(FIND NO_SINGLE_CHECK_HEADERS "${r}" hfile_exclude_idx)
if(${hfile_exclude_idx} EQUAL -1)
list(APPEND HEADER_CHECK_TARGETS ${texe})
endif()
endif()
endforeach()
add_custom_target(check-single-includes DEPENDS ${HEADER_CHECK_TARGETS})
add_subdirectory(po) add_subdirectory(po)

View File

@@ -3,6 +3,7 @@
#include <limits.h> #include <limits.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h>
#include "nvim/hashtab.h" #include "nvim/hashtab.h"
#include "nvim/lib/queue.h" #include "nvim/lib/queue.h"

View File

@@ -67,6 +67,7 @@
#include "nvim/event/rstream.h" #include "nvim/event/rstream.h"
#include "nvim/event/wstream.h" #include "nvim/event/wstream.h"
#include "nvim/shada.h" #include "nvim/shada.h"
#include "nvim/globals.h"
static int quitmore = 0; static int quitmore = 0;
static int ex_pressedreturn = FALSE; static int ex_pressedreturn = FALSE;

View File

@@ -2,6 +2,7 @@
#define NVIM_EX_DOCMD_H #define NVIM_EX_DOCMD_H
#include "nvim/ex_cmds_defs.h" #include "nvim/ex_cmds_defs.h"
#include "nvim/globals.h"
// flags for do_cmdline() // flags for do_cmdline()
#define DOCMD_VERBOSE 0x01 // included command in error message #define DOCMD_VERBOSE 0x01 // included command in error message

View File

@@ -29,7 +29,7 @@
/// Clear given fmark /// Clear given fmark
#define CLEAR_FMARK(fmarkp_) \ #define CLEAR_FMARK(fmarkp_) \
RESET_FMARK(fmarkp_, ((pos_T) {0, 0, 0}), 0) RESET_FMARK(fmarkp_, ((pos_T) { 0, 0, 0 }), 0)
/// Set given extended mark (regular mark + file name) /// Set given extended mark (regular mark + file name)
#define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \ #define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \

View File

@@ -14,7 +14,7 @@ typedef struct {
uint64_t device_id; ///< @private The id of the device containing the file uint64_t device_id; ///< @private The id of the device containing the file
} FileID; } FileID;
#define FILE_ID_EMPTY (FileID) {.inode = 0, .device_id = 0} #define FILE_ID_EMPTY (FileID) { .inode = 0, .device_id = 0 }
typedef struct { typedef struct {
uv_fs_t request; ///< @private The request to uv for the directory. uv_fs_t request; ///< @private The request to uv for the directory.

View File

@@ -27,11 +27,11 @@
// Use up to 5 Mbyte for a buffer. // Use up to 5 Mbyte for a buffer.
#ifndef DFLT_MAXMEM #ifndef DFLT_MAXMEM
# define DFLT_MAXMEM (5*1024) # define DFLT_MAXMEM (5 * 1024)
#endif #endif
// use up to 10 Mbyte for Vim. // use up to 10 Mbyte for Vim.
#ifndef DFLT_MAXMEMTOT #ifndef DFLT_MAXMEMTOT
# define DFLT_MAXMEMTOT (10*1024) # define DFLT_MAXMEMTOT (10 * 1024)
#endif #endif
// Note: Some systems need both string.h and strings.h (Savage). However, // Note: Some systems need both string.h and strings.h (Savage). However,

View File

@@ -8,7 +8,7 @@
// POSIX.1-2008 says that NAME_MAX should be in here // POSIX.1-2008 says that NAME_MAX should be in here
#include <limits.h> #include <limits.h>
#define TEMP_DIR_NAMES {"$TMPDIR", "/tmp", ".", "~"} #define TEMP_DIR_NAMES { "$TMPDIR", "/tmp", ".", "~" }
#define TEMP_FILE_PATH_MAXLEN 256 #define TEMP_FILE_PATH_MAXLEN 256
#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL) #define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL)

View File

@@ -1,6 +1,10 @@
#ifndef NVIM_OS_WIN_DEFS_H #ifndef NVIM_OS_WIN_DEFS_H
#define NVIM_OS_WIN_DEFS_H #define NVIM_OS_WIN_DEFS_H
#ifndef WIN32
# error Header must be included only when compiling for Windows.
#endif
// winsock2.h must be first to avoid incompatibilities // winsock2.h must be first to avoid incompatibilities
// with winsock.h (included by windows.h) // with winsock.h (included by windows.h)
#include <winsock2.h> #include <winsock2.h>
@@ -15,7 +19,7 @@
#define NAME_MAX _MAX_PATH #define NAME_MAX _MAX_PATH
#define TEMP_DIR_NAMES {"$TMP", "$TEMP", "$USERPROFILE", ""} #define TEMP_DIR_NAMES { "$TMP", "$TEMP", "$USERPROFILE", "" }
#define TEMP_FILE_PATH_MAXLEN _MAX_PATH #define TEMP_FILE_PATH_MAXLEN _MAX_PATH
#define FNAME_ILLEGAL "\"*?><|" #define FNAME_ILLEGAL "\"*?><|"

View File

@@ -1,9 +1,8 @@
#ifndef NVIM_STRINGS_H #ifndef NVIM_STRINGS_H
#define NVIM_STRINGS_H #define NVIM_STRINGS_H
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stdarg.h>
#include "nvim/types.h" #include "nvim/types.h"
#include "nvim/eval_defs.h" #include "nvim/eval_defs.h"