Diagnostics: Use new methods

Find places that are currently relying on diagnostic-specific message
types to issue diagnostics and replace these with calls to the new
diagnostic methods.
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 60ed118..da0726a 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -14,6 +14,7 @@
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandTypes.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -208,8 +209,8 @@
           return false;
         }
         if (cmp0175 == cmPolicies::WARN) {
-          mf.IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          mf.IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat(msg, '\n',
                      cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
         }
@@ -381,8 +382,8 @@
               return false;
             }
             if (cmp0175 == cmPolicies::WARN) {
-              mf.IssueMessage(
-                MessageType::AUTHOR_WARNING,
+              mf.IssueDiagnostic(
+                cmDiagnostics::CMD_AUTHOR,
                 cmStrCat(msg, '\n',
                          cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
             }
@@ -465,8 +466,8 @@
         return false;
       }
       if (cmp0175 == cmPolicies::WARN) {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(msg, ".\n",
                    cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
       }
@@ -503,8 +504,8 @@
         return false;
       }
       if (cmp0175 == cmPolicies::WARN) {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(msg, '\n',
                    cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
       }
@@ -525,8 +526,8 @@
         return false;
       }
       if (cmp0175 == cmPolicies::WARN) {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(msg, ".\n",
                    cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
       }
@@ -552,8 +553,8 @@
           case cmCustomCommandType::POST_BUILD:
             msg += "POST_BUILD";
         }
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(msg, " to preserve backward compatibility.\n",
                    cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
       }
@@ -576,8 +577,8 @@
         return false;
       }
       if (cmp0175 == cmPolicies::WARN) {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(msg, ".\n",
                    cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
       }
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 1c9d0c6..c9209b2 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmAddLibraryCommand.h"
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -235,8 +236,8 @@
       !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
     switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0164)) {
       case cmPolicies::WARN:
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(
             "ADD_LIBRARY called with ",
             (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
diff --git a/Source/cmBinUtilsLinker.cxx b/Source/cmBinUtilsLinker.cxx
index 9766f8d..12c2cff 100644
--- a/Source/cmBinUtilsLinker.cxx
+++ b/Source/cmBinUtilsLinker.cxx
@@ -6,8 +6,8 @@
 #include <utility>
 
 #include "cmCMakePath.h"
+#include "cmDiagnostics.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmRuntimeDependencyArchive.h"
 #include "cmStringAlgorithms.h"
@@ -34,8 +34,8 @@
   cmPolicies::PolicyStatus policy =
     this->Archive->GetMakefile()->GetPolicyStatus(cmPolicies::CMP0207);
   if (policy == cmPolicies::WARN) {
-    this->Archive->GetMakefile()->IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    this->Archive->GetMakefile()->IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0207),
                "\n"
                "Path\n  \"",
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
index d84418b..ed2a80d 100644
--- a/Source/cmBuildCommand.cxx
+++ b/Source/cmBuildCommand.cxx
@@ -2,10 +2,10 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmBuildCommand.h"
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -79,8 +79,9 @@
 
   cmMakefile& mf = status.GetMakefile();
   if (!project_name.empty()) {
-    mf.IssueMessage(MessageType::AUTHOR_WARNING,
-                    "Ignoring PROJECT_NAME option because it has no effect.");
+    mf.IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
+      "Ignoring PROJECT_NAME option because it has no effect.");
   }
 
   std::string makecommand = mf.GetGlobalGenerator()->GenerateCMakeBuildCommand(
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
index 1a68f03..b9ab7a9 100644
--- a/Source/cmCMakeMinimumRequired.cxx
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -5,6 +5,7 @@
 #include <cstdio>
 #include <sstream>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -113,8 +114,8 @@
   }
 
   if (required_major < 2 || (required_major == 2 && required_minor < 4)) {
-    status.GetMakefile().IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    status.GetMakefile().IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0.");
     status.GetMakefile().SetPolicyVersion("2.4", version_max);
   } else {
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index d2da7ec..b614e6c 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -18,6 +18,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmComputeComponentGraph.h"
+#include "cmDiagnostics.h"
 #include "cmGenExContext.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -362,8 +363,8 @@
         if (!makefile->GetCMakeInstance()->GetIsInTryCompile() &&
             makefile->PolicyOptionalWarningEnabled(
               "CMAKE_POLICY_WARNING_CMP0156")) {
-          makefile->GetCMakeInstance()->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0156),
                      "\nSince the policy is not set, legacy libraries "
                      "de-duplication strategy will be applied."),
@@ -379,8 +380,8 @@
             !makefile->GetCMakeInstance()->GetIsInTryCompile() &&
             makefile->PolicyOptionalWarningEnabled(
               "CMAKE_POLICY_WARNING_CMP0179")) {
-          makefile->GetCMakeInstance()->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0179),
                      "\nSince the policy is not set, static libraries "
                      "de-duplication will keep the last occurrence of the "
@@ -1037,8 +1038,8 @@
       if (depender.Target && depender.Target->IsImported() &&
           !IsFeatureSupported(this->Makefile, this->LinkLanguage,
                               item.Feature)) {
-        this->CMakeInstance->IssueMessage(
-          MessageType::AUTHOR_ERROR,
+        this->CMakeInstance->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("The 'IMPORTED' target '", depender.Target->GetName(),
                    "' uses the generator-expression '$<LINK_LIBRARY>' with "
                    "the feature '",
@@ -1088,8 +1089,8 @@
       if (depender.Target && depender.Target->IsImported() &&
           !IsGroupFeatureSupported(this->Makefile, this->LinkLanguage,
                                    groupFeature)) {
-        this->CMakeInstance->IssueMessage(
-          MessageType::AUTHOR_ERROR,
+        this->CMakeInstance->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("The 'IMPORTED' target '", depender.Target->GetName(),
                    "' uses the generator-expression '$<LINK_GROUP>' with "
                    "the feature '",
@@ -1117,8 +1118,8 @@
            cmStateEnums::TargetType::INTERFACE_LIBRARY)) {
       supportedItem = false;
       auto const& groupFeature = this->EntryList[group->first].Feature;
-      this->CMakeInstance->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->CMakeInstance->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(
           "The feature '", groupFeature,
           "', specified as part of a generator-expression "
@@ -1137,8 +1138,8 @@
       if (featureAttributes.LibraryTypes.find(entry.Target->GetType()) ==
           featureAttributes.LibraryTypes.end()) {
         supportedItem = false;
-        this->CMakeInstance->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->CMakeInstance->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("The feature '", itemFeature,
                    "', specified as part of a generator-expression "
                    "'$<LINK_LIBRARY:",
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 1c0900c..e5467a4 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -17,6 +17,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmCMakePath.h"
+#include "cmDiagnostics.h"
 #include "cmExpandedCommandArgument.h"
 #include "cmList.h"
 #include "cmMakefile.h"
@@ -666,7 +667,7 @@
              "when the policy is set to NEW.  "
              "Since the policy is not set the OLD behavior will be used.";
 
-        this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+        this->Makefile.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str());
       }
     }
   }
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
index 42ef230..8848a4c 100644
--- a/Source/cmConfigureFileCommand.cxx
+++ b/Source/cmConfigureFileCommand.cxx
@@ -10,10 +10,10 @@
 
 #include <sys/types.h>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmFSPermissions.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmNewLineStyle.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -156,7 +156,7 @@
   if (!unknown_args.empty()) {
     std::string msg = cmStrCat(
       "configure_file called with unknown argument(s):\n", unknown_args);
-    status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, msg);
+    status.GetMakefile().IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, msg);
   }
 
   if (useSourcePermissions && noSourcePermissions) {
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 2309897..bbf4e1e 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -18,6 +18,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmConfigureLog.h"
+#include "cmDiagnostics.h"
 #include "cmExperimental.h"
 #include "cmExportTryCompileFileGenerator.h"
 #include "cmGlobalGenerator.h"
@@ -247,7 +248,7 @@
     for (auto const& i : unparsedArguments) {
       m = cmStrCat(m, "\n  \"", i, '"');
     }
-    this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m);
+    this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, m);
   }
   return arguments;
 }
@@ -757,7 +758,7 @@
             "(e.g. CMAKE_C_FLAGS_DEBUG) in the test project."
             ;
           /* clang-format on */
-          this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+          this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
         }
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
@@ -1047,7 +1048,7 @@
       for (std::string const& vi : warnCMP0067Variables) {
         w << "  " << vi << "\n";
       }
-      this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+      this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
     }
 
     for (auto const& p : arguments.LangProps) {
diff --git a/Source/cmEnableLanguageCommand.cxx b/Source/cmEnableLanguageCommand.cxx
index 96a845b..425be31 100644
--- a/Source/cmEnableLanguageCommand.cxx
+++ b/Source/cmEnableLanguageCommand.cxx
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmEnableLanguageCommand.h"
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -20,8 +21,8 @@
   if (!mf.IsNormalDefinitionSet("PROJECT_NAME")) {
     switch (mf.GetPolicyStatus(cmPolicies::CMP0165)) {
       case cmPolicies::WARN:
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           "project() should be called prior to this enable_language() call.");
         break;
       case cmPolicies::OLD:
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index d5e9a3a..9a2c7c0 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -28,6 +28,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmEnvironment.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
@@ -370,8 +371,8 @@
           cmProcessOutput::FindEncoding(*arguments.Encoding)) {
       encoding = *maybeEncoding;
     } else {
-      status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("ENCODING option given unknown value \"", *arguments.Encoding,
                  "\".  Ignoring."));
     }
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index 7d40c0b..74c4a6b 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -7,9 +7,9 @@
 #include <cstddef>
 #include <string>
 
+#include "cmDiagnostics.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmValue.h"
 
@@ -111,10 +111,10 @@
 
     if (mf.GetGlobalGenerator()->ShouldWarnExperimental(data.Name, *value)) {
       if (enabled) {
-        mf.IssueMessage(MessageType::AUTHOR_WARNING, data.Description);
+        mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, data.Description);
       } else {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(
             data.Variable, " is set to incorrect value\n  ", value,
             "\n"
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 38c2458..a3f1258 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -16,6 +16,7 @@
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmCryptoHash.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmExperimental.h"
 #include "cmExportBuildAndroidMKGenerator.h"
@@ -198,8 +199,8 @@
   if (gg->GetExportedTargetsFile(fname)) {
     switch (mf.GetPolicyStatus(cmPolicies::CMP0103)) {
       case cmPolicies::WARN:
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0103),
                    "\n"
                    "export() command already specified for the file\n  ",
@@ -283,10 +284,10 @@
       return false;
     }
     if (p == cmPolicies::WARN) {
-      status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING, cmStrCat("export "_s, status.GetError()));
-      status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR, cmStrCat("export "_s, status.GetError()));
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmPolicies::GetPolicyWarning(cmPolicies::CMP0208));
     }
   }
diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx
index 62a01e5..3b657c5 100644
--- a/Source/cmExportPackageInfoGenerator.cxx
+++ b/Source/cmExportPackageInfoGenerator.cxx
@@ -18,6 +18,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmExportSet.h"
 #include "cmFindPackageStack.h"
 #include "cmGeneratorExpression.h"
@@ -118,10 +119,11 @@
       // so, but will probably need to introduce a policy whether to treat
       // invalid versions as an error.
     } else if (schema != "custom"_s) {
-      this->IssueMessage(MessageType::AUTHOR_WARNING,
-                         cmStrCat("Package \""_s, this->GetPackageName(),
-                                  "\" uses unrecognized version schema \""_s,
-                                  this->PackageVersionSchema, "\"."_s));
+      this->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
+        cmStrCat("Package \""_s, this->GetPackageName(),
+                 "\" uses unrecognized version schema \""_s,
+                 this->PackageVersionSchema, "\"."_s));
     }
 
     if (validator) {
@@ -574,8 +576,8 @@
       BuildArray(component, "dyld_requires", components);
       if (!libraries.empty()) {
         // In theory this can never happen?
-        this->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("Package \""_s, this->GetPackageName(),
                    "\" has IMPORTED_LINK_DEPENDENT_LIBRARIES \""_s,
                    cmJoin(libraries, ";"_s), this->PackageVersionSchema,
diff --git a/Source/cmExportSbomGenerator.cxx b/Source/cmExportSbomGenerator.cxx
index c99141f..53bdcef 100644
--- a/Source/cmExportSbomGenerator.cxx
+++ b/Source/cmExportSbomGenerator.cxx
@@ -14,12 +14,12 @@
 #include <cmext/algorithm>
 
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmFindPackageStack.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmList.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmSbomArguments.h"
 #include "cmSbomObject.h"
 #include "cmSpdx.h"
@@ -334,8 +334,8 @@
     }(linkedTarget->Target);
 
     if (!pkgInfo) {
-      target->Makefile->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      target->Makefile->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Target \"", target->GetName(),
                  "\" references imported target \"", linkedName,
                  "\" which does not come from any known package."));
@@ -362,8 +362,8 @@
   if (exportInfo.Namespaces.size() == 1 && exportInfo.Sets.size() == 1) {
     auto const& linkNamespace = *exportInfo.Namespaces.begin();
     if (!cmHasSuffix(linkNamespace, "::")) {
-      target->Makefile->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      target->Makefile->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Target \"", target->GetName(), "\" references target \"",
                  linkedName,
                  "\", which does not use the standard namespace separator. "
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 269cf23..b43eb67 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -10,15 +10,14 @@
 
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmake.h"
 
 class cmListFileBacktrace;
 class cmTarget;
@@ -36,8 +35,7 @@
       ".  The problem was found while processing the source directory: ",
       makefile.GetCurrentSourceDirectory(),
       ".  This FLTK_WRAP_UI call will be ignored.");
-    makefile.GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_ERROR, msg,
-                                              lfbt);
+    makefile.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, msg, lfbt);
   }
 }
 
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index dba3d04..5b58b57 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -33,6 +33,7 @@
 #include "cmArgumentParserTypes.h"
 #include "cmCMakePath.h"
 #include "cmCryptoHash.h"
+#include "cmDiagnostics.h"
 #include "cmELF.h"
 #include "cmExecutionStatus.h"
 #include "cmFSPermissions.h"
@@ -415,8 +416,8 @@
         case cmPolicies::WARN:
           if (status.GetMakefile().PolicyOptionalWarningEnabled(
                 "CMAKE_POLICY_WARNING_CMP0159")) {
-            status.GetMakefile().IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            status.GetMakefile().IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0159),
                        "\n"
                        "For compatibility, CMake is leaving CMAKE_MATCH_<n> "
@@ -732,8 +733,8 @@
     } else if (*i == "CONFIGURE_DEPENDS") {
       // Generated build system depends on glob results
       if (!configureDepends && warnConfigureLate) {
-        status.GetMakefile().IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        status.GetMakefile().IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           "CONFIGURE_DEPENDS flag was given after a glob expression was "
           "already evaluated.");
       }
@@ -769,8 +770,8 @@
         bool shouldExit = false;
         for (cmsys::Glob::Message const& globMessage : globMessages) {
           if (globMessage.type == cmsys::Glob::cyclicRecursion) {
-            status.GetMakefile().IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            status.GetMakefile().IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat("Cyclic recursion detected while globbing for '", *i,
                        "':\n", globMessage.content));
           } else if (globMessage.type == cmsys::Glob::error) {
@@ -1375,8 +1376,8 @@
     if (warnAbout152) {
       computeNewPath(input, realPath);
       if (oldPolicyPath != realPath) {
-        status.GetMakefile().IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        status.GetMakefile().IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0152),
                    "\n"
                    "From input path:\n  ",
@@ -1392,8 +1393,8 @@
   }
 
   if (!cmSystemTools::FileExists(realPath)) {
-    status.GetMakefile().IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    status.GetMakefile().IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat("Given path:\n  ", input,
                "\ndoes not refer to an existing path on disk."));
   }
@@ -1609,8 +1610,8 @@
     std::string fileName = arg;
     if (fileName.empty()) {
       std::string r = recurse ? "REMOVE_RECURSE" : "REMOVE";
-      status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Ignoring empty file name in ", std::move(r), '.'));
       continue;
     }
@@ -2060,8 +2061,8 @@
       file = *i;
     } else {
       // Do not return error for compatibility reason.
-      std::string err = cmStrCat("Unexpected argument: ", *i);
-      status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, err);
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR, cmStrCat("Unexpected argument: ", *i));
     }
     ++i;
   }
@@ -2499,8 +2500,8 @@
       curl_headers.push_back(*i);
     } else {
       // Do not return error for compatibility reason.
-      std::string err = cmStrCat("Unexpected argument: ", *i);
-      status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, err);
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR, cmStrCat("Unexpected argument: ", *i));
     }
 
     ++i;
@@ -3297,8 +3298,8 @@
       if (cmp0205 == cmPolicies::NEW) {
         needToTry = false;
       } else if (cmp0205 == cmPolicies::WARN && arguments.CopyOnError) {
-        status.GetMakefile().IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        status.GetMakefile().IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("Path\n  ", fileName,
                    "\nis a directory. Hard link creation is not supported "
                    "for directories.\n",
@@ -3323,8 +3324,8 @@
 
   if (cmp0205 == cmPolicies::WARN && arguments.CopyOnError &&
       sourceIsDirectory) {
-    status.GetMakefile().IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    status.GetMakefile().IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat("Path\n  ", fileName,
                "\nis a directory. It will be copied "
                "recursively when CMP0205 is set to NEW.\n",
@@ -3378,8 +3379,8 @@
   }
 
   if (status.GetMakefile().GetState()->GetRole() == cmState::Role::Project) {
-    status.GetMakefile().IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    status.GetMakefile().IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       "You have used file(GET_RUNTIME_DEPENDENCIES)"
       " in project mode. This is probably not what "
       "you intended to do. Instead, please consider"
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index e3e1ba7..28b1e0e 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -26,6 +26,7 @@
 #include "cmAlgorithms.h"
 #include "cmConfigureLog.h"
 #include "cmDependencyProvider.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmFindPackageStack.h"
 #include "cmList.h"
@@ -981,8 +982,8 @@
   // Ignore EXACT with no version.
   if (this->VersionComplete.empty() && this->VersionExact) {
     this->VersionExact = false;
-    this->Makefile->IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    this->Makefile->IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       "Ignoring EXACT since no version is requested.");
   }
 
@@ -1333,7 +1334,7 @@
         aw << "\n"
               "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
               "warning.)";
-        this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+        this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, aw.str());
       }
 
       if (this->FindPackageUsingConfigMode()) {
@@ -1565,8 +1566,8 @@
           this->Makefile->GetPolicyStatus(it->second);
         switch (status) {
           case cmPolicies::WARN: {
-            this->Makefile->IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            this->Makefile->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat(cmPolicies::GetPolicyWarning(it->second), '\n'));
             CM_FALLTHROUGH;
           }
@@ -1874,7 +1875,7 @@
       }
 
       if (!aw.str().empty()) {
-        this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+        this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, aw.str());
       }
     }
     // output result if in config mode but not in quiet mode
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index a3e17eb..ea67c9c 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -7,9 +7,9 @@
 
 #include <cm/memory>
 
+#include "cmDiagnostics.h"
 #include "cmFindCommon.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -143,8 +143,8 @@
       return isExeNew;
     }
     if (isExeNew) {
-      this->Makefile->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->Makefile->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
                  "\n"
                  "The file\n"
@@ -154,8 +154,8 @@
                  "is executable but not readable.  "
                  "CMake is ignoring it for compatibility."));
     } else {
-      this->Makefile->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->Makefile->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109),
                  "\n"
                  "The file\n"
diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx
index a41c773..8bc0ef7 100644
--- a/Source/cmFunctionBlocker.cxx
+++ b/Source/cmFunctionBlocker.cxx
@@ -8,9 +8,9 @@
 #include <string> // IWYU pragma: keep
 #include <utility>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmake.h"
 
 bool cmFunctionBlocker::IsFunctionBlocked(cmListFileFunction const& lff,
@@ -38,7 +38,7 @@
           << "  " << closingContext << "\n"
           << "with mis-matching arguments.";  // noqa: spellcheck disable-line
         /* clang-format on */
-        mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+        mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str());
       } else if (!this->EndCommandSupportsArguments() &&
                  !lff.Arguments().empty()) {
         std::ostringstream e;
@@ -47,7 +47,7 @@
           "  " << closingContext << "\n"
           "has unexpected arguments.";
         /* clang-format on */
-        mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+        mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str());
       }
 
       bool replayResult = this->Replay(std::move(this->Functions), status);
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
index 38a320b..7bdc8e1 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.cxx
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -8,6 +8,7 @@
 
 #include "cmsys/FStream.hxx"
 
+#include "cmDiagnostics.h"
 #include "cmGenExContext.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
@@ -251,7 +252,7 @@
         "undefined behavior will be used."
         ;
       /* clang-format on */
-      lg->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+      lg->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
     }
       CM_FALLTHROUGH;
     case cmPolicies::OLD:
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index bb4f0bc..b6c8e81 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -29,6 +29,7 @@
 #include "cmCMakePath.h"
 #include "cmCMakeString.hxx"
 #include "cmComputeLinkInformation.h"
+#include "cmDiagnostics.h"
 #include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpression.h"
@@ -414,7 +415,8 @@
     cmList values;
     cmList checkValues;
     bool check = false;
-    switch (eval->Context.LG->GetPolicyStatus(cmPolicies::CMP0085)) {
+    cmLocalGenerator const* const lg = eval->Context.LG;
+    switch (lg->GetPolicyStatus(cmPolicies::CMP0085)) {
       case cmPolicies::WARN:
         if (parameters.front().empty()) {
           check = true;
@@ -424,12 +426,11 @@
       case cmPolicies::OLD:
         values.assign(parameters[1]);
         if (check && values != checkValues) {
-          std::ostringstream e;
-          e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
-            << "\nSearch Item:\n  \"" << parameters.front()
-            << "\"\nList:\n  \"" << parameters[1] << "\"\n";
-          eval->Context.LG->GetCMakeInstance()->IssueMessage(
-            MessageType ::AUTHOR_WARNING, e.str(), eval->Backtrace);
+          std::string const err =
+            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0085),
+                     "\nSearch Item:\n  \""_s, parameters.front(),
+                     "\"\nList:\n  \""_s, parameters[1], "\"\n"_s);
+          lg->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err, eval->Backtrace);
           return "0";
         }
         if (values.empty()) {
@@ -2899,8 +2900,8 @@
                            eval->CurrentTarget->GetName(), "\", used by \"",
                            eval->HeadTarget->GetName(),
                            "\", may match multiple configurations.\n");
-                lg->GetCMakeInstance()->IssueMessage(
-                  MessageType ::AUTHOR_WARNING, err, eval->Backtrace);
+                lg->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err,
+                                    eval->Backtrace);
               }
               CM_FALLTHROUGH;
             case cmPolicies::OLD:
@@ -4662,8 +4663,8 @@
         cmLocalGenerator* lg = eval->HeadTarget->GetLocalGenerator();
         switch (statusForTarget(eval->HeadTarget, policy)) {
           case cmPolicies::WARN:
-            lg->IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            lg->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmPolicies::GetPolicyWarning(policyForString(policy)));
             CM_FALLTHROUGH;
           case cmPolicies::OLD:
@@ -4743,17 +4744,16 @@
                             cm::GenEx::Evaluation* eval)
   {
     eval->AllTargets.insert(target);
-    cmLocalGenerator const* lg = eval->Context.LG;
+    cmLocalGenerator const* const lg = eval->Context.LG;
     switch (target->GetPolicyStatusCMP0112()) {
       case cmPolicies::WARN:
         if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
               "CMAKE_POLICY_WARNING_CMP0112")) {
-          std::string err =
+          std::string const err =
             cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0112),
                      "\nDependency being added to target:\n  \"",
                      target->GetName(), "\"\n");
-          lg->GetCMakeInstance()->IssueMessage(MessageType ::AUTHOR_WARNING,
-                                               err, eval->Backtrace);
+          lg->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err, eval->Backtrace);
         }
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
@@ -5407,12 +5407,14 @@
       return std::string();
     }
 
+    cmLocalGenerator const* const lg = eval->Context.LG;
+
     std::string language = target->GetLinkerLanguage(eval->Context.Config);
 
     std::string pdbSupportVar =
       cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
 
-    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
+    if (!lg->GetMakefile()->IsOn(pdbSupportVar)) {
       ::reportError(
         eval, content->GetOriginalExpression(),
         "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
@@ -5440,8 +5442,8 @@
 
     if (target->GetPolicyStatusCMP0202() == cmPolicies::WARN &&
         postfix != Postfix::Unspecified) {
-      eval->Context.LG->GetCMakeInstance()->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      lg->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0202),
                  "\n"
                  "\"POSTFIX\" option is recognized only when the policy is "
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index a1d016d..11ae1ca 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -26,6 +26,7 @@
 #include "cmCryptoHash.h"
 #include "cmCxxModuleMetadata.h"
 #include "cmCxxModuleUsageEffects.h"
+#include "cmDiagnostics.h"
 #include "cmExperimental.h"
 #include "cmFileSet.h"
 #include "cmFileSetMetadata.h"
@@ -827,8 +828,8 @@
       w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
       w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
         << "'" << this->GetName() << "'.";
-      this->LocalGenerator->GetCMakeInstance()->IssueMessage(
-        MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+      this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str(),
+                                      this->GetBacktrace());
 
       this->PolicyReportedCMP0069 = true;
     }
@@ -2580,8 +2581,8 @@
     switch (this->GetPolicyStatusCMP0104()) {
       case cmPolicies::WARN:
         if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
-          this->Makefile->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
               "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
               "\".");
diff --git a/Source/cmGeneratorTarget_HeaderSetVerification.cxx b/Source/cmGeneratorTarget_HeaderSetVerification.cxx
index a4420f1..57d82b2 100644
--- a/Source/cmGeneratorTarget_HeaderSetVerification.cxx
+++ b/Source/cmGeneratorTarget_HeaderSetVerification.cxx
@@ -18,6 +18,7 @@
 #include <cm/optional>
 #include <cm/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmFileSetMetadata.h"
 #include "cmGenExContext.h"
 #include "cmGeneratedFileStream.h"
@@ -99,8 +100,8 @@
           this->GetType() == cmStateEnums::EXECUTABLE &&
           !this->GetPropertyAsBool("ENABLE_EXPORTS")) {
         if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) {
-          this->Makefile->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0209),
                      "\n"
                      "Executable target \"",
diff --git a/Source/cmGeneratorTarget_Link.cxx b/Source/cmGeneratorTarget_Link.cxx
index 8650b78..f8341f7 100644
--- a/Source/cmGeneratorTarget_Link.cxx
+++ b/Source/cmGeneratorTarget_Link.cxx
@@ -24,6 +24,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
+#include "cmDiagnostics.h"
 #include "cmGenExContext.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -1298,8 +1299,8 @@
       ", is marked as being deprecated by the owner.  The message provided by "
       "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
     /* clang-format on */
-    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
-      MessageType::AUTHOR_WARNING, w.str(), bt);
+    this->LocalGenerator->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str(),
+                                          bt);
   }
 
   // Skip targets that will not really be linked.  This is probably a
diff --git a/Source/cmGeneratorTarget_LinkDirectories.cxx b/Source/cmGeneratorTarget_LinkDirectories.cxx
index 8f29794..a2917a4 100644
--- a/Source/cmGeneratorTarget_LinkDirectories.cxx
+++ b/Source/cmGeneratorTarget_LinkDirectories.cxx
@@ -5,7 +5,6 @@
 /* clang-format on */
 
 #include <map>
-#include <sstream>
 #include <string>
 #include <unordered_set>
 #include <utility>
@@ -13,6 +12,7 @@
 
 #include <cmext/algorithm>
 
+#include "cmDiagnostics.h"
 #include "cmEvaluatedTargetProperty.h"
 #include "cmGenExContext.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -42,37 +42,33 @@
     std::string usedDirectories;
     for (std::string& entryDirectory : entry.Values) {
       if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
-        std::ostringstream e;
-        bool noMessage = false;
-        MessageType messageType = MessageType::FATAL_ERROR;
         if (!targetName.empty()) {
-          /* clang-format off */
-          e << "Target \"" << targetName << "\" contains relative "
-            "path in its INTERFACE_LINK_DIRECTORIES:\n"
-            "  \"" << entryDirectory << "\"";
-          /* clang-format on */
-        } else {
-          switch (tgt->GetPolicyStatusCMP0081()) {
-            case cmPolicies::WARN: {
-              e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
-              messageType = MessageType::AUTHOR_WARNING;
-            } break;
-            case cmPolicies::OLD:
-              noMessage = true;
-              break;
-            case cmPolicies::NEW:
-              // Issue the fatal message.
-              break;
-          }
-          e << "Found relative path while evaluating link directories of "
-               "\""
-            << tgt->GetName() << "\":\n  \"" << entryDirectory << "\"\n";
+          tgt->GetLocalGenerator()->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat("Target \"", targetName,
+                     "\" contains relative path"
+                     " in its INTERFACE_LINK_DIRECTORIES:\n  \"",
+                     entryDirectory, "\""));
+          return;
         }
-        if (!noMessage) {
-          tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
-          if (messageType == MessageType::FATAL_ERROR) {
+        switch (tgt->GetPolicyStatusCMP0081()) {
+          case cmPolicies::WARN:
+            tgt->GetLocalGenerator()->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
+              cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0081),
+                       "\nFound relative path while evaluating"
+                       " link directories of \"",
+                       tgt->GetName(), "\":\n  \"", entryDirectory, "\"\n"));
+            break;
+          case cmPolicies::OLD:
+            break;
+          case cmPolicies::NEW:
+            tgt->GetLocalGenerator()->IssueMessage(
+              MessageType::FATAL_ERROR,
+              cmStrCat("Found relative path while evaluating"
+                       " link directories of \"",
+                       tgt->GetName(), "\":\n  \"", entryDirectory, "\"\n"));
             return;
-          }
         }
       }
 
diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx
index 4a21427..a1b9ec9 100644
--- a/Source/cmGeneratorTarget_Sources.cxx
+++ b/Source/cmGeneratorTarget_Sources.cxx
@@ -22,6 +22,7 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmDiagnostics.h"
 #include "cmEvaluatedTargetProperty.h"
 #include "cmFileSetMetadata.h"
 #include "cmGenExContext.h"
@@ -120,13 +121,13 @@
       std::string e;
       std::string w;
       std::string fullPath = sf->ResolveFullPath(&e, &w);
-      cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+      cmLocalGenerator const* const lg = tgt->GetLocalGenerator();
       if (!w.empty()) {
-        cm->IssueMessage(MessageType::AUTHOR_WARNING, w, entry.Backtrace);
+        lg->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w, entry.Backtrace);
       }
       if (fullPath.empty()) {
         if (!e.empty()) {
-          cm->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace);
+          lg->IssueMessage(MessageType::FATAL_ERROR, e, entry.Backtrace);
         }
         return contextDependent;
       }
@@ -163,8 +164,8 @@
               tgt->GetGeneratorFileSets()->GetFileSetForSource(config, src)) {
           switch (tgt->GetPolicyStatusCMP0211()) {
             case cmPolicies::WARN:
-              tgt->GetLocalGenerator()->IssueMessage(
-                MessageType::AUTHOR_WARNING,
+              tgt->GetLocalGenerator()->IssueDiagnostic(
+                cmDiagnostics::CMD_AUTHOR,
                 cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0211),
                          "\nIn target \"", tgt->GetName(), "\" the file\n  ",
                          src, "\nalready belongs to file set \"",
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 0a36d67..90d403c 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -34,6 +34,7 @@
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandTypes.h"
+#include "cmDiagnostics.h"
 #include "cmDuration.h"
 #include "cmExperimental.h"
 #include "cmExportBuildFileGenerator.h"
@@ -1025,7 +1026,7 @@
             R"( compiler id "XLClang" to "XL" for compatibility.)"
             ;
           /* clang-format on */
-          mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+          mf->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
         }
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
@@ -1050,7 +1051,7 @@
             R"( compiler id "LCC" to "GNU" for compatibility.)"
             ;
           /* clang-format on */
-          mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+          mf->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
         }
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
@@ -1337,8 +1338,8 @@
     this->CMakeInstance->GetHomeOutputDirectory());
 
   if (this->ExtraGenerator && !this->CMakeInstance->GetIsInTryCompile()) {
-    this->CMakeInstance->IssueMessage(
-      MessageType::DEPRECATION_WARNING,
+    this->CMakeInstance->IssueDiagnostic(
+      cmDiagnostics::CMD_DEPRECATED,
       cmStrCat("Support for \"Extra Generators\" like\n  ",
                this->ExtraGenerator->GetName(),
                "\nis deprecated and will be removed from a future version "
@@ -1783,8 +1784,8 @@
     for (std::string const& t : this->CMP0068WarnTargets) {
       w << ' ' << t << '\n';
     }
-    this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
-                                           w.str());
+    this->GetCMakeInstance()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR,
+                                              w.str());
   }
 }
 
@@ -3098,29 +3099,22 @@
     return;
   }
 
-  MessageType messageType = MessageType::AUTHOR_WARNING;
-  std::ostringstream e;
-  bool issueMessage = false;
   switch (policyStatus) {
     case cmPolicies::WARN:
-      e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0171) << '\n';
-      issueMessage = true;
-      CM_FALLTHROUGH;
+      this->GetCMakeInstance()->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
+        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0171), '\n',
+                 "The target name \"codegen\" is reserved."),
+        tgt->GetBacktrace());
+      break;
     case cmPolicies::OLD:
       break;
     case cmPolicies::NEW:
-      issueMessage = true;
-      messageType = MessageType::FATAL_ERROR;
-      break;
-  }
-  if (issueMessage) {
-    e << "The target name \"codegen\" is reserved.";
-    this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
-                                           tgt->GetBacktrace());
-    if (messageType == MessageType::FATAL_ERROR) {
+      this->GetCMakeInstance()->IssueMessage(
+        MessageType::FATAL_ERROR, "The target name \"codegen\" is reserved.",
+        tgt->GetBacktrace());
       cmSystemTools::SetFatalErrorOccurred();
-      return;
-    }
+      break;
   }
 }
 
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index fe45795..128f77d 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -16,6 +16,7 @@
 
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGhsMultiGpj.h"
@@ -679,8 +680,8 @@
       std::ostringstream msg;
       msg << "Any pre-check scripts, such as those generated for file(GLOB "
              "CONFIGURE_DEPENDS), will not be run by gbuild.";
-      this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
-                                             msg.str());
+      this->GetCMakeInstance()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR,
+                                                msg.str());
     }
 
     // Sort the list of input files and remove duplicates.
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index dfac9ff..23c7ef4 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -26,6 +26,7 @@
 
 #include "cmCustomCommand.h"
 #include "cmCxxModuleMapper.h"
+#include "cmDiagnostics.h"
 #include "cmDyndepCollation.h"
 #include "cmFortranParser.h"
 #include "cmGeneratedFileStream.h"
@@ -1927,8 +1928,8 @@
         << "\n";
     msg << "Any pre-check scripts, such as those generated for file(GLOB "
            "CONFIGURE_DEPENDS), will not be run by Ninja.";
-    this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
-                                           msg.str());
+    this->GetCMakeInstance()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR,
+                                              msg.str());
   }
 
   std::sort(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end());
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 074caea..c273c87 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -23,6 +23,7 @@
 #include "cmCallVisualStudioMacro.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
@@ -300,8 +301,8 @@
     if (this->FindTarget(startup)) {
       return startup;
     }
-    root->GetMakefile()->IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    root->GetMakefile()->IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat("Directory property VS_STARTUP_PROJECT specifies target "
                "'",
                startup, "' that does not exist.  Ignoring."));
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 1c7fc47..de19966 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -26,6 +26,7 @@
 #include "cmCustomCommandGenerator.h"
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandTypes.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorFileSet.h"
@@ -2715,8 +2716,8 @@
         case cmSwiftCompileMode::Singlefile:
           break;
         case cmSwiftCompileMode::Unknown:
-          this->CurrentLocalGenerator->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->CurrentLocalGenerator->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat("Unknown Swift_COMPILATION_MODE on target '",
                      gtgt->GetName(), '\''));
           break;
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index c8c314c..6102b46 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -10,6 +10,7 @@
 #include <cmext/string_view>
 
 #include "cmConditionEvaluator.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmExpandedCommandArgument.h"
 #include "cmFunctionBlocker.h"
@@ -78,7 +79,7 @@
                            this->GetStartingContext().FilePath, func.Line() });
 
       if (this->ElseSeen) {
-        mf.GetCMakeInstance()->IssueMessage(
+        mf.IssueMessage(
           MessageType::FATAL_ERROR,
           "A duplicate ELSE command was found inside an IF block.", elseBT);
         cmSystemTools::SetFatalErrorOccurred();
@@ -100,17 +101,17 @@
         cmListFileContext{ func.OriginalName(),
                            this->GetStartingContext().FilePath, func.Line() });
       if (this->ElseSeen) {
-        mf.GetCMakeInstance()->IssueMessage(
-          MessageType::FATAL_ERROR,
-          "An ELSEIF command was found after an ELSE command.", elseifBT);
+        mf.IssueMessage(MessageType::FATAL_ERROR,
+                        "An ELSEIF command was found after an ELSE command.",
+                        elseifBT);
         cmSystemTools::SetFatalErrorOccurred();
         return true;
       }
 
       if (func.Arguments().empty()) {
-        mf.GetCMakeInstance()->IssueMessage(
-          MessageType::AUTHOR_WARNING,
-          "ELSEIF called with no arguments, it will be skipped. ", elseifBT);
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
+          "ELSEIF called with no arguments, it will be skipped.", elseifBT);
       }
 
       if (this->HasRun) {
@@ -137,7 +138,7 @@
         if (!errorString.empty()) {
           std::string err =
             cmStrCat(cmIfCommandError(expandedArguments), errorString);
-          mf.GetCMakeInstance()->IssueMessage(messType, err, elseifBT);
+          mf.IssueMessage(messType, err, elseifBT);
           if (messType == MessageType::FATAL_ERROR) {
             cmSystemTools::SetFatalErrorOccurred();
             return true;
diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx
index 84a7034..0b3aec7 100644
--- a/Source/cmIncludeCommand.cxx
+++ b/Source/cmIncludeCommand.cxx
@@ -5,6 +5,7 @@
 #include <map>
 #include <utility>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
@@ -87,9 +88,8 @@
   }
 
   if (fname.empty()) {
-    status.GetMakefile().IssueMessage(
-      MessageType::AUTHOR_WARNING,
-      "include() given empty file name (ignored).");
+    status.GetMakefile().IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR, "include() given empty file name (ignored).");
     return true;
   }
 
@@ -106,8 +106,8 @@
           status.GetMakefile().GetPolicyStatus(ModulePolicy->second);
         switch (PolicyStatus) {
           case cmPolicies::WARN: {
-            status.GetMakefile().IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            status.GetMakefile().IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat(cmPolicies::GetPolicyWarning(ModulePolicy->second),
                        '\n'));
             CM_FALLTHROUGH;
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 1783e18..1fb9d4b 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -8,7 +8,6 @@
 #include <iterator>
 #include <map>
 #include <set>
-#include <sstream>
 #include <utility>
 
 #include <cm/memory>
@@ -21,6 +20,7 @@
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmCMakePath.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmExperimental.h"
 #include "cmExportSet.h"
@@ -1082,10 +1082,11 @@
             helper.Makefile, absFiles, privateHeaderArgs, false,
             helper.GetIncludeDestination(&privateHeaderArgs));
         } else {
-          std::ostringstream e;
-          e << "Target " << target.GetName() << " has "
-            << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
-          helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+          helper.Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
+            cmStrCat("Target ", target.GetName(),
+                     " has PRIVATE_HEADER files"
+                     " but no PRIVATE_HEADER DESTINATION."));
         }
       }
 
@@ -1104,10 +1105,11 @@
             helper.Makefile, absFiles, publicHeaderArgs, false,
             helper.GetIncludeDestination(&publicHeaderArgs));
         } else {
-          std::ostringstream e;
-          e << "Target " << target.GetName() << " has "
-            << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
-          helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+          helper.Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
+            cmStrCat("Target ", target.GetName(),
+                     " has PUBLIC_HEADER files"
+                     " but no PUBLIC_HEADER DESTINATION."));
         }
       }
 
@@ -1124,8 +1126,8 @@
           resourceGenerator = CreateInstallFilesGenerator(
             helper.Makefile, absFiles, resourceArgs, false);
         } else if (!target.IsAppBundleOnApple()) {
-          helper.Makefile->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          helper.Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat("Target ", target.GetName(),
                      " has RESOURCE files but no RESOURCE DESTINATION."));
         }
@@ -1807,8 +1809,8 @@
           // generator expressions
           if (cmGeneratorExpression::Find(args[i]) == cm::string_view::npos &&
               args[i] != cmCMakePath(args[i]).Normal().String()) {
-            status.GetMakefile().IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            status.GetMakefile().IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmPolicies::GetPolicyWarning(cmPolicies::CMP0177));
           }
           CM_FALLTHROUGH;
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
index 23b38f6..5a4725c 100644
--- a/Source/cmInstallCommandArguments.cxx
+++ b/Source/cmInstallCommandArguments.cxx
@@ -10,9 +10,9 @@
 #include <cmext/string_view>
 
 #include "cmCMakePath.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
@@ -48,8 +48,8 @@
         // generator expressions
         if (cmGeneratorExpression::Find(arg) == cm::string_view::npos &&
             arg != cmCMakePath(arg).Normal().String()) {
-          makefile.IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          makefile.IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0177));
         }
         return ArgumentParser::Continue::No;
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index 7173305..a75e924 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -6,9 +6,9 @@
 #include <utility>
 #include <vector>
 
+#include "cmDiagnostics.h"
 #include "cmGeneratorExpression.h"
 #include "cmLocalGenerator.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmScriptGenerator.h"
 
@@ -36,8 +36,8 @@
   if (this->ActionsPerConfig) {
     switch (this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0087)) {
       case cmPolicies::WARN:
-        this->LocalGenerator->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->LocalGenerator->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmPolicies::GetPolicyWarning(cmPolicies::CMP0087));
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index a9be820..6b89f86 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -15,6 +15,7 @@
 #include <cm/optional>
 
 #include "cmComputeLinkInformation.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -400,12 +401,15 @@
           // Assume the NamelinkModeSkip instance will warn and install.
           return files;
         case NamelinkModeSkip: {
-          std::string e = "Target '" + this->Target->GetName() +
-            "' was changed to a FRAMEWORK sometime after install().  "
-            "This may result in the wrong install DESTINATION.  "
-            "Set the FRAMEWORK property earlier.";
-          this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-            MessageType::AUTHOR_WARNING, e, this->GetBacktrace());
+          cmake const* const cm =
+            this->Target->GetGlobalGenerator()->GetCMakeInstance();
+          cm->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
+            cmStrCat("Target '", this->Target->GetName(),
+                     "' was changed to a FRAMEWORK sometime after install().  "
+                     "This may result in the wrong install DESTINATION.  "
+                     "Set the FRAMEWORK property earlier."),
+            this->GetBacktrace());
         } break;
       }
 
@@ -972,12 +976,14 @@
                                   std::string::npos);
 
   if (potentially_affected) {
+    cmake const* const cm =
+      this->Target->GetGlobalGenerator()->GetCMakeInstance();
     std::ostringstream w;
     w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0095) << "\n";
     w << "RPATH entries for target '" << this->Target->GetName() << "' "
       << "will not be escaped in the intermediary "
       << "cmake_install.cmake script.";
-    this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-      MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+    cm->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str(),
+                        this->GetBacktrace());
   }
 }
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 60bd083..d45e905 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -16,10 +16,10 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
@@ -39,7 +39,7 @@
         std::string warn =
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0121),
                    " Invalid list index \"", arg, "\".");
-        mf.IssueMessage(MessageType::AUTHOR_WARNING, warn);
+        mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, warn);
         CM_FALLTHROUGH;
       }
       case cmPolicies::OLD:
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 34ac595..d7be27e 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -13,6 +13,7 @@
 
 #include <cm/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmList.h"
 #include "cmListFileLexer.h"
 #include "cmMakefile.h"
@@ -337,7 +338,7 @@
     return false;
   }
   if (this->Makefile) {
-    this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg, lfbt);
+    this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, msg, lfbt);
   }
   return true;
 }
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 5856af2..219611c 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -272,14 +272,14 @@
         w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
           << ", which is less than the minimum of 128.  "
              "The value will be ignored.";
-        this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+        this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
       }
     } else {
       std::ostringstream w;
       w << "CMAKE_OBJECT_PATH_MAX is set to \"" << *plen
         << "\", which fails to parse as a positive integer.  "
            "The value will be ignored.";
-      this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+      this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str());
     }
   }
   this->ObjectMaxPathViolations.clear();
@@ -719,7 +719,7 @@
             "CMAKE_POLICY_WARNING_CMP0082")) {
         std::ostringstream e;
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n";
-        this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+        this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str());
       }
       CM_FALLTHROUGH;
     case cmPolicies::OLD: {
@@ -1706,8 +1706,8 @@
         case cmSwiftCompileMode::Singlefile:
           break;
         case cmSwiftCompileMode::Unknown: {
-          this->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat("Unknown Swift_COMPILATION_MODE on target '",
                      target->GetName(), '\''));
         }
@@ -2636,8 +2636,8 @@
       if (!this->Makefile->GetCMakeInstance()->GetIsInTryCompile() &&
           this->Makefile->PolicyOptionalWarningEnabled(
             "CMAKE_POLICY_WARNING_CMP0181")) {
-        this->Makefile->GetCMakeInstance()->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->Makefile->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0181),
                    "\nSince the policy is not set, the contents of variable '",
                    name,
@@ -3417,8 +3417,8 @@
             this->Makefile->GetSafeDefinition(
               cmStrCat("CMAKE_EXECUTABLE_CREATE_", lang, "_FLAGS")) &&
           this->GlobalGenerator->ShouldWarnCMP0210(lang)) {
-        this->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0210), "\n",
                    "For compatibility with older versions of CMake, ",
                    "CMAKE_", lang, "_LINK_FLAGS will be ignored for all ",
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index dc319af..205901e 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmCryptoHash.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
+#include "cmDiagnostics.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
@@ -28,7 +29,6 @@
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmNinjaTargetGenerator.h"
 #include "cmNinjaTypes.h"
 #include "cmPolicies.h"
@@ -713,8 +713,8 @@
                   this->GetBinaryDirectory() ||
                 this->Makefile->PolicyOptionalWarningEnabled(
                   "CMAKE_POLICY_WARNING_CMP0116")) {
-              this->GetCMakeInstance()->IssueMessage(
-                MessageType::AUTHOR_WARNING,
+              this->GetCMakeInstance()->IssueDiagnostic(
+                cmDiagnostics::CMD_AUTHOR,
                 cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
                 cc->GetBacktrace());
             }
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index ae1cba4..d755360 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -288,7 +288,7 @@
                     *rootEnv, '\n');
     }
     e += "For compatibility, CMake is ignoring the variable.";
-    this->IssueMessage(MessageType::AUTHOR_WARNING, e);
+    this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e);
   }
 }
 
@@ -308,7 +308,7 @@
     }
     e += "For compatibility, find_package is ignoring the variable, but "
          "code in a .cmake module might still use it.";
-    this->IssueMessage(MessageType::AUTHOR_WARNING, e);
+    this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e);
   }
 }
 
@@ -1700,16 +1700,15 @@
     }
     // if no project command is found, add one
     if (!hasProject) {
-      this->GetCMakeInstance()->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         "No project() command is present.  The top-level CMakeLists.txt "
         "file must contain a literal, direct call to the project() command.  "
         "Add a line of code such as\n"
         "  project(ProjectName)\n"
         "near the top of the file, but after cmake_minimum_required().\n"
         "CMake is pretending there is a \"project(Project)\" command on "
-        "the first line.",
-        this->Backtrace);
+        "the first line.");
       cmListFileFunction project{
         "project", 0, 0, { { "Project", cmListFileArgument::Unquoted, 0 } }
       };
@@ -1932,8 +1931,8 @@
     case cmPolicies::WARN:
       if (this->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0126") &&
           this->IsNormalDefinitionSet(name)) {
-        this->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0126),
                    "\nFor compatibility with older versions of CMake, normal "
                    "variable \"",
@@ -1971,8 +1970,9 @@
       !this->VariableInitialized(variable)) {
     if (this->CheckSystemVars ||
         (sourceFilename && this->IsProjectFile(sourceFilename))) {
-      this->IssueMessage(MessageType::AUTHOR_WARNING,
-                         cmStrCat("uninitialized variable '", variable, '\''));
+      this->IssueDiagnostic(
+        cmDiagnostics::CMD_UNINITIALIZED,
+        cmStrCat("uninitialized variable '", variable, '\''));
     }
   }
 }
@@ -3209,8 +3209,8 @@
     }
     if (!duplicate_languages.empty()) {
       auto quantity = duplicate_languages.size() == 1 ? " has"_s : "s have"_s;
-      this->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Languages to be enabled may not be specified more "
                  "than once at the same time. The following language",
                  quantity, " been specified multiple times: ",
@@ -3838,8 +3838,8 @@
   }
 
   if (!this->StateSnapshot.RaiseScope(var, varDef)) {
-    this->IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    this->IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat("Cannot set \"", var, "\": current scope has no parent."));
     return;
   }
@@ -4135,11 +4135,9 @@
           id == cmPolicies::CMP0104 || id == cmPolicies::CMP0123 ||
           id == cmPolicies::CMP0126 || id == cmPolicies::CMP0128 ||
           id == cmPolicies::CMP0136 || id == cmPolicies::CMP0141 ||
-          id == cmPolicies::CMP0155)) &&
-      (!this->IsSet("CMAKE_WARN_DEPRECATED") ||
-       this->IsOn("CMAKE_WARN_DEPRECATED"))) {
-    this->IssueMessage(MessageType::DEPRECATION_WARNING,
-                       cmPolicies::GetPolicyDeprecatedWarning(id));
+          id == cmPolicies::CMP0155))) {
+    this->IssueDiagnostic(cmDiagnostics::CMD_DEPRECATED,
+                          cmPolicies::GetPolicyDeprecatedWarning(id));
   }
 
   this->StateSnapshot.SetPolicy(id, status);
diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx
index 963076b..a592c56 100644
--- a/Source/cmMarkAsAdvancedCommand.cxx
+++ b/Source/cmMarkAsAdvancedCommand.cxx
@@ -2,9 +2,9 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmMarkAsAdvancedCommand.h"
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -68,7 +68,7 @@
         "is no longer created when policy CMP0102 is set to NEW. Run \"cmake "
         "--help-policy CMP0102\" for policy details. Use the cmake_policy "
         "command to set the policy and suppress this warning.");
-      mf.IssueMessage(MessageType::AUTHOR_WARNING, err);
+      mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err);
     }
 
     // If it's not in the cache and we're using the new behavior, nothing to
diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx
index 85c5281..75d0464 100644
--- a/Source/cmMathCommand.cxx
+++ b/Source/cmMathCommand.cxx
@@ -6,10 +6,10 @@
 
 #include <cm3p/kwiml/int.h>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmExprParserHelper.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 
 namespace {
 bool HandleExprCommand(std::vector<std::string> const& args,
@@ -111,7 +111,7 @@
 
   std::string const& w = helper.GetWarning();
   if (!w.empty()) {
-    status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, w);
+    status.GetMakefile().IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w);
   }
 
   status.GetMakefile().AddDefinition(outputVariable, buffer);
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 35764d4..8ce1a7c 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -58,7 +58,7 @@
     mf.DisplayStatus(IndentText(std::move(text), mf), -1);
   } else {
     mf.GetMessenger()->DisplayMessage(
-      MessageType::AUTHOR_WARNING, cmDiagnostics::CMD_NONE,
+      MessageType::WARNING, cmDiagnostics::CMD_AUTHOR,
       cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
       mf.GetBacktrace());
   }
@@ -96,6 +96,7 @@
 
   auto i = args.cbegin();
 
+  auto category = cmDiagnostics::CMD_NONE;
   auto type = MessageType::MESSAGE;
   auto fatal = false;
   auto level = Message::LogLevel::LOG_UNDEFINED;
@@ -114,6 +115,7 @@
     level = Message::LogLevel::LOG_WARNING;
     ++i;
   } else if (*i == "AUTHOR_WARNING") {
+    category = cmDiagnostics::CMD_AUTHOR;
     switch (mf.GetDiagnosticAction(cmDiagnostics::CMD_AUTHOR)) {
       case cmDiagnostics::Ignore:
         return true;
@@ -121,11 +123,11 @@
         fatal = true;
         CM_FALLTHROUGH;
       case cmDiagnostics::SendError:
-        type = MessageType::AUTHOR_ERROR;
+        type = MessageType::FATAL_ERROR;
         level = Message::LogLevel::LOG_ERROR;
         break;
       default:
-        type = MessageType::AUTHOR_WARNING;
+        type = MessageType::WARNING;
         level = Message::LogLevel::LOG_WARNING;
         break;
     }
@@ -163,6 +165,7 @@
     level = Message::LogLevel::LOG_TRACE;
     ++i;
   } else if (*i == "DEPRECATION") {
+    category = cmDiagnostics::CMD_DEPRECATED;
     switch (mf.GetDiagnosticAction(cmDiagnostics::CMD_DEPRECATED)) {
       case cmDiagnostics::Ignore:
         return true;
@@ -170,11 +173,11 @@
         fatal = true;
         CM_FALLTHROUGH;
       case cmDiagnostics::SendError:
-        type = MessageType::DEPRECATION_ERROR;
+        type = MessageType::FATAL_ERROR;
         level = Message::LogLevel::LOG_ERROR;
         break;
       default:
-        type = MessageType::DEPRECATION_WARNING;
+        type = MessageType::WARNING;
         level = Message::LogLevel::LOG_WARNING;
         break;
     }
@@ -203,7 +206,7 @@
     case Message::LogLevel::LOG_ERROR:
     case Message::LogLevel::LOG_WARNING:
       // we've overridden the message type, above, so display it directly
-      mf.GetMessenger()->DisplayMessage(type, cmDiagnostics::CMD_NONE, message,
+      mf.GetMessenger()->DisplayMessage(type, category, message,
                                         mf.GetBacktrace());
       break;
 
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 36a3cad..8f0ddca 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -26,6 +26,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
+#include "cmDiagnostics.h"
 #include "cmDyndepCollation.h"
 #include "cmFileSetMetadata.h"
 #include "cmGeneratedFileStream.h"
@@ -1131,8 +1132,8 @@
           if (independentFiles.IsOn() &&
               dependencyMode != DependencyMode::IndependentFiles) {
             // requested dependency mode not supported
-            this->GetMakefile()->IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            this->GetMakefile()->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat(R"(the "INDEPENDENT_FILES" property of the file set ")",
                        fileset->GetName(), R"(" of the target ")",
                        this->GeneratorTarget->GetName(),
diff --git a/Source/cmOptionCommand.cxx b/Source/cmOptionCommand.cxx
index cc20002..8e2fb63 100644
--- a/Source/cmOptionCommand.cxx
+++ b/Source/cmOptionCommand.cxx
@@ -2,9 +2,9 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmOptionCommand.h"
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
@@ -78,8 +78,8 @@
     auto const& existsAfterSet =
       status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
     if (!existsAfterSet) {
-      status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      status.GetMakefile().IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0077),
                  "\n"
                  "For compatibility with older versions of CMake, option "
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index b043b11..ee0a877 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -10,6 +10,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmMakefile.h"
@@ -95,8 +96,8 @@
       // The OLD policy behavior doesn't define a variable for an empty or
       // missing value, and we can't differentiate between those two cases.
       if (parseFromArgV && (cmp0174 == cmPolicies::WARN)) {
-        makefile.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        makefile.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("The ", iter.first,
                    " keyword was followed by an empty string or no value at "
                    "all. Policy CMP0174 is not set, so "
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 0c308fb..5c4ba3f 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -10,6 +10,7 @@
 
 #include "cmsys/String.h"
 
+#include "cmDiagnostics.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -339,8 +340,8 @@
     }
   } else if (majorVer == 3 && minorVer < 10 && warnCompat == WarnCompat::On) {
     // Warn about policy versions for which support will be removed.
-    mf->IssueMessage(
-      MessageType::DEPRECATION_WARNING,
+    mf->IssueDiagnostic(
+      cmDiagnostics::CMD_DEPRECATED,
       "Compatibility with CMake < 3.10 will be removed from "
       "a future version of CMake.\n" ADVICE_UPDATE_VERSION_ARGUMENT);
   }
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 8551132..0976d40 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -16,6 +16,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmMakefile.h"
@@ -81,8 +82,8 @@
   cmMakefile& mf = status.GetMakefile();
   std::string const& projectName = args[0];
   if (parser.HasKeyword(projectName)) {
-    mf.IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    mf.IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat(
         "project() called with '", projectName,
         "' as first argument. The first parameter should be the project name, "
@@ -94,8 +95,8 @@
 
   if (mf.IsRootMakefile() &&
       !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
-    mf.IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    mf.IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       "cmake_minimum_required() should be called prior to this top-level "
       "project() call. Please see the cmake-commands(7) manual for usage "
       "documentation of both commands.");
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 6514f80..c86bb26 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -8,11 +8,11 @@
 #include <cm/memory>
 
 #include "cmCustomCommand.h"
+#include "cmDiagnostics.h"
 #include "cmDuration.h"
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmProcessOutput.h"
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenInitializer.h"
@@ -145,7 +145,7 @@
             cmQtAutoGen::Tools(mocDisabled, uicDisabled, rccDisabled),
             " disabled.  Consider adding:\n  find_package(Qt", version,
             " COMPONENTS ", component, ")\nto your CMakeLists.txt file.");
-          target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
+          target->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, msg);
         }
         if (mocIsValid || uicIsValid || rccIsValid) {
           // Create autogen target initializer
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 05b8a51..615cd44 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -31,6 +31,7 @@
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDiagnostics.h"
 #include "cmEvaluatedTargetProperty.h"
 #include "cmGenExContext.h"
 #include "cmGeneratedFileStream.h"
@@ -533,8 +534,8 @@
         this->AutogenTarget.Parallel = static_cast<ParallelType>(propInt);
       } else {
         // Warn the project author that AUTOGEN_PARALLEL is not valid.
-        this->Makefile->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->Makefile->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("AUTOGEN_PARALLEL=\"", prop, "\" for target \"",
                    this->GenTarget->GetName(),
                    "\" is not valid. Using AUTOGEN_PARALLEL=1"));
@@ -556,8 +557,8 @@
             static_cast<maxCommandLineLengthType>(propInt);
         } else {
           // Warn the project author that AUTOGEN_PARALLEL is not valid.
-          this->Makefile->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmStrCat("AUTOGEN_COMMAND_LINE_LENGTH_MAX=\"", *value,
                      "\" for target \"", this->GenTarget->GetName(),
                      "\" is not valid. Using no limit for "
@@ -620,8 +621,8 @@
       // CMAKE_AUTOMOC_RELAXED_MODE
       if (this->Makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) {
         this->Moc.RelaxedMode = true;
-        this->Makefile->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        this->Makefile->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat("AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
                    "deprecated an will be removed in the future.  Consider "
                    "disabling it and converting the target ",
@@ -1220,8 +1221,8 @@
       for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
         files += cmStrCat("  ", Quoted(muf->FullPath), '\n');
       }
-      this->Makefile->IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      this->Makefile->IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(
           cmPolicies::GetPolicyWarning(cmPolicies::CMP0071),
           "\n"
@@ -1252,8 +1253,8 @@
     for (cmSourceFile const* sf : this->AutogenTarget.CMP0100HeadersWarn) {
       files += cmStrCat("  ", Quoted(sf->GetFullPath()), '\n');
     }
-    this->Makefile->IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    this->Makefile->IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat(
         cmPolicies::GetPolicyWarning(cmPolicies::CMP0100),
         "\n"
diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx
index c0d7491..a142b42 100644
--- a/Source/cmReturnCommand.cxx
+++ b/Source/cmReturnCommand.cxx
@@ -5,9 +5,9 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -19,8 +19,8 @@
   if (!args.empty()) {
     switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0140)) {
       case cmPolicies::WARN:
-        status.GetMakefile().IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        status.GetMakefile().IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0140),
             "\n"
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index be9825c..b5907d3 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -10,10 +10,10 @@
 
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmRange.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -64,10 +64,11 @@
       // if there's extra arguments, warn user
       // that they are ignored by this command.
       if (args.size() > 2) {
-        std::string m = "Only the first value argument is used when setting "
-                        "an environment variable.  Argument '" +
-          args[2] + "' and later are unused.";
-        status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m);
+        status.GetMakefile().IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
+          cmStrCat("Only the first value argument is used when setting "
+                   "an environment variable.  Argument '",
+                   args[2] + "' and later are unused."));
       }
       return true;
     }
@@ -229,9 +230,10 @@
   if (cache) {
     std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
     if (!cmState::StringToCacheEntryType(args[cacheStart + 1], type)) {
-      std::string m = "implicitly converting '" + args[cacheStart + 1] +
-        "' to 'STRING' type.";
-      status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m);
+      status.GetMakefile().IssueDiagnostic(cmDiagnostics::CMD_AUTHOR,
+                                           cmStrCat("implicitly converting '",
+                                                    args[cacheStart + 1],
+                                                    "' to 'STRING' type."));
       // Setting this may not be required, since it's
       // initialized as a string. Keeping this here to
       // ensure that the type is actually converting to a string.
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 676a796..f8dd560 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -9,13 +9,13 @@
 #include <cm/optional>
 #include <cm/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmFileSet.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmRange.h"
@@ -345,8 +345,8 @@
   auto isProblematic = [&mf, &propertyValue,
                         op](cm::string_view policy) -> bool {
     if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_ERROR,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Policy ", policy,
                  " is set to NEW and the following non-boolean value given "
                  "for property 'GENERATED' is therefore not allowed:\n",
@@ -354,15 +354,15 @@
       return true;
     }
     if (cmIsOff(propertyValue)) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_ERROR,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat("Unsetting the 'GENERATED' property is not allowed under ",
                  policy, "!\n"));
       return true;
     }
     if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_ERROR,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(
           "Policy ", policy,
           " is set to NEW and appending to the 'GENERATED' property is "
@@ -396,8 +396,8 @@
 
   if (cmp0118PolicyWARN) {
     if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
                  "\nAttempt to set property 'GENERATED' with the following "
                  "non-boolean value (which will be interpreted as \"0\"):\n",
@@ -407,15 +407,15 @@
                  "This will be an error under policy CMP0118.\n"));
     }
     if (cmIsOff(propertyValue)) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
                  "\nUnsetting property 'GENERATED' will not be allowed under "
                  "policy CMP0118!\n"));
     }
     if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
-      mf.IssueMessage(
-        MessageType::AUTHOR_WARNING,
+      mf.IssueDiagnostic(
+        cmDiagnostics::CMD_AUTHOR,
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
                  "\nAppending to property 'GENERATED' will not be allowed "
                  "under policy CMP0118!\n"));
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 3325eee..2ae4fd3 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -7,6 +7,7 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmGlobalGenerator.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
@@ -206,8 +207,8 @@
               if (cmp0115Warning) {
                 *cmp0115Warning = std::move(warning);
               } else {
-                makefile->GetCMakeInstance()->IssueMessage(
-                  MessageType::AUTHOR_WARNING, warning);
+                makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, warning,
+                                          cmListFileBacktrace{});
               }
             }
             return true;
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index d6690af..7074502 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -18,6 +18,7 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -127,8 +128,8 @@
             state = "disabled";
           }
           if (state) {
-            makefile->IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            makefile->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0128),
                        "\nFor compatibility with older versions of CMake, "
                        "compiler extensions won't be ",
@@ -177,8 +178,8 @@
       if (cmp0128 == cmPolicies::WARN &&
           makefile->PolicyOptionalWarningEnabled(
             "CMAKE_POLICY_WARNING_CMP0128")) {
-        makefile->IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        makefile->IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0128),
                    "\nFor compatibility with older versions of CMake, "
                    "unnecessary flags for language standard or compiler "
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 76d0741..e458b4c 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -473,7 +473,7 @@
           if (additionalWarning) {
             warning = cmStrCat(warning, '\n', additionalWarning);
           }
-          mf.IssueMessage(MessageType::AUTHOR_WARNING, warning);
+          mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, warning);
         }
           CM_FALLTHROUGH;
         case cmPolicies::OLD:
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 4d46bf4..94f081b 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -21,6 +21,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
+#include "cmDiagnostics.h"
 #include "cmFileSet.h"
 #include "cmFileSetMetadata.h"
 #include "cmFindPackageStack.h"
@@ -2059,8 +2060,8 @@
     } else {
       switch (target->GetPolicyStatus(*this->Policy)) {
         case cmPolicies::WARN:
-          context->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          context->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0160) + "\n" +
               this->message(prop, target));
           CM_FALLTHROUGH;
@@ -3135,8 +3136,8 @@
 
       switch (this->GetPolicyStatus(cmPolicies::CMP0111)) {
         case cmPolicies::WARN:
-          this->impl->Makefile->IssueMessage(
-            MessageType::AUTHOR_WARNING,
+          this->impl->Makefile->IssueDiagnostic(
+            cmDiagnostics::CMD_AUTHOR,
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" +
               message());
           CM_FALLTHROUGH;
@@ -3326,7 +3327,7 @@
         "\nConfiguration selection for imported target \"", this->GetName(),
         "\" failed, but would select configuration \"", newConfig,
         "\" under the NEW policy.\n");
-      this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
+      this->GetMakefile()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err);
     }
 
     return false;
@@ -3340,7 +3341,7 @@
                "\nConfiguration selection for imported target \"",
                this->GetName(), "\" selected configuration \"", oldConfig,
                "\", but would fail under the NEW policy.\n");
-    this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
+    this->GetMakefile()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err);
   } else if (suffix != newSuffix) {
     // OLD and NEW policies found different configurations.
     cm::string_view newConfig = configFromSuffix(newSuffix);
@@ -3350,7 +3351,7 @@
                this->GetName(), "\" selected configuration \"", oldConfig,
                "\", but would select configuration \"", newConfig,
                "\" under the NEW policy.\n");
-    this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
+    this->GetMakefile()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err);
   }
 
   return true;
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 2c68392..45cdca6 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -12,6 +12,7 @@
 #include <cm/optional>
 #include <cm/string_view>
 
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -320,8 +321,8 @@
 static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left,
                                             int right)
 {
-  mf.IssueMessage(
-    MessageType::AUTHOR_WARNING,
+  mf.IssueDiagnostic(
+    cmDiagnostics::CMD_AUTHOR,
     cmStrCat(
       "Link library type specifier \"", LinkLibraryTypeNames[left],
       "\" is followed by specifier \"", LinkLibraryTypeNames[right],
@@ -443,8 +444,8 @@
   }
 
   if (this->WarnRemoteInterface) {
-    this->Makefile.IssueMessage(
-      MessageType::AUTHOR_WARNING,
+    this->Makefile.IssueDiagnostic(
+      cmDiagnostics::CMD_AUTHOR,
       cmStrCat(
         cmPolicies::GetPolicyWarning(cmPolicies::CMP0079), "\nTarget\n  ",
         this->Target->GetName(),
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 1dd3197..993b87a 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -11,6 +11,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
+#include "cmDiagnostics.h"
 #include "cmFileSet.h"
 #include "cmFileSetMetadata.h"
 #include "cmGeneratorExpression.h"
@@ -186,7 +187,7 @@
       e << "A private source from a directory other than that of target \""
         << tgt->GetName() << "\" has a relative path.";
     }
-    this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+    this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str());
   }
 
   return useAbsoluteContent ? absoluteContent : content;
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index d003636..c356470 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -9,13 +9,13 @@
 #include <utility>
 #include <vector>
 
+#include "cmDiagnostics.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmPropertyMap.h"
 #include "cmRange.h"
@@ -36,8 +36,8 @@
     case cmPolicies::WARN:
       // Only warn if a forbidden character is used in the name.
       if (name.find_first_of("$[] #;\t\n\"\\") != std::string::npos) {
-        mf.IssueMessage(
-          MessageType::AUTHOR_WARNING,
+        mf.IssueDiagnostic(
+          cmDiagnostics::CMD_AUTHOR,
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0110),
                    "\nThe following name given to add_test() is invalid if "
                    "CMP0110 is not set or set to OLD:\n  `",
@@ -148,8 +148,8 @@
           cmList argsWithEmptyValuesPreserved(
             propVal, cmList::ExpandElements::Yes, cmList::EmptyElements::Yes);
           if (launcherWithArgs != argsWithEmptyValuesPreserved) {
-            this->LG->GetMakefile()->IssueMessage(
-              MessageType::AUTHOR_WARNING,
+            this->LG->GetMakefile()->IssueDiagnostic(
+              cmDiagnostics::CMD_AUTHOR,
               cmStrCat("The ", propertyName, " property of target '",
                        target->GetName(),
                        "' contains empty list items. Those empty items are "
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index c6f7432..6622957 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -27,6 +27,7 @@
 #include "cmCryptoHash.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
+#include "cmDiagnostics.h"
 #include "cmFileSetMetadata.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
@@ -397,7 +398,7 @@
       cmStrCat("The C# target \"", this->GeneratorTarget->GetName(),
                "\" is of type STATIC_LIBRARY. This is discouraged (and may be "
                "disabled in future). Make it a SHARED library instead.");
-    this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message);
+    this->Makefile->IssueDiagnostic(cmDiagnostics::CMD_DEPRECATED, message);
   }
 
   if (this->Android &&
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
index 43d8975..34f2ea9 100644
--- a/Source/cmWhileCommand.cxx
+++ b/Source/cmWhileCommand.cxx
@@ -10,6 +10,7 @@
 #include <cmext/string_view>
 
 #include "cmConditionEvaluator.h"
+#include "cmDiagnostics.h"
 #include "cmExecutionStatus.h"
 #include "cmExpandedCommandArgument.h"
 #include "cmFunctionBlocker.h"
@@ -20,7 +21,6 @@
 #include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmake.h"
 
 class cmWhileFunctionBlocker : public cmFunctionBlocker
 {
@@ -117,19 +117,8 @@
 
   if (!errorString.empty() && !enforceError) {
     // This error should only be enforced if CMP0130 is NEW.
-    switch (mf.GetPolicyStatus(cmPolicies::CMP0130)) {
-      case cmPolicies::WARN:
-        // Convert the error to a warning and enforce it.
-        messageType = MessageType::AUTHOR_WARNING;
-        enforceError = true;
-        break;
-      case cmPolicies::OLD:
-        // OLD behavior is to silently ignore the error.
-        break;
-      case cmPolicies::NEW:
-        // NEW behavior is to enforce the error.
-        enforceError = true;
-        break;
+    if (mf.GetPolicyStatus(cmPolicies::CMP0130) != cmPolicies::OLD) {
+      enforceError = true;
     }
   }
 
@@ -144,10 +133,12 @@
     if (mf.GetPolicyStatus(cmPolicies::CMP0130) == cmPolicies::WARN) {
       err =
         cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0130), '\n', err);
-    }
-    mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT);
-    if (messageType == MessageType::FATAL_ERROR) {
-      cmSystemTools::SetFatalErrorOccurred();
+      mf.IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, err, whileBT);
+    } else {
+      mf.IssueMessage(messageType, err, whileBT);
+      if (messageType == MessageType::FATAL_ERROR) {
+        cmSystemTools::SetFatalErrorOccurred();
+      }
     }
   }
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 2a588f6..6bd8cc5 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -48,7 +48,6 @@
 #    include "cmDebuggerPosixPipeConnection.h"
 #  endif //_WIN32
 #endif
-#include "cmDiagnostics.h"
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h"
 #include "cmDuration.h"
@@ -4511,10 +4510,7 @@
       }
     }
     if (haveUnused) {
-      this->IssueMessage(action > cmDiagnostics::Warn
-                           ? MessageType::FATAL_ERROR
-                           : MessageType::WARNING,
-                         msg.str());
+      this->IssueDiagnostic(cmDiagnostics::CMD_UNUSED_CLI, msg.str());
     }
   }
 #endif