FILE_SET: add SKIP_LINTING property support
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 571585d..73f880f1 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -552,6 +552,7 @@
    /prop_fs/INTERFACE_INCLUDE_DIRECTORIES
    /prop_fs/INTERFACE_SOURCES
    /prop_fs/SCOPE
+   /prop_fs/SKIP_LINTING
    /prop_fs/SOURCES
    /prop_fs/TYPE
 
diff --git a/Help/prop_fs/SKIP_LINTING.rst b/Help/prop_fs/SKIP_LINTING.rst
new file mode 100644
index 0000000..7c6546e
--- /dev/null
+++ b/Help/prop_fs/SKIP_LINTING.rst
@@ -0,0 +1,54 @@
+SKIP_LINTING
+------------
+
+.. versionadded:: 4.4
+
+This property allows you to exclude a source files of the specific file set
+from the linting process. The linting process involves running
+tools such as :prop_tgt:`<LANG>_CPPLINT`, :prop_tgt:`<LANG>_CLANG_TIDY`,
+:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT`,
+:prop_tgt:`<LANG>_PVS_STUDIO` and :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` on
+the source files, as well as compiling header files as part of
+:prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`. By setting ``SKIP_LINTING`` on a
+file set, the mentioned linting tools will not be executed for the files of
+that particular file set.  If the :prop_fs:`SKIP_LINTING` file set property
+is set, it takes precedence over this source-file and target-wide properties.
+
+This is a convenience alternative to setting the :prop_sf:`SKIP_LINTING`
+source file property individually on each source.
+
+Example
+^^^^^^^
+
+Consider a C++ project that includes multiple source files,
+such as ``main.cpp``, ``things.cpp``, and ``generatedBindings.cpp``.
+In this example, you want to exclude the ``things.cpp`` and
+``generatedBindings.cpp`` files from the linting process. To achieve this, you
+can use a file set and utilize the ``SKIP_LINTING`` property with the
+:command:`set_property(FILE_SET) <set_property>` command as shown below:
+
+.. code-block:: cmake
+
+  add_executable(MyApp main.cpp)
+  target_sources(MyApp PRIVATE FILE_SET skip_lint TYPE SOURCES
+                               FILES things.cpp generatedBindings.cpp)
+
+  set_property(FILE_SET skip_lint TARGET MyApp PROPERTY SKIP_LINTING ON)
+
+In the provided code snippet, the ``SKIP_LINTING`` property is set to true
+for the ``skip_lint`` file set. As a result, when the linting
+tools specified by :prop_tgt:`<LANG>_CPPLINT`, :prop_tgt:`<LANG>_CLANG_TIDY`,
+:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT` or
+:prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` are executed, they will skip analyzing
+the ``things.cpp`` and ``generatedBindings.cpp`` files.
+
+By using the ``SKIP_LINTING`` file set property, you can selectively exclude
+specific source files from the linting process. This allows you to focus the
+linting tools on the relevant parts of your project, enhancing the efficiency
+and effectiveness of the linting workflow.
+
+See Also
+^^^^^^^^
+
+* :prop_sf:`SKIP_LINTING` source file property
+* :prop_tgt:`SKIP_LINTING` target property
diff --git a/Help/prop_sf/SKIP_LINTING.rst b/Help/prop_sf/SKIP_LINTING.rst
index 5d2c0c4..07e5cd1 100644
--- a/Help/prop_sf/SKIP_LINTING.rst
+++ b/Help/prop_sf/SKIP_LINTING.rst
@@ -43,7 +43,11 @@
 linting tools on the relevant parts of your project, enhancing the efficiency
 and effectiveness of the linting workflow.
 
+A convenient alternative, when multiple sources should be excluded from the
+linting process, is to use the file set's :prop_fs:`SKIP_LINTING` property.
+
 See Also
 ^^^^^^^^
 
+* :prop_fs:`SKIP_LINTING` file set property
 * :prop_tgt:`SKIP_LINTING` target property
diff --git a/Help/prop_tgt/SKIP_LINTING.rst b/Help/prop_tgt/SKIP_LINTING.rst
index 031f653..996c4ee 100644
--- a/Help/prop_tgt/SKIP_LINTING.rst
+++ b/Help/prop_tgt/SKIP_LINTING.rst
@@ -10,16 +10,19 @@
 :prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT` and
 :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE`) will not be invoked for source files
 compiled by the target.  If the :prop_sf:`SKIP_LINTING` source-file property
-is set on a specific source, it takes precedence over this target-wide property.
+is set on a specific source or if the :prop_fs:`SKIP_LINTING` file set property
+is set, it takes precedence over this target-wide property.
 
 This is a convenience alternative to setting the :prop_sf:`SKIP_LINTING`
 source file property individually on each source.  If either the target's
-:prop_tgt:`SKIP_LINTING` or a source’s :prop_sf:`SKIP_LINTING` is enabled,
-that source will be excluded from linting.
+:prop_tgt:`SKIP_LINTING` or file set's :prop_fs:`SKIP_LINTING` including this
+source or a source’s :prop_sf:`SKIP_LINTING` is enabled, that source will be
+excluded from linting.
 
 The property has no effect on targets that do not have sources.
 
 See Also
 ^^^^^^^^
 
+* :prop_fs:`SKIP_LINTING` file set property
 * :prop_sf:`SKIP_LINTING` source file property
diff --git a/Help/release/dev/FILE_SET-SKIP_LINTING.rst b/Help/release/dev/FILE_SET-SKIP_LINTING.rst
new file mode 100644
index 0000000..eeca0cd
--- /dev/null
+++ b/Help/release/dev/FILE_SET-SKIP_LINTING.rst
@@ -0,0 +1,5 @@
+FILE_SET-SKIP_LINTING
+---------------------
+
+* File sets gained the support of the :prop_fs:`SKIP_LINTING` file set
+  property.
diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx
index 6aa2ee4..615c45b 100644
--- a/Source/cmFastbuildNormalTargetGenerator.cxx
+++ b/Source/cmFastbuildNormalTargetGenerator.cxx
@@ -1141,10 +1141,16 @@
 std::string cmFastbuildNormalTargetGenerator::ComputeCodeCheckOptions(
   cmSourceFile const& srcFile)
 {
+  cmGeneratorFileSet const* fileSet =
+    this->GeneratorTarget->GetFileSetForSource(Config, &srcFile);
+  cmValue const fsSkipCodeCheckVal =
+    fileSet ? fileSet->GetProperty("SKIP_LINTING") : nullptr;
   cmValue const srcSkipCodeCheckVal = srcFile.GetProperty("SKIP_LINTING");
-  bool const skipCodeCheck = srcSkipCodeCheckVal.IsSet()
-    ? srcSkipCodeCheckVal.IsOn()
-    : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING");
+  bool const skipCodeCheck = fsSkipCodeCheckVal.IsSet()
+    ? fsSkipCodeCheckVal.IsOn()
+    : (srcSkipCodeCheckVal.IsSet()
+         ? srcSkipCodeCheckVal.IsOn()
+         : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING"));
 
   if (skipCodeCheck) {
     return {};
diff --git a/Source/cmGeneratorTarget_HeaderSetVerification.cxx b/Source/cmGeneratorTarget_HeaderSetVerification.cxx
index 57d82b2..a84ad97 100644
--- a/Source/cmGeneratorTarget_HeaderSetVerification.cxx
+++ b/Source/cmGeneratorTarget_HeaderSetVerification.cxx
@@ -89,8 +89,11 @@
     std::set<cmGeneratorFileSet const*> fileSets;
     for (auto const& fileSet : fileSetEntries) {
       if (all || verifySet.count(fileSet->GetName())) {
-        fileSets.insert(fileSet);
         verifySet.erase(fileSet->GetName());
+        if (fileSet->GetProperty("SKIP_LINTING").IsOn()) {
+          continue;
+        }
+        fileSets.insert(fileSet);
       }
     }
 
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 77b1550..31300f4 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -1107,10 +1107,14 @@
       compilerLauncher = GetCompilerLauncher(lang, config);
     }
 
+    cmValue const fsSkipCodeCheckVal =
+      fileSet ? fileSet->GetProperty("SKIP_LINTING") : nullptr;
     cmValue const srcSkipCodeCheckVal = source.GetProperty("SKIP_LINTING");
-    bool const skipCodeCheck = srcSkipCodeCheckVal.IsSet()
-      ? srcSkipCodeCheckVal.IsOn()
-      : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING");
+    bool const skipCodeCheck = fsSkipCodeCheckVal.IsSet()
+      ? fsSkipCodeCheckVal.IsOn()
+      : (srcSkipCodeCheckVal.IsSet()
+           ? srcSkipCodeCheckVal.IsOn()
+           : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING"));
 
     if (!skipCodeCheck) {
       std::string const codeCheck = this->GenerateCodeCheckRules(
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 762da6c..c20ceb5 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1585,10 +1585,17 @@
 
   auto compilerLauncher = this->GetCompilerLauncher(language, config);
 
+  cmGeneratorFileSet const* fileSet =
+    this->GeneratorTarget->GetFileSetForSource(config, source);
+
+  cmValue const fsSkipCodeCheckVal =
+    fileSet ? fileSet->GetProperty("SKIP_LINTING") : nullptr;
   cmValue const srcSkipCodeCheckVal = source->GetProperty("SKIP_LINTING");
-  bool const skipCodeCheck = srcSkipCodeCheckVal.IsSet()
-    ? srcSkipCodeCheckVal.IsOn()
-    : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING");
+  bool const skipCodeCheck = fsSkipCodeCheckVal.IsSet()
+    ? fsSkipCodeCheckVal.IsOn()
+    : (srcSkipCodeCheckVal.IsSet()
+         ? srcSkipCodeCheckVal.IsOn()
+         : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING"));
 
   if (!skipCodeCheck) {
     auto const cmakeCmd =
diff --git a/Tests/RunCMake/MultiLint/RunCMakeTest.cmake b/Tests/RunCMake/MultiLint/RunCMakeTest.cmake
index b9b69fb..a42945a 100644
--- a/Tests/RunCMake/MultiLint/RunCMakeTest.cmake
+++ b/Tests/RunCMake/MultiLint/RunCMakeTest.cmake
@@ -28,9 +28,9 @@
   run_multilint(genex)
 endif()
 
-function(run_skip_linting test_name prop_sf prop_tgt)
-  set(RunCMake_TEST_VARIANT_DESCRIPTION " (prop_sf=${prop_sf}, prop_tgt=${prop_tgt})")
-  list(APPEND RunCMake_TEST_OPTIONS "-Dprop_sf=${prop_sf}" "-Dprop_tgt=${prop_tgt}")
+function(run_skip_linting test_name prop_fs prop_sf prop_tgt)
+  set(RunCMake_TEST_VARIANT_DESCRIPTION " (prop_fs=${prop_fs}, prop_sf=${prop_sf}, prop_tgt=${prop_tgt})")
+  list(APPEND RunCMake_TEST_OPTIONS "-Dprop_fs=${prop_fs}" "-Dprop_sf=${prop_sf}" "-Dprop_tgt=${prop_tgt}")
 
   set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test_name}-build")
   set(RunCMake_TEST_NO_CLEAN 1)
@@ -40,52 +40,90 @@
   run_cmake_command(${test_name}-Build ${CMAKE_COMMAND} --build .)
 endfunction()
 
-# There are a few `SKIP_LINTING` source/target propertiy combinations
+# There are a few `SKIP_LINTING` file set/source/target propertiy combinations
 # that affect the final result:
 #
-#  prop_sf   prop_tgt   result
-#  ---------------------------
-#    -         -         OFF
-#    OFF       -         OFF
-#    ON        -         ON
-#    -         OFF       OFF
-#    OFF       OFF       OFF
-#    ON        OFF       ON
-#    -         ON        ON
-#    OFF       ON        OFF
-#    ON        ON        ON
+#  prop_fs  prop_sf   prop_tgt   result
+#  ------------------------------------
+#    -        -         -         OFF
+#    OFF      -         -         OFF
+#    ON       -         -         ON
+#    -        OFF       -         OFF
+#    OFF      OFF       -         OFF
+#    ON       OFF       -         ON
+#    -        ON        -         ON
+#    OFF      ON        -         OFF
+#    ON       ON        -         ON
+#    -        -         OFF       OFF
+#    OFF      -         OFF       OFF
+#    ON       -         OFF       ON
+#    -        -         ON        ON
+#    OFF      -         ON        OFF
+#    ON       -         ON        ON
+#    -        OFF       OFF       OFF
+#    OFF      OFF       OFF       OFF
+#    ON       OFF       OFF       ON
+#    -        OFF       ON        OFF
+#    OFF      OFF       ON        OFF
+#    ON       OFF       ON        ON
+#    -        ON        OFF       ON
+#    OFF      ON        OFF       OFF
+#    ON       ON        OFF       ON
+#    -        ON        ON        ON
+#    OFF      ON        ON        OFF
+#    ON       ON        ON        ON
 #
 # where `-` means unset property.
 #
 # Here's the same table for convenience sorted by `result`:
 #
-#  prop_sf   prop_tgt   result
-#  ---------------------------
-#    -         -         OFF
-#    OFF       -         OFF
-#    -         OFF       OFF
-#    OFF       OFF       OFF
-#    OFF       ON        OFF
-#    ON        -         ON
-#    ON        OFF       ON
-#    -         ON        ON
-#    ON        ON        ON
+#  prop_fs  prop_sf   prop_tgt   result
+#  ------------------------------------
+#    -        -         -         OFF
+#    OFF      -         -         OFF
+#    -        OFF       -         OFF
+#    OFF      OFF       -         OFF
+#    OFF      ON        -         OFF
+#    -        -         OFF       OFF
+#    OFF      -         OFF       OFF
+#    OFF      -         ON        OFF
+#    -        OFF       OFF       OFF
+#    OFF      OFF       OFF       OFF
+#    -        OFF       ON        OFF
+#    OFF      OFF       ON        OFF
+#    OFF      ON        OFF       OFF
+#    OFF      ON        ON        OFF
+#    ON       -         -         ON
+#    ON       OFF       -         ON
+#    -        ON        -         ON
+#    ON       ON        -         ON
+#    ON       -         OFF       ON
+#    -        -         ON        ON
+#    ON       -         ON        ON
+#    ON       OFF       OFF       ON
+#    ON       OFF       ON        ON
+#    -        ON        OFF       ON
+#    ON       ON        OFF       ON
+#    -        ON        ON        ON
+#    ON       ON        ON        ON
 
 foreach(lang IN ITEMS C CXX)
   # Testing `SKIP_LINTING=OFF` (first half of the table above)
-  set(prop_sf_OFF_variants "-" OFF "-" OFF OFF)
-  set(prop_tgt_OFF_variants "-" "-" OFF OFF ON)
-  foreach(prop_fs prop_tgt IN ZIP_LISTS prop_sf_OFF_variants prop_tgt_OFF_variants)
-    run_skip_linting(${lang}_skip_linting_OFF "${prop_fs}" "${prop_tgt}")
+  set(prop_fs_OFF_variants  "-" OFF "-" OFF OFF "-" OFF OFF "-" OFF "-" OFF OFF OFF)
+  set(prop_sf_OFF_variants  "-" "-" OFF OFF ON  "-" "-" "-" OFF OFF OFF OFF ON  ON)
+  set(prop_tgt_OFF_variants "-" "-" "-" "-" "-" OFF OFF ON  OFF OFF ON  ON  OFF ON)
+  foreach(prop_fs prop_sf prop_tgt IN ZIP_LISTS prop_fs_OFF_variants prop_sf_OFF_variants prop_tgt_OFF_variants)
+    run_skip_linting(${lang}_skip_linting_OFF "${prop_fs}" "${prop_sf}" "${prop_tgt}")
   endforeach()
 
   # Testing `SKIP_LINTING=ON` (second half of the table above)
-  set(prop_sf_ON_variants ON ON "-" ON)
-  set(prop_tgt_ON_variants "-" OFF ON ON)
-  foreach(prop_fs prop_tgt IN ZIP_LISTS prop_sf_ON_variants prop_tgt_ON_variants)
-    run_skip_linting(${lang}_skip_linting_ON "${prop_fs}" "${prop_tgt}")
+  set(prop_fs_ON_variants  ON  ON  "-" ON  ON  "-" ON  ON  ON  "-" ON  "-" ON)
+  set(prop_sf_ON_variants  "-" OFF ON  ON  "-" "-" "-" OFF OFF ON  ON  ON  ON)
+  set(prop_tgt_ON_variants "-" "-" "-" "-" OFF ON  ON  OFF ON  OFF OFF ON  ON)
+  foreach(prop_fs prop_sf prop_tgt IN ZIP_LISTS prop_fs_ON_variants prop_sf_ON_variants prop_tgt_ON_variants)
+    run_skip_linting(${lang}_skip_linting_ON "${prop_fs}" "${prop_sf}" "${prop_tgt}")
     if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
-      run_skip_linting(${lang}-launch_skip_linting_ON "${prop_fs}" "${prop_tgt}")
+      run_skip_linting(${lang}-launch_skip_linting_ON "${prop_fs}" "${prop_sf}" "${prop_tgt}")
     endif()
   endforeach()
 endforeach()
diff --git a/Tests/RunCMake/MultiLint/setup_skip_linter_test.cmake b/Tests/RunCMake/MultiLint/setup_skip_linter_test.cmake
index ab8d646..a655339 100644
--- a/Tests/RunCMake/MultiLint/setup_skip_linter_test.cmake
+++ b/Tests/RunCMake/MultiLint/setup_skip_linter_test.cmake
@@ -12,7 +12,12 @@
   set(CMAKE_${lang}_CPPCHECK "${maybe_genex_pre}${PSEUDO_CPPCHECK}${maybe_genex_post}" -error)
 
   string(TOLOWER "${lang}" ext)
-  add_executable(main main.${ext})
+  add_executable(main)
+  target_sources(main PRIVATE FILE_SET SOURCES FILES main.${ext})
+
+  if(NOT prop_fs STREQUAL "-")
+    set_property(FILE_SET SOURCES TARGET main PROPERTY SKIP_LINTING ${prop_fs})
+  endif()
 
   if(NOT prop_sf STREQUAL "-")
     set_source_files_properties(main.${ext} PROPERTIES SKIP_LINTING ${prop_sf})
diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyInterfaceHeaderSets.cmake b/Tests/RunCMake/VerifyHeaderSets/VerifyInterfaceHeaderSets.cmake
index 2efd560..c96279a 100644
--- a/Tests/RunCMake/VerifyHeaderSets/VerifyInterfaceHeaderSets.cmake
+++ b/Tests/RunCMake/VerifyHeaderSets/VerifyInterfaceHeaderSets.cmake
@@ -83,3 +83,10 @@
 target_sources(skip_linting INTERFACE FILE_SET HEADERS FILES lang_test.h skip_linting.h)
 set_property(SOURCE skip_linting.h PROPERTY LANGUAGE C)
 set_property(SOURCE skip_linting.h PROPERTY SKIP_LINTING TRUE)
+
+add_library(skip_linting2 STATIC lib.c)
+target_sources(skip_linting2 INTERFACE FILE_SET HEADERS FILES lang_test.h)
+target_sources(skip_linting2 INTERFACE FILE_SET skip_headers TYPE HEADERS FILES skip_linting2.h)
+set_property(FILE_SET skip_headers TARGET skip_linting2 PROPERTY SKIP_LINTING TRUE)
+
+set_property(SOURCE skip_linting2.h PROPERTY LANGUAGE C)
diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake
index 1fc92e1..975a398 100644
--- a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake
+++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake
@@ -86,3 +86,10 @@
 target_sources(skip_linting PRIVATE FILE_SET HEADERS FILES lang_test.h skip_linting.h)
 set_property(SOURCE skip_linting.h PROPERTY LANGUAGE C)
 set_property(SOURCE skip_linting.h PROPERTY SKIP_LINTING TRUE)
+
+add_library(skip_linting2 STATIC lib.c)
+target_sources(skip_linting2 PRIVATE FILE_SET HEADERS FILES lang_test.h)
+target_sources(skip_linting2 PRIVATE FILE_SET skip_headers TYPE HEADERS FILES skip_linting2.h)
+set_property(FILE_SET skip_headers TARGET skip_linting2 PROPERTY SKIP_LINTING TRUE)
+
+set_property(SOURCE skip_linting2.h PROPERTY LANGUAGE C)
diff --git a/Tests/RunCMake/VerifyHeaderSets/skip_linting2.h b/Tests/RunCMake/VerifyHeaderSets/skip_linting2.h
new file mode 100644
index 0000000..8a268bd
--- /dev/null
+++ b/Tests/RunCMake/VerifyHeaderSets/skip_linting2.h
@@ -0,0 +1,3 @@
+#error "This file should not be included"
+
+extern void skip_linting2_h(void);