diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2022-11-29 18:39:10 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2022-12-06 15:39:29 (GMT) |
commit | 232467eb1c0dab9156cd8c4af56aad3959cbee4b (patch) | |
tree | 2772b01850c143598e642282966401cb976dd421 | |
parent | 7ea665b74da322e96dd3e7f90075143c2957728c (diff) | |
download | CMake-232467eb1c0dab9156cd8c4af56aad3959cbee4b.zip CMake-232467eb1c0dab9156cd8c4af56aad3959cbee4b.tar.gz CMake-232467eb1c0dab9156cd8c4af56aad3959cbee4b.tar.bz2 |
clang-tidy: add <LANG>_CLANG_TIDY_EXPORT_FIXES_DIR property
Fixes: #21362
28 files changed, 397 insertions, 2 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index e9ee681..93c6d3e 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -301,6 +301,7 @@ Properties on Targets /prop_tgt/JOB_POOL_PRECOMPILE_HEADER /prop_tgt/LABELS /prop_tgt/LANG_CLANG_TIDY + /prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR /prop_tgt/LANG_COMPILER_LAUNCHER /prop_tgt/LANG_CPPCHECK /prop_tgt/LANG_CPPLINT diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index d66bb2b..2a1e017 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -450,6 +450,7 @@ Variables that Control the Build /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG /variable/CMAKE_IOS_INSTALL_COMBINED /variable/CMAKE_LANG_CLANG_TIDY + /variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR /variable/CMAKE_LANG_COMPILER_LAUNCHER /variable/CMAKE_LANG_CPPCHECK /variable/CMAKE_LANG_CPPLINT diff --git a/Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst b/Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst new file mode 100644 index 0000000..265fade --- /dev/null +++ b/Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst @@ -0,0 +1,29 @@ +<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR +---------------------------------- + +.. versionadded:: 3.26 + +This property is implemented only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` +or ``OBJCXX``, and only has an effect when :prop_tgt:`<LANG>_CLANG_TIDY` is +set. + +Specify a directory for the ``clang-tidy`` tool to put ``.yaml`` files +containing its suggested changes in. This can be used for automated mass +refactoring by ``clang-tidy``. Each object file that gets compiled will have a +corresponding ``.yaml`` file in this directory. After the build is completed, +you can run ``clang-apply-replacements`` on this directory to simultaneously +apply all suggested changes to the code base. If this property is not an +absolute directory, it is assumed to be relative to the target's binary +directory. This property should be preferred over adding an ``--export-fixes`` +or ``--fix`` argument directly to the :prop_tgt:`<LANG>_CLANG_TIDY` property. + +At generate-time, in order to avoid passing stale fixes from old code to +``clang-apply-replacements``, CMake will search the directory for any ``.yaml`` +files that won't be generated by ``clang-tidy`` during the build, and delete +them. In addition, just before running ``clang-tidy`` on a file, CMake will +delete that file's corresponding ``.yaml`` file in case ``clang-tidy`` doesn't +produce any fixes. + +This property is initialized by the value of +the :variable:`CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` variable if it is set +when a target is created. diff --git a/Help/release/dev/clang-tidy-export-fixes-dir.rst b/Help/release/dev/clang-tidy-export-fixes-dir.rst new file mode 100644 index 0000000..edb7ed5 --- /dev/null +++ b/Help/release/dev/clang-tidy-export-fixes-dir.rst @@ -0,0 +1,8 @@ +clang-tidy-export-fixes-dir +--------------------------- + +* A new :prop_tgt:`<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` target property was + created to allow the ``clang-tidy`` tool to export its suggested fixes to a + set of ``.yaml`` files. A new + :variable:`CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` variable was created to + initialize this property. diff --git a/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst b/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst new file mode 100644 index 0000000..60b7f40 --- /dev/null +++ b/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst @@ -0,0 +1,15 @@ +CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR +---------------------------------------- + +.. versionadded:: 3.26 + +Default value for :prop_tgt:`<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` target +property when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` or ``OBJCXX``. + +This variable is used to initialize the property on each target as it is +created. For example: + +.. code-block:: cmake + + set(CMAKE_CXX_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy-fixes) + add_executable(foo foo.cxx) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index c80cdb9..123b5e6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3726,6 +3726,24 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( return ""; } +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetClangTidyExportFixesDirectory( + const std::string& lang) const +{ + cmValue val = + this->GetProperty(cmStrCat(lang, "_CLANG_TIDY_EXPORT_FIXES_DIR")); + if (!cmNonempty(val)) { + return {}; + } + + std::string path = *val; + if (!cmSystemTools::FileIsFullPath(path)) { + path = + cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', path); + } + return cmSystemTools::CollapseFullPath(path); +} + namespace { void processIncludeDirectories(cmGeneratorTarget const* tgt, EvaluatedTargetPropertyEntries& entries, diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3cd5e34..7fa662d 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -490,6 +490,8 @@ public: std::string GetCreateRuleVariable(std::string const& lang, std::string const& config) const; + std::string GetClangTidyExportFixesDirectory(const std::string& lang) const; + private: using ConfigAndLanguage = std::pair<std::string, std::string>; using ConfigAndLanguageToBTStrings = diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index 3ae66f0..7a44452 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -2,11 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalCommonGenerator.h" +#include <algorithm> #include <memory> #include <utility> #include <cmext/algorithm> +#include <cmsys/Glob.hxx> + #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" @@ -14,6 +17,7 @@ #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" #include "cmake.h" @@ -124,3 +128,23 @@ std::string cmGlobalCommonGenerator::GetEditCacheCommand() const cmValue edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); return edit_cmd ? *edit_cmd : std::string(); } + +void cmGlobalCommonGenerator::RemoveUnknownClangTidyExportFixesFiles() const +{ + for (auto const& dir : this->ClangTidyExportFixesDirs) { + cmsys::Glob g; + g.SetRecurse(true); + g.SetListDirs(false); + g.FindFiles(cmStrCat(dir, "/*.yaml")); + for (auto const& file : g.GetFiles()) { + if (!this->ClangTidyExportFixesFiles.count(file) && + !std::any_of(this->ClangTidyExportFixesFiles.begin(), + this->ClangTidyExportFixesFiles.end(), + [&file](const std::string& knownFile) -> bool { + return cmSystemTools::SameFile(file, knownFile); + })) { + cmSystemTools::RemoveFile(file); + } + } + } +} diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h index fed9ce8..fa42674 100644 --- a/Source/cmGlobalCommonGenerator.h +++ b/Source/cmGlobalCommonGenerator.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> +#include <set> #include <string> #include <vector> @@ -42,9 +43,21 @@ public: std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const; bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t, const std::string& config); + void AddClangTidyExportFixesDir(const std::string& dir) + { + this->ClangTidyExportFixesDirs.insert(dir); + } + void AddClangTidyExportFixesFile(const std::string& file) + { + this->ClangTidyExportFixesFiles.insert(file); + } protected: virtual bool SupportsDirectConsole() const { return true; } const char* GetEditCacheTargetName() const override { return "edit_cache"; } std::string GetEditCacheCommand() const override; + + std::set<std::string> ClangTidyExportFixesDirs; + std::set<std::string> ClangTidyExportFixesFiles; + void RemoveUnknownClangTidyExportFixesFiles() const; }; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 4500f33..75c347e 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -592,6 +592,8 @@ void cmGlobalNinjaGenerator::Generate() this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DisableCleandead = false; this->DiagnosedCxxModuleNinjaSupport = false; + this->ClangTidyExportFixesDirs.clear(); + this->ClangTidyExportFixesFiles.clear(); this->PolicyCMP0058 = this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus( @@ -632,6 +634,8 @@ void cmGlobalNinjaGenerator::Generate() { this->CleanMetaData(); } + + this->RemoveUnknownClangTidyExportFixesFiles(); } void cmGlobalNinjaGenerator::CleanMetaData() diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 70a9d3e..30206b5 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -102,6 +102,9 @@ void cmGlobalUnixMakefileGenerator3::Configure() void cmGlobalUnixMakefileGenerator3::Generate() { + this->ClangTidyExportFixesDirs.clear(); + this->ClangTidyExportFixesFiles.clear(); + // first do superclass method this->cmGlobalGenerator::Generate(); @@ -137,6 +140,8 @@ void cmGlobalUnixMakefileGenerator3::Generate() *this->CommandDatabase << "\n]"; this->CommandDatabase.reset(); } + + this->RemoveUnknownClangTidyExportFixesFiles(); } void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 766e9f9..20cc2c3 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -25,6 +25,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalCommonGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalCommonGenerator.h" @@ -1107,8 +1108,29 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } else { driverMode = lang == "C" ? "gcc" : "g++"; } + std::string d = + this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang); + std::string exportFixes; + if (!d.empty()) { + this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d); + std::string fixesFile = cmSystemTools::CollapseFullPath(cmStrCat( + d, '/', + this->LocalGenerator->MaybeRelativeToTopBinDir(cmStrCat( + this->LocalGenerator->GetCurrentBinaryDirectory(), '/', + this->LocalGenerator->GetTargetDirectory( + this->GeneratorTarget), + '/', objectName, ".yaml")))); + this->GlobalCommonGenerator->AddClangTidyExportFixesFile( + fixesFile); + cmSystemTools::MakeDirectory( + cmSystemTools::GetFilenamePath(fixesFile)); + fixesFile = + this->LocalGenerator->MaybeRelativeToCurBinDir(fixesFile); + exportFixes = cmStrCat(";--export-fixes=", fixesFile); + } run_iwyu += this->LocalGenerator->EscapeForShell( - cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode, + exportFixes)); } if (cmNonempty(cpplint)) { run_iwyu += " --cpplint="; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 85a6fc2..f2f719d 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -27,6 +27,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalCommonGenerator.h" #include "cmGlobalNinjaGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" @@ -394,6 +395,24 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath( return path; } +std::string cmNinjaTargetGenerator::GetClangTidyReplacementsFilePath( + const std::string& directory, cmSourceFile const* source, + const std::string& config) const +{ + std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); + if (!path.empty()) { + path += '/'; + } + path = cmStrCat(directory, '/', path); + std::string const& objectName = this->GeneratorTarget->GetObjectName(source); + path = + cmStrCat(std::move(path), + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', + objectName, ".yaml"); + return path; +} + std::string cmNinjaTargetGenerator::GetPreprocessedFilePath( cmSourceFile const* source, const std::string& config) const { @@ -932,8 +951,24 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } else { driverMode = lang == "C" ? "gcc" : "g++"; } + const bool haveClangTidyExportFixesDir = + !this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang) + .empty(); + std::string exportFixes; + if (haveClangTidyExportFixesDir) { + exportFixes = ";--export-fixes=$CLANG_TIDY_EXPORT_FIXES"; + } run_iwyu += this->GetLocalGenerator()->EscapeForShell( - cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode, + exportFixes)); + if (haveClangTidyExportFixesDir) { + std::string search = cmStrCat( + this->GetLocalGenerator()->GetState()->UseWindowsShell() ? "" + : "\\", + "$$CLANG_TIDY_EXPORT_FIXES"); + auto loc = run_iwyu.rfind(search); + run_iwyu.replace(loc, search.length(), "$CLANG_TIDY_EXPORT_FIXES"); + } } if (cmNonempty(cpplint)) { run_iwyu += cmStrCat( @@ -1314,6 +1349,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } } + std::string d = + this->GeneratorTarget->GetClangTidyExportFixesDirectory(language); + if (!d.empty()) { + this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d); + std::string fixesFile = + this->GetClangTidyReplacementsFilePath(d, source, config); + this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile); + cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(fixesFile)); + fixesFile = this->ConvertToNinjaPath(fixesFile); + vars["CLANG_TIDY_EXPORT_FIXES"] = fixesFile; + } + if (firstForConfig) { this->ExportObjectCompileCommand( language, sourceFilePath, objectDir, objectFileName, objectFileDir, diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index b5abb36..8bf7986 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -134,6 +134,11 @@ protected: std::string GetPreprocessedFilePath(cmSourceFile const* source, const std::string& config) const; + /// @return the clang-tidy replacements file path for the given @a source. + std::string GetClangTidyReplacementsFilePath( + const std::string& directory, cmSourceFile const* source, + const std::string& config) const; + /// @return the dyndep file path for this target. std::string GetDyndepFilePath(std::string const& lang, const std::string& config) const; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 70a624d..d73e7cf 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -573,12 +573,14 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("NO_SYSTEM_FROM_IMPORTED"); initProp("BUILD_WITH_INSTALL_NAME_DIR"); initProp("C_CLANG_TIDY"); + initProp("C_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("C_CPPLINT"); initProp("C_CPPCHECK"); initProp("C_INCLUDE_WHAT_YOU_USE"); initProp("C_LINKER_LAUNCHER"); initProp("LINK_WHAT_YOU_USE"); initProp("CXX_CLANG_TIDY"); + initProp("CXX_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("CXX_CPPLINT"); initProp("CXX_CPPCHECK"); initProp("CXX_INCLUDE_WHAT_YOU_USE"); @@ -600,8 +602,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); initProp("OBJC_CLANG_TIDY"); + initProp("OBJC_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("OBJC_LINKER_LAUNCHER"); initProp("OBJCXX_CLANG_TIDY"); + initProp("OBJCXX_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("OBJCXX_LINKER_LAUNCHER"); initProp("Swift_LANGUAGE_VERSION"); initProp("Swift_MODULE_DIRECTORY"); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 06bceb4..4303f96 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -367,6 +367,12 @@ int HandleTidy(const std::string& runCmd, const std::string& sourceFile, std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true); tidy_cmd.push_back(sourceFile); + for (auto const& arg : tidy_cmd) { + if (cmHasLiteralPrefix(arg, "--export-fixes=")) { + cmSystemTools::RemoveFile(arg.substr(cmStrLen("--export-fixes="))); + } + } + // clang-tidy supports working out the compile commands from a // compile_commands.json file in a directory given by a "-p" option, or by // passing the compiler command line arguments after --. When the latter diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake new file mode 100644 index 0000000..97ec52b --- /dev/null +++ b/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake @@ -0,0 +1,35 @@ +if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml" + ) +else() + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml" + ) +endif() diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake new file mode 100644 index 0000000..2b278da --- /dev/null +++ b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake @@ -0,0 +1,6 @@ +enable_language(C) +set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args) +set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy) +set(files ${CMAKE_CURRENT_SOURCE_DIR}/main.c ${CMAKE_CURRENT_SOURCE_DIR}/extra.c) +add_executable(main ${files}) +add_subdirectory(export_fixes_subdir) diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake new file mode 100644 index 0000000..f65d33c --- /dev/null +++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake @@ -0,0 +1,35 @@ +if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml" + ) +else() + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml" + ) +endif() diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake new file mode 100644 index 0000000..f65d33c --- /dev/null +++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake @@ -0,0 +1,35 @@ +if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml" + ) +else() + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml" + ) + assert_any_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml" + ) + assert_no_file_exists( + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml" + "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml" + ) +endif() diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake new file mode 100644 index 0000000..c81c49a --- /dev/null +++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake @@ -0,0 +1,6 @@ +enable_language(C) +set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args) +set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy) +set(files ${CMAKE_CURRENT_SOURCE_DIR}/main.c) +add_executable(main ${files}) +add_subdirectory(export_fixes_subdir) diff --git a/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake b/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake index 5e3fbc4..01dbb61 100644 --- a/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake +++ b/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake @@ -30,3 +30,55 @@ if (NOT RunCMake_GENERATOR STREQUAL "Watcom WMake") endif() run_tidy(C-bad) run_tidy(compdb) + +function(any_file_exists varname) + foreach(filename IN LISTS ARGN) + if(EXISTS "${filename}") + set("${varname}" 1 PARENT_SCOPE) + return() + endif() + endforeach() + set("${varname}" 0 PARENT_SCOPE) +endfunction() + +function(assert_any_file_exists) + any_file_exists(exists ${ARGN}) + if(NOT exists) + string(APPEND RunCMake_TEST_FAILED "Expected one of the following files to exist but they do not:\n") + foreach(filename IN LISTS ARGN) + string(APPEND RunCMake_TEST_FAILED " ${filename}\n") + endforeach() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + endif() +endfunction() + +function(assert_no_file_exists) + any_file_exists(exists ${ARGN}) + if(exists) + string(APPEND RunCMake_TEST_FAILED "Expected none of the following files to exist but one of them does:\n") + foreach(filename IN LISTS ARGN) + string(APPEND RunCMake_TEST_FAILED " ${filename}\n") + endforeach() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + endif() +endfunction() + +function(run_tidy_export_fixes) + # Use a single build tree for tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExportFixesDir-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(ExportFixesDir) + + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(ExportFixesDir-Build ${CMAKE_COMMAND} --build . --config Debug) + unset(RunCMake_TEST_OUTPUT_MERGE) + + run_cmake(ExportFixesDir2) + + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(ExportFixesDir2-Build ${CMAKE_COMMAND} --build . --config Debug) + unset(RunCMake_TEST_OUTPUT_MERGE) +endfunction() +run_tidy_export_fixes() diff --git a/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt b/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt new file mode 100644 index 0000000..af2db88 --- /dev/null +++ b/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(subdir ${files}) diff --git a/Tests/RunCMake/ClangTidy/extra.c b/Tests/RunCMake/ClangTidy/extra.c new file mode 100644 index 0000000..d235550 --- /dev/null +++ b/Tests/RunCMake/ClangTidy/extra.c @@ -0,0 +1,3 @@ +void extra(void) +{ +} diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake new file mode 100644 index 0000000..d638fda --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake @@ -0,0 +1,3 @@ +if(EXISTS "${RunCMake_BINARY_DIR}/tidy-fixes.yaml") + string(APPEND RunCMake_TEST_FAILED "Expected ${RunCMake_BINARY_DIR}/tidy-fixes.yaml not to exist but it does") +endif() diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake new file mode 100644 index 0000000..1e89ffe --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake @@ -0,0 +1 @@ +file(TOUCH "${RunCMake_BINARY_DIR}/tidy-fixes.yaml") diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 08c5a49..9f342bb 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -47,6 +47,7 @@ run_cmake_command(E___run_co_compile-no-iwyu ${CMAKE_COMMAND} -E __run_co_compil run_cmake_command(E___run_co_compile-bad-iwyu ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist -- command-does-not-exist) run_cmake_command(E___run_co_compile-no--- ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist command-does-not-exist) run_cmake_command(E___run_co_compile-no-cc ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist --) +run_cmake_command(E___run_co_compile-tidy-remove-fixes ${CMAKE_COMMAND} -E __run_co_compile "--tidy=${CMAKE_COMMAND}\\;-E\\;true\\;--export-fixes=${RunCMake_BINARY_DIR}/tidy-fixes.yaml" -- ${CMAKE_COMMAND} -E true) run_cmake_command(G_no-arg ${CMAKE_COMMAND} -B DummyBuildDir -G) run_cmake_command(G_bad-arg ${CMAKE_COMMAND} -B DummyBuildDir -G NoSuchGenerator) diff --git a/Tests/RunCMake/pseudo_tidy.c b/Tests/RunCMake/pseudo_tidy.c index a43133b..f227c06 100644 --- a/Tests/RunCMake/pseudo_tidy.c +++ b/Tests/RunCMake/pseudo_tidy.c @@ -1,8 +1,13 @@ +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif + #include <stdio.h> #include <string.h> int main(int argc, char* argv[]) { + FILE* f; int i; for (i = 1; i < argc; ++i) { if (strcmp(argv[i], "-p") == 0) { @@ -20,6 +25,14 @@ int main(int argc, char* argv[]) fprintf(stderr, "stderr from bad command line arg '-bad'\n"); return 1; } + if (strncmp(argv[i], "--export-fixes=", 15) == 0) { + f = fopen(argv[i] + 15, "w"); + if (!f) { + fprintf(stderr, "Error opening %s for writing\n", argv[i] + 15); + return 1; + } + fclose(f); + } if (argv[i][0] != '-') { fprintf(stdout, "%s:0:0: warning: message [checker]\n", argv[i]); break; |