diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2020-05-22 15:50:39 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2020-05-26 11:27:35 (GMT) |
commit | 12e483c5633340078a81507a0a81e2cfc34482a5 (patch) | |
tree | efe8e531ff731ee9d7d3a2e0d0ed2ea06cd24068 | |
parent | 3ed8b663a9fd6e8d6f7ec0571ab1e3530f9156db (diff) | |
download | CMake-12e483c5633340078a81507a0a81e2cfc34482a5.zip CMake-12e483c5633340078a81507a0a81e2cfc34482a5.tar.gz CMake-12e483c5633340078a81507a0a81e2cfc34482a5.tar.bz2 |
cmake_language: check CALL with control command
Fixes: #20739
-rw-r--r-- | Help/command/cmake_language.rst | 9 | ||||
-rw-r--r-- | Source/cmCMakeLanguageCommand.cxx | 26 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/CallInvalidCommand.cmake | 2 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/CheckIncludeGuard.cmake | 4 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/CheckProject/CMakeLists.txt | 19 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/CheckProject/lib.c | 0 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/RunCMakeTest.cmake | 2 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/call_invalid_command.cmake | 14 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_language/call_valid_command.cmake | 99 |
9 files changed, 175 insertions, 0 deletions
diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst index 21f51a0..0988097 100644 --- a/Help/command/cmake_language.rst +++ b/Help/command/cmake_language.rst @@ -42,6 +42,15 @@ is equivalent to message(STATUS "Hello World!") +.. note:: + To ensure consistency of the code, the following commands are not allowed: + + * ``if`` / ``elseif`` / ``else`` / ``endif`` + * ``while`` / ``endwhile`` + * ``foreach`` / ``endforeach`` + * ``function`` / ``endfunction`` + * ``macro`` / ``endmacro`` + Evaluating Code ^^^^^^^^^^^^^^^ diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 66857be..eb9269f 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -3,15 +3,32 @@ #include "cmCMakeLanguageCommand.h" #include <algorithm> +#include <array> #include <cstddef> #include <memory> #include <string> +#include <cm/string_view> +#include <cmext/string_view> + #include "cmExecutionStatus.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +namespace { +std::array<cm::static_string_view, 12> InvalidCommands{ + { // clang-format off + "function"_s, "endfunction"_s, + "macro"_s, "endmacro"_s, + "if"_s, "elseif"_s, "else"_s, "endif"_s, + "while"_s, "endwhile"_s, + "foreach"_s, "endforeach"_s + } // clang-format on +}; +} bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, cmExecutionStatus& status) @@ -64,6 +81,15 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, startArg = 1; } + // ensure specified command is valid + // start/end flow control commands are not allowed + auto cmd = cmSystemTools::LowerCase(callCommand); + if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) != + InvalidCommands.cend()) { + status.SetError(cmStrCat("invalid command specified: "_s, callCommand)); + return false; + } + cmListFileFunction func; func.Name = callCommand; func.Line = context.Line; diff --git a/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake b/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake new file mode 100644 index 0000000..8bee6f2 --- /dev/null +++ b/Tests/RunCMake/cmake_language/CallInvalidCommand.cmake @@ -0,0 +1,2 @@ + +cmake_language(CALL ${COMMAND}) diff --git a/Tests/RunCMake/cmake_language/CheckIncludeGuard.cmake b/Tests/RunCMake/cmake_language/CheckIncludeGuard.cmake new file mode 100644 index 0000000..902c1e4 --- /dev/null +++ b/Tests/RunCMake/cmake_language/CheckIncludeGuard.cmake @@ -0,0 +1,4 @@ + +cmake_language (CALL "include_guard") + +set (GUARD_VALUE 1) diff --git a/Tests/RunCMake/cmake_language/CheckProject/CMakeLists.txt b/Tests/RunCMake/cmake_language/CheckProject/CMakeLists.txt new file mode 100644 index 0000000..9a27692 --- /dev/null +++ b/Tests/RunCMake/cmake_language/CheckProject/CMakeLists.txt @@ -0,0 +1,19 @@ + +cmake_language (CALL cmake_minimum_required VERSION 3.17...3.18) + +cmake_language (CALL project CheckProject VERSION 1.2.3 LANGUAGES C) + +if (NOT PROJECT_NAME STREQUAL "CheckProject") + message (SEND_ERROR "error on project() usage.") +endif() + +if (NOT CheckProject_VERSION VERSION_EQUAL "1.2.3") + message (SEND_ERROR "error on project() usage.") +endif() + +get_property (languages GLOBAL PROPERTY ENABLED_LANGUAGES) +if (NOT "C" IN_LIST languages) + message (SEND_ERROR "error on project() usage.") +endif() + +add_library (lib SHARED lib.c) diff --git a/Tests/RunCMake/cmake_language/CheckProject/lib.c b/Tests/RunCMake/cmake_language/CheckProject/lib.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/cmake_language/CheckProject/lib.c diff --git a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake index c556e42..5fb93c8 100644 --- a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake @@ -2,6 +2,8 @@ include(RunCMake) run_cmake(no_parameters) run_cmake(unknown_meta_operation) +run_cmake(call_invalid_command) +run_cmake(call_valid_command) run_cmake(call_double_evaluation) run_cmake(call_expanded_command) run_cmake(call_expanded_command_and_arguments) diff --git a/Tests/RunCMake/cmake_language/call_invalid_command.cmake b/Tests/RunCMake/cmake_language/call_invalid_command.cmake new file mode 100644 index 0000000..88bf08c --- /dev/null +++ b/Tests/RunCMake/cmake_language/call_invalid_command.cmake @@ -0,0 +1,14 @@ + +foreach (command IN ITEMS "function" "ENDFUNCTION" + "macro" "endMACRO" + "if" "elseif" "else" "endif" + "while" "endwhile" + "foreach" "endforeach") + execute_process(COMMAND "${CMAKE_COMMAND}" -DCOMMAND=${command} + -P "${CMAKE_CURRENT_SOURCE_DIR}/CallInvalidCommand.cmake" + OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE result) + if (NOT result) + message (SEND_ERROR "cmake_language(CALL ${command}) unexpectedly successfull.") + endif() +endforeach() diff --git a/Tests/RunCMake/cmake_language/call_valid_command.cmake b/Tests/RunCMake/cmake_language/call_valid_command.cmake new file mode 100644 index 0000000..2e965dc --- /dev/null +++ b/Tests/RunCMake/cmake_language/call_valid_command.cmake @@ -0,0 +1,99 @@ + +## check continue() usage +set (VALUE 0) +foreach (i RANGE 1 4) + set (VALUE "${i}") + cmake_language (CALL "continue") + set (VALUE "0") +endforeach() +if (NOT VALUE EQUAL "4") + message (SEND_ERROR "error on continue() usage.") +endif() + + +## check break() usage +set (VALUE 0) +foreach (i RANGE 1 4) + set (VALUE "${i}") + cmake_language (CALL "break") + set (VALUE 0) +endforeach() +if (NOT VALUE EQUAL "1") + message (SEND_ERROR "error on break() usage.") +endif() + + +## check return() usage in macro +macro (call_return_in_macro) + cmake_language (CALL "return") + set (VALUE 1) +endmacro() +function (wrapper) + call_return_in_macro() + set (VALUE 1 PARENT_SCOPE) +endfunction() + +set (VALUE 0) +wrapper() +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in macro.") +endif() + +set (VALUE 0) +cmake_language (CALL "wrapper") +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in macro.") +endif() + +function (wrapper2) + cmake_language (CALL "call_return_in_macro") + set (VALUE 1 PARENT_SCOPE) +endfunction() + +set (VALUE 0) +wrapper2() +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in macro.") +endif() + +set (VALUE 0) +cmake_language (CALL "wrapper2") +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in macro.") +endif() + +## check return() usage in function +function (call_return_in_function) + cmake_language (CALL "return") + set (VALUE 1 PARENT_SCOPE) +endfunction() + +set (VALUE 0) +call_return_in_function() +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in function.") +endif() + +set (VALUE 0) +cmake_language (CALL "call_return_in_function") +if (NOT VALUE EQUAL "0") + message (SEND_ERROR "error on return() usage in function.") +endif() + + +## check usage of include_guard() +set (GUARD_VALUE 0) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckIncludeGuard.cmake") +if (NOT GUARD_VALUE EQUAL "1") + message (SEND_ERROR "error on include_guard() on first include.") +endif() + +set (GUARD_VALUE 0) +include ("${CMAKE_CURRENT_SOURCE_DIR}/CheckIncludeGuard.cmake") +if (NOT GUARD_VALUE EQUAL "0") + message (SEND_ERROR "error on include_guard() on second include.") +endif() + + +## check usage of cmake_minimum_required() and project() +add_subdirectory (CheckProject) |