clang-tidy: Enable performance-inefficient-string-concatenation

Enables the clang-tidy test performance-inefficient-string-concatenation
and replaces all inefficient string concatenations with `cmStrCat`.

Closes: #19555
diff --git a/.clang-tidy b/.clang-tidy
index 57e571a..2b7c9ae 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -22,7 +22,6 @@
 -modernize-use-transparent-functors,\
 -modernize-use-using,\
 performance-*,\
--performance-inefficient-string-concatenation,\
 readability-*,\
 -readability-function-size,\
 -readability-identifier-naming,\
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 407e9f8..b98a4e3 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -385,11 +385,8 @@
   if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
     std::string srcdir =
       this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
-    std::string srcdirrep;
     for (cc = srcdir.size() - 2; cc > 0; cc--) {
       if (srcdir[cc] == '/') {
-        srcdirrep = srcdir.substr(cc);
-        srcdirrep = "/..." + srcdirrep;
         srcdir = srcdir.substr(0, cc + 1);
         break;
       }
@@ -399,11 +396,8 @@
   if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
     std::string bindir =
       this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
-    std::string bindirrep;
     for (cc = bindir.size() - 2; cc > 0; cc--) {
       if (bindir[cc] == '/') {
-        bindirrep = bindir.substr(cc);
-        bindirrep = "/..." + bindirrep;
         bindir = bindir.substr(0, cc + 1);
         break;
       }
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index bbf490e..739cc58 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -494,9 +494,9 @@
       continue;
     }
     if (this->Match(line, this->RegexWarningSuppress)) {
-      line = "[CTest: warning suppressed] " + line;
+      line = cmStrCat("[CTest: warning suppressed] ", line);
     } else if (this->Match(line, this->RegexWarning)) {
-      line = "[CTest: warning matched] " + line;
+      line = cmStrCat("[CTest: warning matched] ", line);
     }
     e4.Content(sep);
     e4.Content(line);
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index f8d9f1b..4288b25 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -30,6 +30,7 @@
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -663,8 +664,8 @@
         fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
         this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
       if (!res || retVal != 0) {
-        cmSystemTools::Error("Unable to perform extra updates:\n" + eu +
-                             "\nWith output:\n" + output);
+        cmSystemTools::Error(cmStrCat("Unable to perform extra updates:\n", eu,
+                                      "\nWith output:\n", output));
         return 0;
       }
     }
@@ -934,7 +935,7 @@
       continue;
     }
 
-    std::string fullPath = directoryPath + std::string("/") + path;
+    std::string fullPath = cmStrCat(directoryPath, "/", path);
 
     bool isDirectory = cmSystemTools::FileIsDirectory(fullPath) &&
       !cmSystemTools::FileIsSymlink(fullPath);
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 2c6ff83..17ef350 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -225,7 +225,7 @@
       std::string local_file = file;
       bool initialize_cdash_buildid = false;
       if (!cmSystemTools::FileExists(local_file)) {
-        local_file = localprefix + "/" + file;
+        local_file = cmStrCat(localprefix, "/", file);
         // If this file exists within the local Testing directory we assume
         // that it will be associated with the current build in CDash.
         initialize_cdash_buildid = true;
@@ -237,9 +237,9 @@
                      << remote_file << std::endl;
 
       std::string ofile = cmSystemTools::EncodeURL(remote_file);
-      std::string upload_as = url +
-        ((url.find('?') == std::string::npos) ? '?' : '&') +
-        "FileName=" + ofile;
+      std::string upload_as =
+        cmStrCat(url, ((url.find('?') == std::string::npos) ? '?' : '&'),
+                 "FileName=", ofile);
 
       if (initialize_cdash_buildid) {
         // Provide extra arguments to CDash so that it can initialize and
diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx
index 848a034..e0186c9 100644
--- a/Source/CTest/cmParseCoberturaCoverage.cxx
+++ b/Source/CTest/cmParseCoberturaCoverage.cxx
@@ -2,6 +2,7 @@
 
 #include "cmCTest.h"
 #include "cmCTestCoverageHandler.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmXMLParser.h"
 
@@ -75,7 +76,7 @@
             // Check if this is a path that is relative to our source or
             // binary directories.
             for (std::string const& filePath : FilePaths) {
-              finalpath = filePath + "/" + filename;
+              finalpath = cmStrCat(filePath, "/", filename);
               if (cmSystemTools::FileExists(finalpath)) {
                 this->CurFileName = finalpath;
                 break;
@@ -86,7 +87,7 @@
           cmsys::ifstream fin(this->CurFileName.c_str());
           if (this->CurFileName.empty() || !fin) {
             this->CurFileName =
-              this->Coverage.BinaryDir + "/" + atts[tagCount + 1];
+              cmStrCat(this->Coverage.BinaryDir, "/", atts[tagCount + 1]);
             fin.open(this->CurFileName.c_str());
             if (!fin) {
               cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index 86846cb..6316a29 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -8,6 +8,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 #include <cmsys/RegularExpression.hxx>
@@ -151,7 +152,7 @@
   std::string& path, bool& resolved)
 {
   for (auto const& searchPath : searchPaths) {
-    path = searchPath + '/' + name;
+    path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path)) {
       resolved = true;
       return true;
@@ -159,7 +160,7 @@
   }
 
   for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
-    path = searchPath + '/' + name;
+    path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path)) {
       std::ostringstream warning;
       warning << "Dependency " << name << " found in search directory:\n  "
diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx
index 31602c4..5a9ad66 100644
--- a/Source/cmBinUtilsWindowsPELinker.cxx
+++ b/Source/cmBinUtilsWindowsPELinker.cxx
@@ -6,6 +6,7 @@
 #include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
 #include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
 #include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 #include <sstream>
@@ -110,7 +111,7 @@
   dirs.insert(dirs.begin(), origin);
 
   for (auto const& searchPath : dirs) {
-    path = searchPath + '/' + name;
+    path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path)) {
       resolved = true;
       return true;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 5f46631..4aa18f2 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1754,7 +1754,7 @@
               cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
             d = cmSystemTools::RelativePath(targetOutputDir, d);
             if (!d.empty()) {
-              d = originToken + "/" + d;
+              d = cmStrCat(originToken, "/", d);
             } else {
               d = originToken;
             }
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index d2a4148..edd8d46 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -514,7 +514,7 @@
     for (std::string const& li : testLangs) {
       projectLangs += " " + li;
       std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
-      std::string rulesOverrideLang = rulesOverrideBase + "_" + li;
+      std::string rulesOverrideLang = cmStrCat(rulesOverrideBase, "_", li);
       if (const char* rulesOverridePath =
             this->Makefile->GetDefinition(rulesOverrideLang)) {
         fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
@@ -574,7 +574,8 @@
         std::string const cfg =
           !tcConfig.empty() ? cmSystemTools::UpperCase(tcConfig) : cfgDefault;
         for (std::string const& li : testLangs) {
-          std::string const langFlagsCfg = "CMAKE_" + li + "_FLAGS_" + cfg;
+          std::string const langFlagsCfg =
+            cmStrCat("CMAKE_", li, "_FLAGS_", cfg);
           const char* flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
           fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
                   cmOutputConverter::EscapeForCMake(flagsCfg ? flagsCfg : "")
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index ab4a62b..4bc2d1b 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -412,7 +412,7 @@
     std::vector<std::string> objects;
     itgen->GetInstallObjectNames(config, objects);
     for (std::string& obj : objects) {
-      obj = value + obj;
+      obj = cmStrCat(value, obj);
     }
 
     // Store the property.
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index f47744b..4146db8 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -16,6 +16,7 @@
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmXMLWriter.h"
 #include "cmake.h"
@@ -178,18 +179,18 @@
 {
   for (std::string const& f : files) {
     xml.StartElement("Unit");
-    xml.Attribute("filename", fsPath + path + "/" + f);
+    xml.Attribute("filename", cmStrCat(fsPath, path, "/", f));
 
     xml.StartElement("Option");
     xml.Attribute("virtualFolder",
-                  "CMake Files\\" + virtualFolderPath + path + "\\");
+                  cmStrCat("CMake Files\\", virtualFolderPath, path, "\\"));
     xml.EndElement();
 
     xml.EndElement();
   }
   for (Tree const& folder : folders) {
-    folder.BuildUnitImpl(xml, virtualFolderPath + path + "\\",
-                         fsPath + path + "/");
+    folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, path, "\\"),
+                         cmStrCat(fsPath, path, "/"));
   }
 }
 
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 30b3f0d..70e9a36 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -9,6 +9,7 @@
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmXMLWriter.h"
 #include "cmake.h"
@@ -121,7 +122,7 @@
       cmStateEnums::TargetType type = lt->GetType();
       std::string const& outputDir = lg->GetCurrentBinaryDirectory();
       std::string targetName = lt->GetName();
-      std::string filename = outputDir + "/" + targetName + ".project";
+      std::string filename = cmStrCat(outputDir, "/", targetName, ".project");
       retval.push_back(targetName);
       // Make the project file relative to the workspace
       std::string relafilename =
@@ -131,7 +132,7 @@
         case cmStateEnums::SHARED_LIBRARY:
         case cmStateEnums::STATIC_LIBRARY:
         case cmStateEnums::MODULE_LIBRARY:
-          visualname = "lib" + visualname;
+          visualname = cmStrCat("lib", visualname);
           CM_FALLTHROUGH;
         case cmStateEnums::EXECUTABLE:
           xml->StartElement("Project");
@@ -161,7 +162,7 @@
     std::string const& outputDir = it.second[0]->GetCurrentBinaryDirectory();
     std::string projectName = it.second[0]->GetProjectName();
     retval.push_back(projectName);
-    std::string filename = outputDir + "/" + projectName + ".project";
+    std::string filename = cmStrCat(outputDir, "/", projectName, ".project");
 
     // Make the project file relative to the workspace
     filename = cmSystemTools::RelativePath(this->WorkspacePath, filename);
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 71c8fcd..67773e0 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -17,6 +17,7 @@
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -266,7 +267,7 @@
         R"((^|[ ])-[DIOUWfgs][^= ]+(=\"[^"]+\"|=[^"][^ ]+)?)";
       flagRegex.compile(regexString);
       std::string workString =
-        flagsString + " " + definesString + " " + includesString;
+        cmStrCat(flagsString, " ", definesString, " ", includesString);
       while (flagRegex.find(workString)) {
         std::string::size_type start = flagRegex.start();
         if (workString[start] == ' ') {
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index b7a2b27..ccd6be9 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -8,6 +8,7 @@
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 class cmExecutionStatus;
@@ -66,18 +67,15 @@
     // if we should use the source GUI
     // to generate .cxx and .h files
     if (!curr || !curr->GetPropertyAsBool("WRAP_EXCLUDE")) {
-      std::string outName = outputDirectory;
-      outName += "/";
-      outName += cmSystemTools::GetFilenameWithoutExtension(arg);
-      std::string hname = outName;
-      hname += ".h";
-      std::string origname = cdir + "/" + arg;
+      std::string outName = cmStrCat(
+        outputDirectory, "/", cmSystemTools::GetFilenameWithoutExtension(arg));
+      std::string hname = cmStrCat(outName, ".h");
+      std::string origname = cmStrCat(cdir, "/", arg);
       // add starting depends
       std::vector<std::string> depends;
       depends.push_back(origname);
       depends.push_back(fluid_exe);
-      std::string cxxres = outName;
-      cxxres += ".cxx";
+      std::string cxxres = cmStrCat(outName, ".cxx");
 
       cmCustomCommandLine commandLine;
       commandLine.push_back(fluid_exe);
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 2594287..aee42d7 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -94,7 +94,7 @@
   std::vector<std::string> files = this->LoadDir(reply_dir);
   for (std::string const& f : files) {
     if (this->ReplyFiles.find(f) == this->ReplyFiles.end()) {
-      std::string file = reply_dir + "/" + f;
+      std::string file = cmStrCat(reply_dir, "/", f);
       cmSystemTools::RemoveFile(file);
     }
   }
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
index 4f1a158..71493bb 100644
--- a/Source/cmFileCopier.cxx
+++ b/Source/cmFileCopier.cxx
@@ -7,6 +7,7 @@
 #include "cmFileCommand.h"
 #include "cmFileTimes.h"
 #include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmsys/Directory.hxx"
 #include "cmsys/Glob.hxx"
@@ -490,7 +491,7 @@
   while (cmSystemTools::ReadSymlink(fromFile, newFromFile)) {
     if (!cmSystemTools::FileIsFullPath(newFromFile)) {
       std::string fromFilePath = cmSystemTools::GetFilenamePath(fromFile);
-      newFromFile = fromFilePath + "/" + newFromFile;
+      newFromFile = cmStrCat(fromFilePath, "/", newFromFile);
     }
 
     std::string symlinkTarget = cmSystemTools::GetFilenameName(newFromFile);
@@ -520,7 +521,7 @@
     }
 
     fromFile = newFromFile;
-    toFile = toFilePath + "/" + symlinkTarget;
+    toFile = cmStrCat(toFilePath, "/", symlinkTarget);
   }
 
   return true;
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 14dc7b8..f78c72e 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1441,7 +1441,7 @@
       }
 
       for (std::string& o : objects) {
-        o = obj_dir + o;
+        o = cmStrCat(obj_dir, o);
       }
     }
 
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 997595b..00ebbb5 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -18,6 +18,7 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
@@ -442,12 +443,12 @@
         // This command was specified as a path to a file in the
         // current directory.  Add a leading "./" so it can run
         // without the current directory being in the search path.
-        cmd = "./" + cmd;
+        cmd = cmStrCat("./", cmd);
       }
       cmd = this->LocalGenerator->ConvertToOutputFormat(
         cmd, cmOutputConverter::SHELL);
       if (useCall) {
-        cmd = "call " + cmd;
+        cmd = cmStrCat("call ", cmd);
       }
       ccg.AppendArguments(c, cmd);
       cmdLines.push_back(std::move(cmd));
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 7cfbea6..9f3dab7 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -11,6 +11,7 @@
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmVersion.h"
 #include "cmake.h"
@@ -418,17 +419,17 @@
     }
 
     // create target build file
-    std::string name = target->GetName() + ".tgt" + FILE_EXTENSION;
-    std::string fname = rootBinaryDir + "/" + name;
+    std::string name = cmStrCat(target->GetName(), ".tgt", FILE_EXTENSION);
+    std::string fname = cmStrCat(rootBinaryDir, "/", name);
     cmGeneratedFileStream fbld(fname);
     fbld.SetCopyIfDifferent(true);
     this->WriteFileHeader(fbld);
     GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
     std::vector<cmGeneratorTarget const*> build;
     if (ComputeTargetBuildOrder(target, build)) {
-      std::string message = "The inter-target dependency graph for target [" +
-        target->GetName() + "] had a cycle.\n";
-      cmSystemTools::Error(message);
+      cmSystemTools::Error(
+        cmStrCat("The inter-target dependency graph for target [",
+                 target->GetName(), "] had a cycle.\n"));
     } else {
       for (auto& tgt : build) {
         WriteProjectLine(fbld, tgt, root, rootBinaryDir);
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 0b68966..c3c44be 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1731,8 +1731,9 @@
   if (arg_lang == "Fortran") {
     info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
   } else {
-    cmSystemTools::Error("-E cmake_ninja_depends does not understand the " +
-                         arg_lang + " language");
+    cmSystemTools::Error(
+      cmStrCat("-E cmake_ninja_depends does not understand the ", arg_lang,
+               " language"));
     return 1;
   }
 
@@ -1786,8 +1787,9 @@
       cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
       Json::Reader reader;
       if (!reader.parse(tdif, tdio, false)) {
-        cmSystemTools::Error("-E cmake_ninja_depends failed to parse " +
-                             arg_tdi + reader.getFormattedErrorMessages());
+        cmSystemTools::Error(
+          cmStrCat("-E cmake_ninja_depends failed to parse ", arg_tdi,
+                   reader.getFormattedErrorMessages()));
         return nullptr;
       }
     }
@@ -1866,8 +1868,9 @@
     cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (!reader.parse(ddif, ddio, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_ddi +
-                           reader.getFormattedErrorMessages());
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                    arg_ddi,
+                                    reader.getFormattedErrorMessages()));
       return false;
     }
 
@@ -1894,14 +1897,14 @@
   // Populate the module map with those provided by linked targets first.
   for (std::string const& linked_target_dir : linked_target_dirs) {
     std::string const ltmn =
-      linked_target_dir + "/" + arg_lang + "Modules.json";
+      cmStrCat(linked_target_dir, "/", arg_lang, "Modules.json");
     Json::Value ltm;
     cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (ltmf && !reader.parse(ltmf, ltm, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " +
-                           linked_target_dir +
-                           reader.getFormattedErrorMessages());
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                    linked_target_dir,
+                                    reader.getFormattedErrorMessages()));
       return false;
     }
     if (ltm.isObject()) {
@@ -2005,8 +2008,9 @@
     cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
     if (!reader.parse(tdif, tdio, false)) {
-      cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_tdi +
-                           reader.getFormattedErrorMessages());
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                    arg_tdi,
+                                    reader.getFormattedErrorMessages()));
       return 1;
     }
   }
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 8f4ae62..c46856a 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2993,7 +2993,7 @@
       } else {
         tgroup = i_folder->second;
       }
-      curr_folder = curr_folder + "\\";
+      curr_folder += "\\";
     }
     return tgroup;
   }
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index c8ebc8c..9357a5c 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -6,6 +6,7 @@
 #include "cmInstallType.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 #include <memory>
@@ -74,7 +75,7 @@
   cmMakefile const& mf = *this->LocalGenerator->GetMakefile();
   for (std::string& d : dirs) {
     if (!cmSystemTools::FileIsFullPath(d)) {
-      d = mf.GetCurrentSourceDirectory() + "/" + d;
+      d = cmStrCat(mf.GetCurrentSourceDirectory(), "/", d);
     }
   }
 
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index a61239e..4e0be5e 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -20,6 +20,7 @@
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmake.h"
@@ -369,7 +370,7 @@
 {
   this->Target->GetTargetObjectNames(config, objects);
   for (std::string& o : objects) {
-    o = computeInstallObjectDir(this->Target, config) + "/" + o;
+    o = cmStrCat(computeInstallObjectDir(this->Target, config), "/", o);
   }
 }
 
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index 2423faf..dc5f477 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -20,6 +20,7 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTest.h"
@@ -500,9 +501,9 @@
         if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) {
           installPath = dest;
         } else {
-          std::string installPrefix =
-            target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
-          installPath = installPrefix + '/' + dest;
+          installPath = cmStrCat(
+            target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"), '/',
+            dest);
         }
 
         installPaths.append(installPath);
diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx
index 4430f97..5e3c790 100644
--- a/Source/cmLinkLineComputer.cxx
+++ b/Source/cmLinkLineComputer.cxx
@@ -11,6 +11,7 @@
 #include "cmOutputConverter.h"
 #include "cmStateDirectory.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
@@ -115,16 +116,17 @@
           type = cmStateEnums::ImportLibraryArtifact;
         }
 
-        linkPath += " " + libPathFlag +
-          item.Target->GetDirectory(cli.GetConfig(), type) +
-          libPathTerminator + " ";
+        linkPath += cmStrCat(" ", libPathFlag,
+                             item.Target->GetDirectory(cli.GetConfig(), type),
+                             libPathTerminator, " ");
       }
     }
   }
 
   for (std::string const& libDir : cli.GetDirectories()) {
-    linkPath += " " + libPathFlag + this->ConvertToOutputForExisting(libDir) +
-      libPathTerminator + " ";
+    linkPath +=
+      cmStrCat(" ", libPathFlag, this->ConvertToOutputForExisting(libDir),
+               libPathTerminator, " ");
   }
 
   return linkPath;
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 8c14596..29c17fa 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -1189,8 +1189,8 @@
     const std::string option = args[argumentIndex++];
     if (option == "COMPARE") {
       if (sortCompare != cmStringSorter::Compare::UNINITIALIZED) {
-        std::string error = messageHint + "option \"" + option +
-          "\" has been specified multiple times.";
+        std::string error = cmStrCat(messageHint, "option \"", option,
+                                     "\" has been specified multiple times.");
         this->SetError(error);
         return false;
       }
@@ -1201,23 +1201,22 @@
         } else if (argument == "FILE_BASENAME") {
           sortCompare = cmStringSorter::Compare::FILE_BASENAME;
         } else {
-          std::string error = messageHint + "value \"" + argument +
-            "\" for option \"" + option + "\" is invalid.";
+          std::string error =
+            cmStrCat(messageHint, "value \"", argument, "\" for option \"",
+                     option, "\" is invalid.");
           this->SetError(error);
           return false;
         }
       } else {
-        std::string error =
-          messageHint + "missing argument for option \"" + option + "\".";
-        this->SetError(error);
+        this->SetError(cmStrCat(messageHint, "missing argument for option \"",
+                                option, "\"."));
         return false;
       }
     } else if (option == "CASE") {
       if (sortCaseSensitivity !=
           cmStringSorter::CaseSensitivity::UNINITIALIZED) {
-        std::string error = messageHint + "option \"" + option +
-          "\" has been specified multiple times.";
-        this->SetError(error);
+        this->SetError(cmStrCat(messageHint, "option \"", option,
+                                "\" has been specified multiple times."));
         return false;
       }
       if (argumentIndex < args.size()) {
@@ -1227,23 +1226,21 @@
         } else if (argument == "INSENSITIVE") {
           sortCaseSensitivity = cmStringSorter::CaseSensitivity::INSENSITIVE;
         } else {
-          std::string error = messageHint + "value \"" + argument +
-            "\" for option \"" + option + "\" is invalid.";
-          this->SetError(error);
+          this->SetError(cmStrCat(messageHint, "value \"", argument,
+                                  "\" for option \"", option,
+                                  "\" is invalid."));
           return false;
         }
       } else {
-        std::string error =
-          messageHint + "missing argument for option \"" + option + "\".";
-        this->SetError(error);
+        this->SetError(cmStrCat(messageHint, "missing argument for option \"",
+                                option, "\"."));
         return false;
       }
     } else if (option == "ORDER") {
 
       if (sortOrder != cmStringSorter::Order::UNINITIALIZED) {
-        std::string error = messageHint + "option \"" + option +
-          "\" has been specified multiple times.";
-        this->SetError(error);
+        this->SetError(cmStrCat(messageHint, "option \"", option,
+                                "\" has been specified multiple times."));
         return false;
       }
       if (argumentIndex < args.size()) {
@@ -1253,21 +1250,19 @@
         } else if (argument == "DESCENDING") {
           sortOrder = cmStringSorter::Order::DESCENDING;
         } else {
-          std::string error = messageHint + "value \"" + argument +
-            "\" for option \"" + option + "\" is invalid.";
-          this->SetError(error);
+          this->SetError(cmStrCat(messageHint, "value \"", argument,
+                                  "\" for option \"", option,
+                                  "\" is invalid."));
           return false;
         }
       } else {
-        std::string error =
-          messageHint + "missing argument for option \"" + option + "\".";
-        this->SetError(error);
+        this->SetError(cmStrCat(messageHint, "missing argument for option \"",
+                                option, "\"."));
         return false;
       }
     } else {
-      std::string error =
-        messageHint + "option \"" + option + "\" is unknown.";
-      this->SetError(error);
+      this->SetError(
+        cmStrCat(messageHint, "option \"", option, "\" is unknown."));
       return false;
     }
   }
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 28ae82e..3deaeb0 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1912,7 +1912,7 @@
   // for which a flag is defined.
   for (; stdIt < defaultStdIt; ++stdIt) {
     std::string option_flag =
-      "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION";
+      cmStrCat("CMAKE_", lang, *stdIt, "_", type, "_COMPILE_OPTION");
 
     if (const char* opt =
           target->Target->GetMakefile()->GetDefinition(option_flag)) {
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 713c985..c6b63ba 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -963,7 +963,7 @@
         // This command was specified as a path to a file in the
         // current directory.  Add a leading "./" so it can run
         // without the current directory being in the search path.
-        cmd = "./" + cmd;
+        cmd = cmStrCat("./", cmd);
       }
 
       std::string launcher;
@@ -1017,18 +1017,16 @@
           std::string::size_type rcurly = cmd.find('}');
           if (rcurly == std::string::npos || rcurly > lcurly) {
             // The first curly is a left curly.  Use the hack.
-            std::string hack_cmd = cmd.substr(0, lcurly);
-            hack_cmd += "{{}";
-            hack_cmd += cmd.substr(lcurly + 1);
-            cmd = hack_cmd;
+            cmd =
+              cmStrCat(cmd.substr(0, lcurly), "{{}", cmd.substr(lcurly + 1));
           }
         }
       }
       if (launcher.empty()) {
         if (useCall) {
-          cmd = "call " + cmd;
+          cmd = cmStrCat("call ", cmd);
         } else if (this->IsNMake() && cmd[0] == '"') {
-          cmd = "echo >nul && " + cmd;
+          cmd = cmStrCat("echo >nul && ", cmd);
         }
       }
       commands1.push_back(std::move(cmd));
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index a7f2a97..19c667e 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -26,6 +26,7 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
@@ -243,7 +244,7 @@
     // Expand placeholders in the commands.
     rulePlaceholderExpander->SetTargetImpLib(targetOutputReal);
     for (std::string& real_link_command : real_link_commands) {
-      real_link_command = launcher + real_link_command;
+      real_link_command = cmStrCat(launcher, real_link_command);
       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                    real_link_command, vars);
     }
@@ -612,7 +613,7 @@
     // Expand placeholders in the commands.
     rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
     for (std::string& real_link_command : real_link_commands) {
-      real_link_command = launcher + real_link_command;
+      real_link_command = cmStrCat(launcher, real_link_command);
       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                    real_link_command, vars);
     }
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index bdde4b8..8d342f3 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -26,6 +26,7 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
@@ -373,7 +374,7 @@
 
     // Expand placeholders.
     for (std::string& real_link_command : real_link_commands) {
-      real_link_command = launcher + real_link_command;
+      real_link_command = cmStrCat(launcher, real_link_command);
       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                    real_link_command, vars);
     }
@@ -891,7 +892,7 @@
 
       // Expand placeholders.
       for (std::string& real_link_command : real_link_commands) {
-        real_link_command = launcher + real_link_command;
+        real_link_command = cmStrCat(launcher, real_link_command);
         rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                      real_link_command, vars);
       }
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 008248c..7b26324 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -806,7 +806,7 @@
 
     // Expand placeholders in the commands.
     for (std::string& compileCommand : compileCommands) {
-      compileCommand = launcher + compileCommand;
+      compileCommand = cmStrCat(launcher, compileCommand);
       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                    compileCommand, vars);
     }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index cd84c03..865ae7d 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -228,7 +228,7 @@
     // Rule for linking library/executable.
     std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd();
     for (std::string& linkCmd : linkCmds) {
-      linkCmd = launcher + linkCmd;
+      linkCmd = cmStrCat(launcher, linkCmd);
       rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
                                                    linkCmd, vars);
     }
@@ -367,7 +367,7 @@
     // Rule for linking library/executable.
     std::vector<std::string> linkCmds = this->ComputeLinkCmd();
     for (std::string& linkCmd : linkCmds) {
-      linkCmd = launcher + linkCmd;
+      linkCmd = cmStrCat(launcher, linkCmd);
       rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
                                                    linkCmd, vars);
     }
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 8b0a6ba..c3459be 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -553,7 +553,7 @@
     }
 
     for (std::string& i : ppCmds) {
-      i = launcher + i;
+      i = cmStrCat(launcher, i);
       rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
                                                    i, ppVars);
     }
@@ -770,7 +770,7 @@
   }
 
   for (std::string& i : compileCmds) {
-    i = launcher + i;
+    i = cmStrCat(launcher, i);
     rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
                                                  vars);
   }
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index a66af5a..587e21c 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -215,10 +215,8 @@
           if (cmSystemTools::FileExists(cxxFile)) {
             found = true;
           }
-          for (std::string path : this->IncludeDirectories) {
-            path = path + "/";
-            path = path + cxxFile;
-            if (cmSystemTools::FileExists(path)) {
+          for (std::string const& path : this->IncludeDirectories) {
+            if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
               found = true;
             }
           }
@@ -227,10 +225,8 @@
             if (cmSystemTools::FileExists(cxxFile)) {
               found = true;
             }
-            for (std::string path : this->IncludeDirectories) {
-              path = path + "/";
-              path = path + cxxFile;
-              if (cmSystemTools::FileExists(path)) {
+            for (std::string const& path : this->IncludeDirectories) {
+              if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
                 found = true;
               }
             }
@@ -240,10 +236,8 @@
             if (cmSystemTools::FileExists(cxxFile)) {
               found = true;
             }
-            for (std::string path : this->IncludeDirectories) {
-              path = path + "/";
-              path = path + cxxFile;
-              if (cmSystemTools::FileExists(path)) {
+            for (std::string const& path : this->IncludeDirectories) {
+              if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
                 found = true;
               }
             }
@@ -253,10 +247,8 @@
             if (cmSystemTools::FileExists(cxxFile)) {
               found = true;
             }
-            for (std::string path : this->IncludeDirectories) {
-              path = path + "/";
-              path = path + cxxFile;
-              if (cmSystemTools::FileExists(path)) {
+            for (std::string const& path : this->IncludeDirectories) {
+              if (cmSystemTools::FileExists(cmStrCat(path, "/", cxxFile))) {
                 found = true;
               }
             }
@@ -340,9 +332,9 @@
           // try to guess which include path to use
           for (std::string incpath : this->IncludeDirectories) {
             if (!incpath.empty() && incpath.back() != '/') {
-              incpath = incpath + "/";
+              incpath += "/";
             }
-            incpath = incpath + path;
+            incpath += path;
             if (srcFile->GetFullPath() == incpath) {
               // set the path to the guessed path
               info->FullPath = incpath;
@@ -421,9 +413,9 @@
 
     for (std::string path : this->IncludeDirectories) {
       if (!path.empty() && path.back() != '/') {
-        path = path + "/";
+        path += "/";
       }
-      path = path + fname;
+      path += fname;
       if (cmSystemTools::FileExists(path, true) &&
           !cmSystemTools::FileIsDirectory(path)) {
         std::string fp = cmSystemTools::CollapseFullPath(path);
@@ -486,9 +478,7 @@
     // write them out
     FILE* fout = cmsys::SystemTools::Fopen(this->OutputFile, "w");
     if (!fout) {
-      std::string err = "Can not open output file: ";
-      err += this->OutputFile;
-      this->SetError(err);
+      this->SetError(cmStrCat("Can not open output file: ", this->OutputFile));
       return false;
     }
     std::set<cmDependInformation const*> visited;
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index a329f7d..1f9aae8 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -342,7 +342,7 @@
 {
   for (auto line : this->MarkupLines) {
     if (!line.empty()) {
-      line = " " + line;
+      line = cmStrCat(" ", line);
     }
     this->OutputLine(line, inlineMarkup);
   }
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index ffdd0ce..bb9aace 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -56,7 +56,7 @@
 {
   for (std::string const& file : files) {
     if (!cmHasPrefix(file, root)) {
-      error = "ROOT: " + root + " is not a prefix of file: " + file;
+      error = cmStrCat("ROOT: ", root, " is not a prefix of file: ", file);
       return false;
     }
   }
@@ -94,7 +94,7 @@
 
     std::vector<std::string> tokenizedPath;
     if (!prefix.empty()) {
-      tokenizedPath = tokenizePath(prefix + '/' + sgFilesPath);
+      tokenizedPath = tokenizePath(cmStrCat(prefix, '/', sgFilesPath));
     } else {
       tokenizedPath = tokenizePath(sgFilesPath);
     }
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 5f4e1fc..6aeba54 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -835,7 +835,7 @@
   cmSystemTools::ConvertToUnixSlashes(dir);
   std::string prevDir;
   while (dir != prevDir) {
-    std::string path = dir + "/" + file;
+    std::string path = cmStrCat(dir, "/", file);
     if (cmSystemTools::FileExists(path)) {
       return path;
     }
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index d6918c0..d099349 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -9,6 +9,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
@@ -39,9 +40,9 @@
   for (std::string const& it : content) {
     if (cmSystemTools::FileIsFullPath(it) ||
         cmGeneratorExpression::Find(it) == 0) {
-      dirs += sep + it;
+      dirs += cmStrCat(sep, it);
     } else {
-      dirs += sep + prefix + it;
+      dirs += cmStrCat(sep, prefix, it);
     }
     sep = ";";
   }
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index 51ecbd1..0dc6ca7 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -114,14 +114,12 @@
 
 std::string cmUuid::ByteToHex(unsigned char byte) const
 {
-  std::string result;
+  std::string result("  ");
   for (int i = 0; i < 2; ++i) {
     unsigned char rest = byte % 16;
     byte /= 16;
-
     char c = (rest < 0xA) ? char('0' + rest) : char('a' + (rest - 0xA));
-
-    result = c + result;
+    result.at(1 - i) = c;
   }
 
   return result;
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index a81b7e4..3cc6776 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -808,8 +808,8 @@
           kdevError = "\nThe KDevelop3 generator is not supported anymore.";
         }
 
-        cmSystemTools::Error("Could not create named generator " + value +
-                             kdevError);
+        cmSystemTools::Error(
+          cmStrCat("Could not create named generator ", value, kdevError));
         this->PrintGeneratorList();
         return;
       }