1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-16 14:08:35 +08:00

cmake_language: check CALL with control command

Fixes: #20739
This commit is contained in:
Marc Chevrier
2020-05-22 17:50:39 +02:00
committed by Brad King
parent 3ed8b663a9
commit 12e483c563
9 changed files with 175 additions and 0 deletions

View File

@@ -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
^^^^^^^^^^^^^^^

View File

@@ -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;

View File

@@ -0,0 +1,2 @@
cmake_language(CALL ${COMMAND})

View File

@@ -0,0 +1,4 @@
cmake_language (CALL "include_guard")
set (GUARD_VALUE 1)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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)