diff options
41 files changed, 789 insertions, 145 deletions
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 9eb993abf1..5e936c29db 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -2013,6 +2013,7 @@ syn keyword cmakeKWExternalProject contained \ IGNORED \ INACTIVITY_TIMEOUT \ INDEPENDENT_STEP_TARGETS + \ INSTALL_BYPRODUCTS \ INSTALL_COMMAND \ INSTALL_DIR \ JOB_POOLS diff --git a/Help/command/FIND_XXX.txt b/Help/command/FIND_XXX.txt index 59a4e71722..bd55e24c7b 100644 --- a/Help/command/FIND_XXX.txt +++ b/Help/command/FIND_XXX.txt @@ -70,23 +70,28 @@ Options include: ``VALIDATOR`` .. versionadded:: 3.25 - Specify a :command:`function` (a :command:`macro` is not an acceptable - choice) which will be called for each found item. The search ends when - the validation function returns a successful status. - - The validation function expects two arguments: output variable name and item - value. By default, the output variable name already holds a ``TRUE`` value. + Specify a :command:`function` to be called for each candidate item found + (a :command:`macro` cannot be provided, that will result in an error). + Two arguments will be passed to the validator function: the name of a + result variable, and the absolute path to the candidate item. The item + will be accepted and the search will end unless the function sets the + value in the result variable to false in the calling scope. The result + variable will hold a true value when the validator function is entered. .. parsed-literal:: - function (MY_CHECK output_status item) - if (NOT item MATCHES ...) - set(${output_status} FALSE PARENT_SCOPE) + function(my_check validator_result_var item) + if(NOT item MATCHES ...) + set(${validator_result_var} FALSE PARENT_SCOPE) endif() endfunction() |FIND_XXX| (result NAMES ... VALIDATOR my_check) + Note that if a cached result is used, the search is skipped and any + ``VALIDATOR`` is ignored. The cached result is not required to pass the + validation function. + ``DOC`` Specify the documentation string for the ``<VAR>`` cache entry. diff --git a/Help/command/block.rst b/Help/command/block.rst index 9d37deb4dc..dfd60d446d 100644 --- a/Help/command/block.rst +++ b/Help/command/block.rst @@ -7,14 +7,14 @@ Evaluate a group of commands with a dedicated variable and/or policy scope. .. code-block:: cmake - block([SCOPE_FOR (POLICIES|VARIABLES)] [PROPAGATE <var-name>...]) + block([SCOPE_FOR [POLICIES] [VARIABLES] ] [PROPAGATE <var-name>...]) <commands> endblock() All commands between ``block()`` and the matching :command:`endblock` are recorded without being invoked. Once the :command:`endblock` is evaluated, the -recorded list of commands is invoked inside the requested scopes, and, finally, -the scopes created by ``block()`` command are removed. +recorded list of commands is invoked inside the requested scopes, then the +scopes created by the ``block()`` command are removed. ``SCOPE_FOR`` Specify which scopes must be created. @@ -33,28 +33,29 @@ the scopes created by ``block()`` command are removed. block(SCOPE_FOR VARIABLES POLICIES) ``PROPAGATE`` - When a variable scope is created by :command:`block` command, this option - set or unset the specified variables in the parent scope. This is equivalent - to :command:`set(PARENT_SCOPE)` or :command:`unset(PARENT_SCOPE)` commands. + When a variable scope is created by the :command:`block` command, this + option sets or unsets the specified variables in the parent scope. This is + equivalent to :command:`set(PARENT_SCOPE)` or :command:`unset(PARENT_SCOPE)` + commands. .. code-block:: cmake - set(VAR1 "INIT1") - set(VAR2 "INIT2") + set(var1 "INIT1") + set(var2 "INIT2") - block(PROPAGATE VAR1 VAR2) - set(VAR1 "VALUE1") - unset(VAR2) + block(PROPAGATE var1 var2) + set(var1 "VALUE1") + unset(var2) endblock() - # here, VAR1 holds value VALUE1 and VAR2 is unset + # Now var1 holds VALUE1, and var2 is unset This option is only allowed when a variable scope is created. An error will be raised in the other cases. -When the ``block`` is local to a :command:`foreach` or :command:`while` -command, the commands :command:`break` and :command:`continue` can be used -inside this block. +When the ``block()`` is inside a :command:`foreach` or :command:`while` +command, the :command:`break` and :command:`continue` commands can be used +inside the block. .. code-block:: cmake diff --git a/Help/command/continue.rst b/Help/command/continue.rst index f62802e2d1..e8012ee303 100644 --- a/Help/command/continue.rst +++ b/Help/command/continue.rst @@ -9,8 +9,8 @@ Continue to the top of enclosing foreach or while loop. continue() -The ``continue`` command allows a cmake script to abort the rest of a block -in a :command:`foreach` or :command:`while` loop, and start at the top of -the next iteration. +The ``continue()`` command allows a cmake script to abort the rest of the +current iteration of a :command:`foreach` or :command:`while` loop, and start +at the top of the next iteration. See also the :command:`break` command. diff --git a/Help/command/return.rst b/Help/command/return.rst index 029fd050e3..3013b52851 100644 --- a/Help/command/return.rst +++ b/Help/command/return.rst @@ -7,46 +7,83 @@ Return from a file, directory or function. return([PROPAGATE <var-name>...]) -Returns from a file, directory or function. When this command is -encountered in an included file (via :command:`include` or +When this command is encountered in an included file (via :command:`include` or :command:`find_package`), it causes processing of the current file to stop and control is returned to the including file. If it is encountered in a -file which is not included by another file, e.g. a ``CMakeLists.txt``, +file which is not included by another file, e.g. a ``CMakeLists.txt``, deferred calls scheduled by :command:`cmake_language(DEFER)` are invoked and -control is returned to the parent directory if there is one. If return is -called in a function, control is returned to the caller of the function. +control is returned to the parent directory if there is one. + +If ``return()`` is called in a function, control is returned to the caller +of that function. Note that a :command:`macro`, unlike a :command:`function`, +is expanded in place and therefore cannot handle ``return()``. + +Policy :policy:`CMP0140` controls the behavior regarding the arguments of the +command. All arguments are ignored unless that policy is set to ``NEW``. ``PROPAGATE`` .. versionadded:: 3.25 - This option set or unset the specified variables in the parent directory or + This option sets or unsets the specified variables in the parent directory or function caller scope. This is equivalent to :command:`set(PARENT_SCOPE)` or - :command:`unset(PARENT_SCOPE)` commands. + :command:`unset(PARENT_SCOPE)` commands, except for the way it interacts + with the :command:`block` command, as described below. - The option ``PROPAGATE`` can be very useful in conjunction with the - :command:`block` command because the :command:`return` will cross over - various scopes created by the :command:`block` commands. + The ``PROPAGATE`` option can be very useful in conjunction with the + :command:`block` command. A :command:`return` will propagate the + specified variables through any enclosing block scopes created by the + :command:`block` commands. Inside a function, this ensures the variables + are propagated to the function's caller, regardless of any blocks within + the function. If not inside a function, it ensures the variables are + propagated to the parent file or directory scope. For example: .. code-block:: cmake + :caption: CMakeLists.txt + + cmake_version_required(VERSION 3.25) + project(example) + + set(var1 "top-value") + + block(SCOPE_FOR VARIABLES) + add_subdirectory(subDir) + # var1 has the value "block-nested" + endblock() - function(MULTI_SCOPES RESULT_VARIABLE) + # var1 has the value "top-value" + + .. code-block:: cmake + :caption: subDir/CMakeLists.txt + + function(multi_scopes result_var1 result_var2) block(SCOPE_FOR VARIABLES) - # here set(PARENT_SCOPE) is not usable because it will not set the - # variable in the caller scope but in the parent scope of the block() - set(${RESULT_VARIABLE} "new-value") - return(PROPAGATE ${RESULT_VARIABLE}) + # This would only propagate out of the immediate block, not to + # the caller of the function. + #set(${result_var1} "new-value" PARENT_SCOPE) + #unset(${result_var2} PARENT_SCOPE) + + # This propagates the variables through the enclosing block and + # out to the caller of the function. + set(${result_var1} "new-value") + unset(${result_var2}) + return(PROPAGATE ${result_var1} ${result_var2}) endblock() endfunction() - set(MY_VAR "initial-value") - multi_scopes(MY_VAR) - # here MY_VAR will holds "new-value" + set(var1 "some-value") + set(var2 "another-value") -Policy :policy:`CMP0140` controls the behavior regarding the arguments of the -command. + multi_scopes(var1 var2) + # Now var1 will hold "new-value" and var2 will be unset -Note that a :command:`macro <macro>`, unlike a :command:`function <function>`, -is expanded in place and therefore cannot handle ``return()``. + block(SCOPE_FOR VARIABLES) + # This return() will set var1 in the directory scope that included us + # via add_subdirectory(). The surrounding block() here does not limit + # propagation to the current file, but the block() in the parent + # directory scope does prevent propagation going any further. + set(var1 "block-nested") + return(PROPAGATE var1) + endblock() See Also ^^^^^^^^ diff --git a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt index 889d97a418..7f19bc09ff 100644 --- a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt +++ b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT-VALUES.txt @@ -8,8 +8,9 @@ Compile with ``-ZI`` or equivalent flag(s) to produce a program database that supports the Edit and Continue feature. -The value is ignored on non-MSVC compilers, but an unsupported value will -be rejected as an error when using a compiler targeting the MSVC ABI. +The value is ignored on compilers not targeting the MSVC ABI, but an +unsupported value will be rejected as an error when using a compiler +targeting the MSVC ABI. The value may also be the empty string (``""``), in which case no debug information format flag will be added explicitly by CMake. diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt index 6c6134197b..5f8b82dec6 100644 --- a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt +++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt @@ -11,8 +11,9 @@ Compile with ``-MDd`` or equivalent flag(s) to use a multi-threaded dynamically-linked runtime library. -The value is ignored on non-MSVC compilers but an unsupported value will -be rejected as an error when using a compiler targeting the MSVC ABI. +The value is ignored on compilers not targeting the MSVC ABI, but an +unsupported value will be rejected as an error when using a compiler +targeting the MSVC ABI. The value may also be the empty string (``""``) in which case no runtime library selection flag will be added explicitly by CMake. Note that with diff --git a/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst new file mode 100644 index 0000000000..233596f79c --- /dev/null +++ b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst @@ -0,0 +1,6 @@ +ExternalProject-INSTALL_BYPRODUCTS +---------------------------------- + +* The :module:`ExternalProject` module :command:`ExternalProject_Add` command + gained an ``INSTALL_BYPRODUCTS`` option to specify files generated by the + "install" step. diff --git a/Help/variable/CMAKE_TASKING_TOOLSET.rst b/Help/variable/CMAKE_TASKING_TOOLSET.rst index 940606b816..6bd14798d7 100644 --- a/Help/variable/CMAKE_TASKING_TOOLSET.rst +++ b/Help/variable/CMAKE_TASKING_TOOLSET.rst @@ -8,12 +8,15 @@ Select the Tasking toolset which provides the compiler Architecture compilers are provided by different toolchains with incompatible versioning schemes. Set this variable in a :variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>` so CMake can detect -the compiler and version correctly. If no toolset is specified, +the compiler features correctly. If no toolset is specified, ``Standalone`` is assumed. -Projects that can be built with different architectures and/or toolsets must -take :variable:`CMAKE_TASKING_TOOLSET` and -:variable:`CMAKE_<LANG>_COMPILER_ARCHITECTURE_ID` into account to qualify +Due to the different versioning schemes, the compiler version +(:variable:`CMAKE_<LANG>_COMPILER_VERSION`) depends on the toolset and +architecture in use. If projects can be built with multiple toolsets or +architectures, the specified :variable:`CMAKE_TASKING_TOOLSET` and the +automatically determined :variable:`CMAKE_<LANG>_COMPILER_ARCHITECTURE_ID` +must be taken into account when comparing against the :variable:`CMAKE_<LANG>_COMPILER_VERSION`. ``TriCore`` diff --git a/Modules/Compiler/Tasking.cmake b/Modules/Compiler/Tasking.cmake index 419db63585..5bf066eef7 100644 --- a/Modules/Compiler/Tasking.cmake +++ b/Modules/Compiler/Tasking.cmake @@ -17,44 +17,12 @@ set(BUILD_SHARED_LIBS FALSE CACHE BOOL "") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(CMAKE_LINK_SEARCH_START_STATIC TRUE) -function(__tasking_set_processor_list lang out_var) - execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" --cpu-list - OUTPUT_VARIABLE processor_list - ERROR_VARIABLE processor_list) - string(REGEX MATCHALL " +([A-Za-z0-9_]+)[^\n]+\n" processor_list "${processor_list}") - list(POP_FRONT processor_list) - string(REGEX REPLACE " +([A-Za-z0-9_]+)[^\n]+\n" "\\1" processor_list "${processor_list}") - set(${out_var} "${processor_list}" PARENT_SCOPE) -endfunction() - -function(__tasking_check_processor processor list out_var) - string(TOLOWER "${processor}" processor) - if(processor IN_LIST list) - set(${out_var} TRUE PARENT_SCOPE) - else() - set(${out_var} FALSE PARENT_SCOPE) - endif() -endfunction() - if(NOT CMAKE_TASKING_TOOLSET) set(CMAKE_TASKING_TOOLSET "Standalone") endif() macro(__compiler_tasking lang) - if(CMAKE_SYSTEM_PROCESSOR) - if(NOT _TASKING_${lang}_PROCESSOR_LIST) - __tasking_set_processor_list(${lang} _TASKING_${lang}_PROCESSOR_LIST) - endif() - __tasking_check_processor(${CMAKE_SYSTEM_PROCESSOR} "${_TASKING_${lang}_PROCESSOR_LIST}" _TASKING_${lang}_VALID_PROCESSOR) - if(${_TASKING_${lang}_VALID_PROCESSOR}) - string(APPEND CMAKE_${lang}_FLAGS_INIT " -C${CMAKE_SYSTEM_PROCESSOR}") - else() - message(FATAL_ERROR "Invalid processor ${CMAKE_SYSTEM_PROCESSOR} specified.\n" - "Supported processors: ${_TASKING_${lang}_PROCESSOR_LIST}") - endif() - endif() - set(CMAKE_${lang}_VERBOSE_FLAG "-v") set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "--pic") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl" " ") diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 141b18586f..9fecd8f840 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -637,8 +637,11 @@ External Project Definition Specifies files that will be generated by the build command but which might or might not have their modification time updated by subsequent - builds. These ultimately get passed through as ``BYPRODUCTS`` to the - build step's own underlying call to :command:`add_custom_command`. + builds. This may also be required to explicitly declare dependencies + when using the :generator:`Ninja` generator. + These ultimately get passed through as ``BYPRODUCTS`` to the + build step's own underlying call to :command:`add_custom_command`, which + has additional documentation. **Install Step Options:** If the configure step assumed the external project uses CMake as its build @@ -661,6 +664,17 @@ External Project Definition supported). Passing an empty string as the ``<cmd>`` makes the install step do nothing. + ``INSTALL_BYPRODUCTS <file>...`` + .. versionadded:: 3.26 + + Specifies files that will be generated by the install command but which + might or might not have their modification time updated by subsequent + installs. This may also be required to explicitly declare dependencies + when using the :generator:`Ninja` generator. + These ultimately get passed through as ``BYPRODUCTS`` to the + install step's own underlying call to :command:`add_custom_command`, which + has additional documentation. + .. note:: If the :envvar:`CMAKE_INSTALL_MODE` environment variable is set when the main project is built, it will only have an effect if the following @@ -943,9 +957,12 @@ control needed to implement such step-level capabilities. .. versionadded:: 3.2 Files that will be generated by this custom step but which might or might - not have their modification time updated by subsequent builds. This list of + not have their modification time updated by subsequent builds. + This may also be required to explicitly declare dependencies + when using the :generator:`Ninja` generator. This list of files will ultimately be passed through as the ``BYPRODUCTS`` option to the - :command:`add_custom_command` used to implement the custom step internally. + :command:`add_custom_command` used to implement the custom step internally, + which has additional documentation. ``ALWAYS <bool>`` When enabled, this option specifies that the custom step should always be @@ -3846,6 +3863,11 @@ function(_ep_add_install_command name) set(always 0) endif() + get_property(install_byproducts + TARGET ${name} + PROPERTY _EP_INSTALL_BYPRODUCTS + ) + set(__cmdQuoted) foreach(__item IN LISTS cmd) string(APPEND __cmdQuoted " [==[${__item}]==]") @@ -3854,6 +3876,7 @@ function(_ep_add_install_command name) ExternalProject_Add_Step(${name} install INDEPENDENT FALSE COMMAND ${__cmdQuoted} + BYPRODUCTS \${install_byproducts} WORKING_DIRECTORY \${binary_dir} DEPENDEES build ALWAYS \${always} @@ -4081,6 +4104,7 @@ function(ExternalProject_Add name) # Install step options # INSTALL_COMMAND + INSTALL_BYPRODUCTS # # Test step options # diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake index 352c4cc1e3..f66ffcf610 100644 --- a/Modules/FindOpenSSL.cmake +++ b/Modules/FindOpenSSL.cmake @@ -404,6 +404,7 @@ if(WIN32 AND NOT CYGWIN) PATH_SUFFIXES "lib/MinGW" "lib" + "lib64" ) find_library(SSL_EAY @@ -414,6 +415,7 @@ if(WIN32 AND NOT CYGWIN) PATH_SUFFIXES "lib/MinGW" "lib" + "lib64" ) mark_as_advanced(SSL_EAY LIB_EAY) diff --git a/Modules/Internal/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake index c011c24238..f8481cdd2b 100644 --- a/Modules/Internal/CheckFlagCommonConfig.cmake +++ b/Modules/Internal/CheckFlagCommonConfig.cmake @@ -48,6 +48,8 @@ macro(CMAKE_CHECK_FLAG_COMMON_INIT _FUNC _LANG _SRC _PATTERNS) FAIL_REGEX "argument unused during compilation: .*") # Clang elseif("${_LANG}" STREQUAL "ISPC") set(${_SRC} "float func(uniform int32, float a) { return a / 2.25; }") + elseif("${_LANG}" STREQUAL "Swift") + set(${_SRC} "func blarpy() { }") else() message (SEND_ERROR "${_FUNC}: ${_LANG}: unknown language.") return() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index c97aa518ea..5e7896fa4b 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 25) -set(CMake_VERSION_PATCH 20221106) +set(CMake_VERSION_PATCH 20221108) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index c72d6a7a8f..133bf5fca0 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -27,7 +27,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name, bool quiet, Encoding encoding) : cmGeneratedFileStreamBase(name) - , Stream(this->TempName.c_str()) + , Stream(this->TempName.c_str()) // NOLINT(cmake-use-cmsys-fstream) { // Check if the file opened. if (!*this && !quiet) { @@ -67,10 +67,11 @@ cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name, // Open the temporary output file. if (binaryFlag) { - this->Stream::open(this->TempName.c_str(), - std::ios::out | std::ios::binary); + this->Stream::open( // NOLINT(cmake-use-cmsys-fstream) + this->TempName.c_str(), std::ios::out | std::ios::binary); } else { - this->Stream::open(this->TempName.c_str()); + this->Stream::open( // NOLINT(cmake-use-cmsys-fstream) + this->TempName.c_str()); } // Check if the file opened. @@ -87,7 +88,7 @@ bool cmGeneratedFileStream::Close() this->Okay = !this->fail(); // Close the temporary output file. - this->Stream::close(); + this->Stream::close(); // NOLINT(cmake-use-cmsys-fstream) // Remove the temporary file (possibly by renaming to the real file). return this->cmGeneratedFileStreamBase::Close(); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 17ee7f339c..f12f91fd48 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -281,7 +281,7 @@ cmStateSnapshot cmState::Reset() it->CompileOptions.clear(); it->LinkOptions.clear(); it->LinkDirectories.clear(); - it->DirectoryEnd = pos; + it->CurrentScope = pos; it->NormalTargetNames.clear(); it->ImportedTargetNames.clear(); it->Properties.Clear(); @@ -821,7 +821,7 @@ cmStateSnapshot cmState::CreateBaseSnapshot() pos->CompileOptionsPosition = 0; pos->LinkOptionsPosition = 0; pos->LinkDirectoriesPosition = 0; - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->Policies = this->PolicyStack.Root(); pos->PolicyRoot = this->PolicyStack.Root(); pos->PolicyScope = this->PolicyStack.Root(); @@ -848,7 +848,7 @@ cmStateSnapshot cmState::CreateBuildsystemDirectorySnapshot( originSnapshot.Position->BuildSystemDirectory); pos->ExecutionListFile = this->ExecutionListFiles.Push(originSnapshot.Position->ExecutionListFile); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->Policies = originSnapshot.Position->Policies; pos->PolicyRoot = originSnapshot.Position->Policies; pos->PolicyScope = originSnapshot.Position->Policies; @@ -878,7 +878,7 @@ cmStateSnapshot cmState::CreateDeferCallSnapshot( pos->ExecutionListFile = this->ExecutionListFiles.Push( originSnapshot.Position->ExecutionListFile, fileName); assert(originSnapshot.Position->Vars.IsValid()); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; return { this, pos }; } @@ -893,7 +893,7 @@ cmStateSnapshot cmState::CreateFunctionCallSnapshot( pos->Keep = false; pos->ExecutionListFile = this->ExecutionListFiles.Push( originSnapshot.Position->ExecutionListFile, fileName); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; assert(originSnapshot.Position->Vars.IsValid()); cmLinkedTree<cmDefinitions>::iterator origin = originSnapshot.Position->Vars; @@ -912,7 +912,7 @@ cmStateSnapshot cmState::CreateMacroCallSnapshot( pos->ExecutionListFile = this->ExecutionListFiles.Push( originSnapshot.Position->ExecutionListFile, fileName); assert(originSnapshot.Position->Vars.IsValid()); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; return { this, pos }; } @@ -927,7 +927,7 @@ cmStateSnapshot cmState::CreateIncludeFileSnapshot( pos->ExecutionListFile = this->ExecutionListFiles.Push( originSnapshot.Position->ExecutionListFile, fileName); assert(originSnapshot.Position->Vars.IsValid()); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; return { this, pos }; } @@ -940,6 +940,7 @@ cmStateSnapshot cmState::CreateVariableScopeSnapshot( pos->ScopeParent = originSnapshot.Position; pos->SnapshotType = cmStateEnums::VariableScopeType; pos->Keep = false; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; assert(originSnapshot.Position->Vars.IsValid()); @@ -959,7 +960,7 @@ cmStateSnapshot cmState::CreateInlineListFileSnapshot( pos->Keep = true; pos->ExecutionListFile = this->ExecutionListFiles.Push( originSnapshot.Position->ExecutionListFile, fileName); - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; return { this, pos }; } @@ -971,7 +972,7 @@ cmStateSnapshot cmState::CreatePolicyScopeSnapshot( this->SnapshotData.Push(originSnapshot.Position, *originSnapshot.Position); pos->SnapshotType = cmStateEnums::PolicyScopeType; pos->Keep = false; - pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; return { this, pos }; } @@ -991,7 +992,7 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot) prevPos->BuildSystemDirectory->LinkOptions.size(); prevPos->LinkDirectoriesPosition = prevPos->BuildSystemDirectory->LinkDirectories.size(); - prevPos->BuildSystemDirectory->DirectoryEnd = prevPos; + prevPos->BuildSystemDirectory->CurrentScope = prevPos; if (!pos->Keep && this->SnapshotData.IsLast(pos)) { if (pos->Vars != prevPos->Vars) { diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h index fd46eedfa2..ec14834d1d 100644 --- a/Source/cmStatePrivate.h +++ b/Source/cmStatePrivate.h @@ -62,7 +62,7 @@ struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap struct cmStateDetail::BuildsystemDirectoryStateType { - cmStateDetail::PositionType DirectoryEnd; + cmStateDetail::PositionType CurrentScope; std::string Location; std::string OutputLocation; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index c51650ac64..cb5f11f930 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -64,7 +64,7 @@ bool cmStateSnapshot::IsValid() const cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectory() const { - return { this->State, this->Position->BuildSystemDirectory->DirectoryEnd }; + return { this->State, this->Position->BuildSystemDirectory->CurrentScope }; } cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectoryParent() const @@ -76,7 +76,7 @@ cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectoryParent() const cmStateDetail::PositionType parentPos = this->Position->DirectoryParent; if (parentPos != this->State->SnapshotData.Root()) { snapshot = cmStateSnapshot(this->State, - parentPos->BuildSystemDirectory->DirectoryEnd); + parentPos->BuildSystemDirectory->CurrentScope); } return snapshot; @@ -177,9 +177,9 @@ cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id, while (true) { assert(dir.IsValid()); cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator leaf = - dir->DirectoryEnd->Policies; + dir->CurrentScope->Policies; cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator root = - dir->DirectoryEnd->PolicyRoot; + dir->CurrentScope->PolicyRoot; for (; leaf != root; ++leaf) { if (parent_scope) { parent_scope = false; @@ -190,7 +190,7 @@ cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id, return status; } } - cmStateDetail::PositionType e = dir->DirectoryEnd; + cmStateDetail::PositionType e = dir->CurrentScope; cmStateDetail::PositionType p = e->DirectoryParent; if (p == this->State->SnapshotData.Root()) { break; diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 45a9e6fc79..b25b2580d2 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -2011,6 +2011,14 @@ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, return 0; } +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wshorten-64-to-32") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wshorten-64-to-32" +# define KWSYSPE_CLANG_DIAG_WSHORTEN +# endif +#endif + /* Get the length of time before the given timeout time arrives. Returns 1 if the time has already arrived, and 0 otherwise. */ static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, @@ -2061,6 +2069,11 @@ static kwsysProcessTime kwsysProcessTimeGetCurrent(void) return current; } +#if defined(KWSYSPE_CLANG_DIAG_WSHORTEN) +# undef KWSYSPE_CLANG_DIAG_WSHORTEN +# pragma clang diagnostic pop +#endif + static double kwsysProcessTimeToDouble(kwsysProcessTime t) { return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001; diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in index 16efaefdf3..7cef029bbb 100644 --- a/Source/kwsys/Status.hxx.in +++ b/Source/kwsys/Status.hxx.in @@ -7,6 +7,16 @@ #include <string> +/* + * Detect a symbol collision with the name of this class. X11 headers use + * `#define Status int` instead of using `typedef` which poisons any other + * usage of this name. + */ +#if defined(Status) && defined(_X11_XLIB_H_) +# error \ + "Status.hxx must be included *before* any X11 headers to avoid a collision with the `Status` define that is made in its API." +#endif + namespace @KWSYS_NAMESPACE@ { /** \class Status diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index e6cc48f280..20e2edbffc 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -482,7 +482,7 @@ protected: unsigned int); // For windows // For Linux and Cygwin, /proc/cpuinfo formats are slightly different - bool RetreiveInformationFromCpuInfoFile(); + bool RetrieveInformationFromCpuInfoFile(); std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, size_t init = 0); @@ -1520,7 +1520,7 @@ void SystemInformationImplementation::RunCPUCheck() #elif defined(__hpux) this->QueryHPUXProcessor(); #elif defined(__linux) || defined(__CYGWIN__) - this->RetreiveInformationFromCpuInfoFile(); + this->RetrieveInformationFromCpuInfoFile(); #else this->QueryProcessor(); #endif @@ -3435,7 +3435,7 @@ std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( } /** Query for the cpu status */ -bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +bool SystemInformationImplementation::RetrieveInformationFromCpuInfoFile() { this->NumberOfLogicalCPU = 0; this->NumberOfPhysicalCPU = 0; diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index a20901cb29..fdd6b2d725 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -36,6 +36,7 @@ #ifdef _WIN32 # include <cwchar> +# include <unordered_map> #endif // Work-around CMake dependency scanning limitation. This must @@ -506,16 +507,39 @@ public: }; #ifdef _WIN32 -struct SystemToolsPathCaseCmp +# if defined(_WIN64) +static constexpr size_t FNV_OFFSET_BASIS = 14695981039346656037ULL; +static constexpr size_t FNV_PRIME = 1099511628211ULL; +# else +static constexpr size_t FNV_OFFSET_BASIS = 2166136261U; +static constexpr size_t FNV_PRIME = 16777619U; +# endif + +// Case insensitive Fnv1a hash +struct SystemToolsPathCaseHash +{ + size_t operator()(std::string const& path) const + { + size_t hash = FNV_OFFSET_BASIS; + for (auto c : path) { + hash ^= static_cast<size_t>(std::tolower(c)); + hash *= FNV_PRIME; + } + + return hash; + } +}; + +struct SystemToolsPathCaseEqual { bool operator()(std::string const& l, std::string const& r) const { # ifdef _MSC_VER - return _stricmp(l.c_str(), r.c_str()) < 0; + return _stricmp(l.c_str(), r.c_str()) == 0; # elif defined(__GNUC__) - return strcasecmp(l.c_str(), r.c_str()) < 0; + return strcasecmp(l.c_str(), r.c_str()) == 0; # else - return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0; + return SystemTools::Strucmp(l.c_str(), r.c_str()) == 0; # endif } }; @@ -540,8 +564,12 @@ public: bool const cache); static std::string GetActualCaseForPathCached(std::string const& path); static const char* GetEnvBuffered(const char* key); - std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap; - std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap; + std::unordered_map<std::string, std::string, SystemToolsPathCaseHash, + SystemToolsPathCaseEqual> + FindFileMap; + std::unordered_map<std::string, std::string, SystemToolsPathCaseHash, + SystemToolsPathCaseEqual> + PathCaseMap; std::map<std::string, std::string> EnvMap; #endif #ifdef __CYGWIN__ diff --git a/Tests/CustomCommandByproducts/CMakeLists.txt b/Tests/CustomCommandByproducts/CMakeLists.txt index 08c897c2d8..e391a6f286 100644 --- a/Tests/CustomCommandByproducts/CMakeLists.txt +++ b/Tests/CustomCommandByproducts/CMakeLists.txt @@ -149,6 +149,29 @@ set_property(TARGET ExternalLibraryWithSubstitution PROPERTY IMPORTED_LOCATION ${binary_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}) add_dependencies(ExternalLibraryWithSubstitution ExtTargetSubst) +# Generate the library file of an imported target as an install byproduct +# of an external project. The byproduct uses <INSTALL_DIR> that is substituted +# by the real install path +if(_isMultiConfig) + set(cfg /${CMAKE_CFG_INTDIR}) +else() + set(cfg) +endif() +include(ExternalProject) +ExternalProject_Add(ExtTargetInstallSubst + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External" + DOWNLOAD_COMMAND "" + INSTALL_COMMAND + "${CMAKE_COMMAND}" -E copy_directory "<BINARY_DIR>${cfg}" "<INSTALL_DIR>${cfg}" + BUILD_BYPRODUCTS "<BINARY_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}" + INSTALL_BYPRODUCTS "<INSTALL_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) +ExternalProject_Get_Property(ExtTargetInstallSubst install_dir) +add_library(ExternalLibraryWithInstallDirSubstitution STATIC IMPORTED) +set_property(TARGET ExternalLibraryWithInstallDirSubstitution PROPERTY IMPORTED_LOCATION + ${install_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}) +add_dependencies(ExternalLibraryWithInstallDirSubstitution ExtTargetInstallSubst) + # Add an executable consuming all the byproducts. add_executable(CustomCommandByproducts CustomCommandByproducts.c @@ -169,6 +192,18 @@ add_dependencies(CustomCommandByproducts Producer2) target_link_libraries(CustomCommandByproducts ExternalLibrary) +add_executable(ExternalLibraryByproducts ExternalLibraryByproducts.c) +target_link_libraries(ExternalLibraryByproducts ExternalLibrary) + +add_executable(ExternalLibraryByproducts_WithSubstitution ExternalLibraryByproducts.c) +target_link_libraries(ExternalLibraryByproducts_WithSubstitution ExternalLibraryWithSubstitution) + +add_executable(ExternalLibraryByproducts_WithInstallDirSubstitution ExternalLibraryByproducts.c) +target_link_libraries( + ExternalLibraryByproducts_WithInstallDirSubstitution + ExternalLibraryWithInstallDirSubstitution +) + if(CMAKE_GENERATOR STREQUAL "Ninja") add_custom_target(CheckNinja ALL COMMENT "Checking build.ninja" diff --git a/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c new file mode 100644 index 0000000000..3588e53b30 --- /dev/null +++ b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c @@ -0,0 +1,5 @@ +extern int ExternalLibrary(void); +int main(void) +{ + return (ExternalLibrary() + 1); +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index ec144c8099..ad5cbb2d45 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -703,7 +703,8 @@ add_RunCMake_test(target_sources) add_RunCMake_test(CheckCompilerFlag -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_ISPC=${CMake_TEST_ISPC} -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID} - -DCMake_TEST_HIP=${CMake_TEST_HIP}) + -DCMake_TEST_HIP=${CMake_TEST_HIP} + -DCMake_TEST_Swift=${CMake_TEST_Swift}) add_RunCMake_test(CheckSourceCompiles -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_ISPC=${CMake_TEST_ISPC} -DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID} diff --git a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake new file mode 100644 index 0000000000..23b300694b --- /dev/null +++ b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake @@ -0,0 +1,21 @@ +enable_language (Swift) +include(CheckCompilerFlag) + +set(Swift 1) + +# test that the check uses an isolated locale +set(_env_LC_ALL "${LC_ALL}") +set(ENV{LC_ALL} "BAD") + +check_compiler_flag(Swift "-foo-as-blarpy" SHOULD_FAIL) +if(SHOULD_FAIL) + message(SEND_ERROR "invalid Swift compile flag didn't fail.") +endif() + +check_compiler_flag(Swift "-parseable-output" SHOULD_WORK) +if(NOT SHOULD_WORK) + message(SEND_ERROR "Swift compiler flag '-parseable-output' check failed") +endif() + +# Reset locale +set(ENV{LC_ALL} ${_env_LC_ALL}) diff --git a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake index b0e025c4f6..81429a66c5 100644 --- a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake +++ b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake @@ -32,3 +32,7 @@ endif() if(APPLE) run_cmake(HeaderpadWorkaround) endif() + +if(CMake_TEST_Swift) + run_cmake(CheckCompilerFlagSwift) +endif() diff --git a/Tests/RunCMake/block/Scope-POLICIES.cmake b/Tests/RunCMake/block/Scope-POLICIES.cmake index 789b3d9d97..9536a99755 100644 --- a/Tests/RunCMake/block/Scope-POLICIES.cmake +++ b/Tests/RunCMake/block/Scope-POLICIES.cmake @@ -2,6 +2,9 @@ set(VAR1 "OUTER1") set(VAR2 "OUTER2") +set(VARSUB1 "OUTERSUB1") +set(VARSUB2 "OUTERSUB2") + cmake_policy(SET CMP0139 NEW) # create a block with a new scope for policies @@ -9,6 +12,7 @@ block(SCOPE_FOR POLICIES) set(VAR1 "INNER1") unset(VAR2) set(VAR3 "INNER3") + add_subdirectory(Scope) cmake_policy(SET CMP0139 OLD) endblock() @@ -23,6 +27,12 @@ endif() if(NOT DEFINED VAR3 OR NOT VAR3 STREQUAL "INNER3") message(SEND_ERROR "block/endblock: VAR3 has unexpected value: ${VAR3}") endif() +if(NOT DEFINED VARSUB1 OR NOT VARSUB1 STREQUAL "SUBDIR1") + message(SEND_ERROR "block/endblock: VARSUB1 has unexpected value: ${VARSUB1}") +endif() +if(NOT DEFINED VARSUB2 OR NOT VARSUB2 STREQUAL "SUBDIR2") + message(SEND_ERROR "block/endblock: VARSUB2 has unexpected value: ${VARSUB2}") +endif() cmake_policy(GET CMP0139 CMP0139_STATUS) if(NOT CMP0139_STATUS STREQUAL "NEW") diff --git a/Tests/RunCMake/block/Scope-VARIABLES.cmake b/Tests/RunCMake/block/Scope-VARIABLES.cmake index 140e63880f..ac8da140c0 100644 --- a/Tests/RunCMake/block/Scope-VARIABLES.cmake +++ b/Tests/RunCMake/block/Scope-VARIABLES.cmake @@ -8,16 +8,20 @@ set(VAR5 "OUTER5") set(VAR6 "CACHE6" CACHE STRING "") set(VAR6 "OUTER6") +set(VARSUB1 "OUTERSUB1") +set(VARSUB2 "OUTERSUB2") + cmake_policy(SET CMP0139 NEW) # create a block with a new scope for variables -block(SCOPE_FOR VARIABLES PROPAGATE VAR3 VAR4 VAR5 VAR6 VAR7) +block(SCOPE_FOR VARIABLES PROPAGATE VAR3 VAR4 VAR5 VAR6 VAR7 VARSUB2) set(VAR1 "INNER1") set(VAR2 "INNER2" PARENT_SCOPE) set(VAR3 "INNER3") unset(VAR4) unset(VAR6) set(VAR7 "INNER7") + add_subdirectory(Scope) cmake_policy(SET CMP0139 OLD) endblock() @@ -45,6 +49,12 @@ endif() if(NOT DEFINED VAR7 OR NOT VAR7 STREQUAL "INNER7") message(SEND_ERROR "block/endblock: VAR7 has unexpected value: ${VAR7}") endif() +if(NOT DEFINED VARSUB1 OR NOT VARSUB1 STREQUAL "OUTERSUB1") + message(SEND_ERROR "block/endblock: VARSUB1 has unexpected value: ${VARSUB1}") +endif() +if(NOT DEFINED VARSUB2 OR NOT VARSUB2 STREQUAL "SUBDIR2") + message(SEND_ERROR "block/endblock: VARSUB2 has unexpected value: ${VARSUB2}") +endif() cmake_policy(GET CMP0139 CMP0139_STATUS) if(NOT CMP0139_STATUS STREQUAL "OLD") diff --git a/Tests/RunCMake/block/Scope.cmake b/Tests/RunCMake/block/Scope.cmake index e1af50a256..ef43df6043 100644 --- a/Tests/RunCMake/block/Scope.cmake +++ b/Tests/RunCMake/block/Scope.cmake @@ -8,16 +8,20 @@ set(VAR5 "OUTER5") set(VAR6 "CACHE6" CACHE STRING "") set(VAR6 "OUTER6") +set(VARSUB1 "OUTERSUB1") +set(VARSUB2 "OUTERSUB2") + cmake_policy(SET CMP0139 NEW) # create a block with a new scope for variables and policies -block(PROPAGATE VAR3 VAR4 VAR5 VAR6 VAR7) +block(PROPAGATE VAR3 VAR4 VAR5 VAR6 VAR7 VARSUB2) set(VAR1 "INNER1") set(VAR2 "INNER2" PARENT_SCOPE) set(VAR3 "INNER3") unset(VAR4) unset(VAR6) set(VAR7 "INNER7") + add_subdirectory(Scope) cmake_policy(SET CMP0139 OLD) endblock() @@ -45,6 +49,12 @@ endif() if(NOT DEFINED VAR7 OR NOT VAR7 STREQUAL "INNER7") message(SEND_ERROR "block/endblock: VAR6 has unexpected value: ${VAR7}") endif() +if(NOT DEFINED VARSUB1 OR NOT VARSUB1 STREQUAL "OUTERSUB1") + message(SEND_ERROR "block/endblock: VARSUB1 has unexpected value: ${VARSUB1}") +endif() +if(NOT DEFINED VARSUB2 OR NOT VARSUB2 STREQUAL "SUBDIR2") + message(SEND_ERROR "block/endblock: VARSUB2 has unexpected value: ${VARSUB2}") +endif() cmake_policy(GET CMP0139 CMP0139_STATUS) if(NOT CMP0139_STATUS STREQUAL "NEW") diff --git a/Tests/RunCMake/block/Scope/CMakeLists.txt b/Tests/RunCMake/block/Scope/CMakeLists.txt new file mode 100644 index 0000000000..afd79e301b --- /dev/null +++ b/Tests/RunCMake/block/Scope/CMakeLists.txt @@ -0,0 +1,2 @@ +set(VARSUB1 "SUBDIR1" PARENT_SCOPE) +set(VARSUB2 "SUBDIR2" PARENT_SCOPE) diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt index 6be13d608d..51603aa32a 100644 --- a/Utilities/ClangTidyModule/CMakeLists.txt +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -16,6 +16,8 @@ add_library(cmake-clang-tidy-module MODULE UseCmstrlenCheck.cxx UseCmstrlenCheck.h + UseCmsysFstreamCheck.cxx + UseCmsysFstreamCheck.h ) target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS}) target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy) diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx index a35c3367a3..a9d344ff4a 100644 --- a/Utilities/ClangTidyModule/Module.cxx +++ b/Utilities/ClangTidyModule/Module.cxx @@ -4,6 +4,7 @@ #include <clang-tidy/ClangTidyModuleRegistry.h> #include "UseCmstrlenCheck.h" +#include "UseCmsysFstreamCheck.h" namespace clang { namespace tidy { @@ -14,6 +15,8 @@ public: void addCheckFactories(ClangTidyCheckFactories& CheckFactories) override { CheckFactories.registerCheck<UseCmstrlenCheck>("cmake-use-cmstrlen"); + CheckFactories.registerCheck<UseCmsysFstreamCheck>( + "cmake-use-cmsys-fstream"); } }; diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt index 42027ed125..a66eaa8d3e 100644 --- a/Utilities/ClangTidyModule/Tests/CMakeLists.txt +++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt @@ -11,3 +11,4 @@ function(add_run_clang_tidy_test check_name) endfunction() add_run_clang_tidy_test(cmake-use-cmstrlen) +add_run_clang_tidy_test(cmake-use-cmsys-fstream) diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake index 486d592e2c..7fd7cddbf3 100644 --- a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake +++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake @@ -3,14 +3,12 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy") set(config_arg "--config-file=${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy") endif() -foreach(o out err) - if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-std${o}.txt") - file(READ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-std${o}.txt" expect_std${o}) - string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}") - else() - set(expect_std${o} "") - endif() -endforeach() +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt") + file(READ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt" expect_stdout) + string(REGEX REPLACE "\n+$" "" expect_stdout "${expect_stdout}") +else() + set(expect_stdout "") +endif() set(source_file "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}.cxx") configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" "${source_file}" COPYONLY) @@ -39,14 +37,12 @@ if(NOT result EQUAL 0) string(APPEND RunClangTidy_TEST_FAILED "Expected result: 0, actual result: ${result}\n") endif() -foreach(o out err) - string(REGEX REPLACE "\n+$" "" actual_std${o} "${actual_std${o}}") - if(NOT actual_std${o} STREQUAL expect_std${o}) - string(REPLACE "\n" "\n " expect_std${o}_formatted " ${expect_std${o}}") - string(REPLACE "\n" "\n " actual_std${o}_formatted " ${actual_std${o}}") - string(APPEND RunClangTidy_TEST_FAILED "Expected std${o}:\n${expect_std${o}_formatted}\nActual std${o}:\n${actual_std${o}_formatted}\n") - endif() -endforeach() +string(REGEX REPLACE "\n+$" "" actual_stdout "${actual_stdout}") +if(NOT actual_stdout STREQUAL expect_stdout) + string(REPLACE "\n" "\n " expect_stdout_formatted " ${expect_stdout}") + string(REPLACE "\n" "\n " actual_stdout_formatted " ${actual_stdout}") + string(APPEND RunClangTidy_TEST_FAILED "Expected stdout:\n${expect_stdout_formatted}\nActual stdout:\n${actual_stdout_formatted}\n") +endif() if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx") set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx") diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt deleted file mode 100644 index 9d9d2ed3c9..0000000000 --- a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stderr.txt +++ /dev/null @@ -1,2 +0,0 @@ -4 warnings generated. -clang-tidy applied 4 of 4 suggested fixes. diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx new file mode 100644 index 0000000000..5c7c12323f --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx @@ -0,0 +1,81 @@ +#include <fstream> +#include <vector> + +namespace cmsys { +using std::ifstream; +using std::ofstream; +using std::fstream; +} + +namespace ns { +using std::ifstream; +using std::ofstream; +using std::fstream; + +namespace ns { +using std::ifstream; +using std::ofstream; +using std::fstream; +} + +class cl +{ +public: + using ifstream = cmsys::ifstream; + using ofstream = cmsys::ofstream; + using fstream = cmsys::fstream; +}; + +using ifs = cmsys::ifstream; +using ofs = cmsys::ofstream; +using fs = cmsys::fstream; +} + +int main() +{ + using std::ifstream; + using std::ofstream; + using std::fstream; + + // Correction needed + cmsys::ifstream ifsUnqual; + cmsys::ifstream ifsQual; + cmsys::ifstream ifsNS; + cmsys::ifstream ifsNested; + cmsys::ifstream ifsClass; + cmsys::ifstream ifsRenamed; + + cmsys::ofstream ofsUnqual; + cmsys::ofstream ofsQual; + cmsys::ofstream ofsNS; + cmsys::ofstream ofsNested; + cmsys::ofstream ofsClass; + cmsys::ofstream ofsRenamed; + + cmsys::fstream fsUnqual; + cmsys::fstream fsQual; + cmsys::fstream fsNS; + cmsys::fstream fsNested; + cmsys::fstream fsClass; + cmsys::fstream fsRenamed; + + cmsys::ifstream::off_type offsetQual = 0; + cmsys::ifstream::off_type offsetUnqual = 0; + cmsys::ifstream::off_type offsetNS = 0; + cmsys::ifstream::off_type offsetNested = 0; + cmsys::ifstream::traits_type::off_type offsetTraitsNested = 0; + cmsys::ifstream::traits_type::off_type offsetTraitsClass = 0; + + std::vector<cmsys::ifstream> ifsVectorUnqual; + + // No correction needed + cmsys::ifstream ifsCmsys; + cmsys::ofstream ofsCmsys; + cmsys::fstream fsCmsys; + cmsys::ifstream::off_type offsetCmsys = 0; + cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0; + std::vector<cmsys::ifstream> ifsVectorCmsys; + std::basic_ifstream<wchar_t> ifsWchar; + + return 0; +} diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt new file mode 100644 index 0000000000..d2c45f2c10 --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt @@ -0,0 +1,155 @@ +cmake-use-cmsys-fstream.cxx:24:20: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + using ifstream = std::ifstream; + ^~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:24:20: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:25:20: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + using ofstream = std::ofstream; + ^~~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:25:20: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:26:19: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + using fstream = std::fstream; + ^~~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:26:19: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:29:13: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] +using ifs = std::ifstream; + ^~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:29:13: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:30:13: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] +using ofs = std::ofstream; + ^~~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:30:13: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:31:12: warning: use cmsys::fstream [cmake-use-cmsys-fstream] +using fs = std::fstream; + ^~~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:31:12: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:41:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ifstream ifsUnqual; + ^~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:41:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:42:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + std::ifstream ifsQual; + ^~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:42:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:43:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ifstream ifsNS; + ^~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:43:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:44:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ns::ifstream ifsNested; + ^~~~~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:44:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:45:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::cl::ifstream ifsClass; + ^~~~~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:45:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:46:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ifs ifsRenamed; + ^~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:46:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:48:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + ofstream ofsUnqual; + ^~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:48:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:49:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + std::ofstream ofsQual; + ^~~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:49:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:50:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + ns::ofstream ofsNS; + ^~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:50:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:51:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + ns::ns::ofstream ofsNested; + ^~~~~~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:51:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:52:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + ns::cl::ofstream ofsClass; + ^~~~~~~~~~~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:52:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:53:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream] + ns::ofs ofsRenamed; + ^~~~~~~ + cmsys::ofstream +cmake-use-cmsys-fstream.cxx:53:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:55:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + fstream fsUnqual; + ^~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:55:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:56:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + std::fstream fsQual; + ^~~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:56:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:57:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + ns::fstream fsNS; + ^~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:57:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:58:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + ns::ns::fstream fsNested; + ^~~~~~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:58:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:59:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + ns::ns::fstream fsClass; + ^~~~~~~~~~~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:59:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:60:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream] + ns::fs fsRenamed; + ^~~~~~ + cmsys::fstream +cmake-use-cmsys-fstream.cxx:60:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:62:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + std::ifstream::off_type offsetQual = 0; + ^~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:62:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:63:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ifstream::off_type offsetUnqual = 0; + ^~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:63:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:64:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ifstream::off_type offsetNS = 0; + ^~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:64:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:65:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ns::ifstream::off_type offsetNested = 0; + ^~~~~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:65:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:66:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0; + ^~~~~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:66:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:67:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0; + ^~~~~~~~~~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:67:3: note: FIX-IT applied suggested code changes +cmake-use-cmsys-fstream.cxx:69:15: warning: use cmsys::ifstream [cmake-use-cmsys-fstream] + std::vector<ifstream> ifsVectorUnqual; + ^~~~~~~~ + cmsys::ifstream +cmake-use-cmsys-fstream.cxx:69:15: note: FIX-IT applied suggested code changes diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx new file mode 100644 index 0000000000..56a7611dcb --- /dev/null +++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx @@ -0,0 +1,81 @@ +#include <fstream> +#include <vector> + +namespace cmsys { +using std::ifstream; +using std::ofstream; +using std::fstream; +} + +namespace ns { +using std::ifstream; +using std::ofstream; +using std::fstream; + +namespace ns { +using std::ifstream; +using std::ofstream; +using std::fstream; +} + +class cl +{ +public: + using ifstream = std::ifstream; + using ofstream = std::ofstream; + using fstream = std::fstream; +}; + +using ifs = std::ifstream; +using ofs = std::ofstream; +using fs = std::fstream; +} + +int main() +{ + using std::ifstream; + using std::ofstream; + using std::fstream; + + // Correction needed + ifstream ifsUnqual; + std::ifstream ifsQual; + ns::ifstream ifsNS; + ns::ns::ifstream ifsNested; + ns::cl::ifstream ifsClass; + ns::ifs ifsRenamed; + + ofstream ofsUnqual; + std::ofstream ofsQual; + ns::ofstream ofsNS; + ns::ns::ofstream ofsNested; + ns::cl::ofstream ofsClass; + ns::ofs ofsRenamed; + + fstream fsUnqual; + std::fstream fsQual; + ns::fstream fsNS; + ns::ns::fstream fsNested; + ns::ns::fstream fsClass; + ns::fs fsRenamed; + + std::ifstream::off_type offsetQual = 0; + ifstream::off_type offsetUnqual = 0; + ns::ifstream::off_type offsetNS = 0; + ns::ns::ifstream::off_type offsetNested = 0; + ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0; + ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0; + + std::vector<ifstream> ifsVectorUnqual; + + // No correction needed + cmsys::ifstream ifsCmsys; + cmsys::ofstream ofsCmsys; + cmsys::fstream fsCmsys; + cmsys::ifstream::off_type offsetCmsys = 0; + cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0; + std::vector<cmsys::ifstream> ifsVectorCmsys; + std::basic_ifstream<wchar_t> ifsWchar; + + return 0; +} diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx new file mode 100644 index 0000000000..95a0a4d6fa --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx @@ -0,0 +1,101 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "UseCmsysFstreamCheck.h" + +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +using namespace ast_matchers; + +UseCmsysFstreamCheck::UseCmsysFstreamCheck(StringRef Name, + ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) +{ +} + +void UseCmsysFstreamCheck::registerMatchers(MatchFinder* Finder) +{ + this->createMatcher("::std::basic_ifstream", "::cmsys::ifstream", Finder, + "ifstream"); + this->createMatcher("::std::basic_ofstream", "::cmsys::ofstream", Finder, + "ofstream"); + this->createMatcher("::std::basic_fstream", "::cmsys::fstream", Finder, + "fstream"); +} + +void UseCmsysFstreamCheck::check(const MatchFinder::MatchResult& Result) +{ + const TypeLoc* ParentTypeNode = + Result.Nodes.getNodeAs<TypeLoc>("parentType"); + const NestedNameSpecifierLoc* ParentNameNode = + Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("parentName"); + const TypeLoc* RootNode = nullptr; + StringRef BindName; + StringRef Warning; + + if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ifstream")) != nullptr) { + BindName = "cmsys::ifstream"; + Warning = "use cmsys::ifstream"; + } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ofstream")) != + nullptr) { + BindName = "cmsys::ofstream"; + Warning = "use cmsys::ofstream"; + } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("fstream")) != + nullptr) { + BindName = "cmsys::fstream"; + Warning = "use cmsys::fstream"; + } + + if (ParentTypeNode != nullptr) { + if (ParentTypeNode->getBeginLoc().isValid()) { + this->diag(ParentTypeNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement(ParentTypeNode->getSourceRange(), + BindName); + } + } else if (ParentNameNode != nullptr) { + if (ParentNameNode->getBeginLoc().isValid()) { + this->diag(ParentNameNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement( + SourceRange(ParentNameNode->getBeginLoc(), RootNode->getEndLoc()), + BindName); + } + } else if (RootNode != nullptr) { + if (RootNode->getBeginLoc().isValid()) { + this->diag(RootNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement(RootNode->getSourceRange(), BindName); + } + } +} + +void UseCmsysFstreamCheck::createMatcher(StringRef StdName, + StringRef CmsysName, + ast_matchers::MatchFinder* Finder, + StringRef Bind) +{ + TypeLocMatcher IsStd = loc(qualType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(classTemplateSpecializationDecl( + hasName(StdName), + hasTemplateArgument( + 0, templateArgument(refersToType(asString("char")))))))))); + + // TODO This only checks to see if the type directly refers to + // cmsys::fstream. There are some corner cases involving template parameters + // that refer to cmsys::fstream that are missed by this matcher, resulting in + // a false positive. Figure out how to find these indirect references to + // cmsys::fstream and filter them out. In the meantime, such false positives + // can be silenced with NOLINT(cmake-use-cmsys-fstream). + TypeLocMatcher IsCmsys = + loc(usingType(throughUsingDecl(namedDecl(hasName(CmsysName))))); + + Finder->addMatcher( + typeLoc(IsStd, unless(IsCmsys), unless(elaboratedTypeLoc()), + optionally(hasParent(elaboratedTypeLoc().bind("parentType"))), + optionally(hasParent(nestedNameSpecifierLoc().bind("parentName")))) + .bind(Bind), + this); +} +} +} +} diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h new file mode 100644 index 0000000000..782123c12a --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <clang-tidy/ClangTidyCheck.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +class UseCmsysFstreamCheck : public ClangTidyCheck +{ +public: + UseCmsysFstreamCheck(StringRef Name, ClangTidyContext* Context); + void registerMatchers(ast_matchers::MatchFinder* Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult& Result) override; + +private: + void createMatcher(StringRef name, StringRef CmsysName, + ast_matchers::MatchFinder* Finder, StringRef bind); +}; +} +} +} |