https://github.com/earnol created 
https://github.com/llvm/llvm-project/pull/197927

The change https://github.com/llvm/llvm-project/issues/183462 and subsequent 
changes removed all hicpp checkers with giving little time to adapt. This 
change adds a generic check alias mechanism to clang-tidy that supports: 
registering aliases, central alias management table, bidirectional disable 
semantics, NOLINT suppression using alias names, canonical name preference, 
opt-in alias usage notification feature.

>From bf9853854ea7dd2a00bd281e204fec4ece5f7d60 Mon Sep 17 00:00:00 2001
From: Vladislav Aranov <[email protected]>
Date: Fri, 15 May 2026 00:38:26 +0200
Subject: [PATCH] [clang-tidy] Add checker alias framework and restore hicpp
 aliases

The change https://github.com/llvm/llvm-project/issues/183462 and subsequent
changes removed all hicpp checkers with giving little time to adapt.
This change adds a generic check alias mechanism to clang-tidy that supports:
registering aliases, central alias management table, bidirectional disable 
semantics,
NOLINT suppression using alias names, canonical name preference,
opt-in alias usage notification feature.
---
 clang-tools-extra/clang-tidy/CMakeLists.txt   |   6 +-
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |   2 +
 .../ClangTidyDiagnosticConsumer.cpp           |  95 +++++++++++++-
 .../clang-tidy/ClangTidyDiagnosticConsumer.h  |   6 +
 .../clang-tidy/ClangTidyForceLinker.h         |   5 +
 .../clang-tidy/ClangTidyModule.cpp            |  12 +-
 .../clang-tidy/ClangTidyModule.h              |  19 +++
 .../clang-tidy/aliases/CMakeLists.txt         |  21 +++
 .../clang-tidy/aliases/ClangTidyAliases.cpp   | 114 +++++++++++++++++
 .../clang-tidy/aliases/ClangTidyAliases.h     |  32 +++++
 .../clang-tidy/cert/CERTTidyModule.cpp        |   5 -
 .../clang-tidy/tool/ClangTidyMain.cpp         |  18 +++
 clang-tools-extra/docs/ReleaseNotes.rst       |  10 ++
 clang-tools-extra/docs/clang-tidy/index.rst   |   3 +
 .../clang-tidy/checkers/cert/oop11-cpp.cpp    |   2 +-
 .../clang-tidy/checkers/check-aliasing.cpp    |  41 ++++++
 .../clang-tidy/checkers/hicpp-aliases.cpp     | 120 ++++++++++++++++++
 17 files changed, 498 insertions(+), 13 deletions(-)
 create mode 100644 clang-tools-extra/clang-tidy/aliases/CMakeLists.txt
 create mode 100644 clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.cpp
 create mode 100644 clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/check-aliasing.cpp
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/hicpp-aliases.cpp

diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/CMakeLists.txt
index 9ee9255fbe17b..19b2f2d7f74ef 100644
--- a/clang-tools-extra/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -50,8 +50,9 @@ endif()
 
 # Checks.
 # If you add a check, also add it to ClangTidyForceLinker.h in this directory.
-add_subdirectory(android)
 add_subdirectory(abseil)
+add_subdirectory(aliases)
+add_subdirectory(android)
 add_subdirectory(altera)
 add_subdirectory(boost)
 add_subdirectory(bugprone)
@@ -77,8 +78,9 @@ add_subdirectory(portability)
 add_subdirectory(readability)
 add_subdirectory(zircon)
 set(ALL_CLANG_TIDY_CHECKS
-  clangTidyAndroidModule
   clangTidyAbseilModule
+  clangTidyAliasesModule
+  clangTidyAndroidModule
   clangTidyAlteraModule
   clangTidyBoostModule
   clangTidyBugproneModule
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 05c8fd02fe86a..a8468a6e333d9 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -360,6 +360,7 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
   }
+  CheckFactories->resolveAliases();
 }
 
 #if CLANG_TIDY_ENABLE_STATIC_ANALYZER
@@ -720,6 +721,7 @@ ChecksAndOptions getAllChecksAndOptions(bool 
AllowEnablingAnalyzerAlphaCheckers,
        ClangTidyModuleRegistry::entries()) {
     Module.instantiate()->addCheckFactories(Factories);
   }
+  Factories.resolveAliases();
 
   for (const auto &Factory : Factories)
     Result.Checks.insert(Factory.getKey());
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index 88d0a433bc7fb..0c68d1511b530 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -19,6 +19,7 @@
 #include "ClangTidyOptions.h"
 #include "GlobList.h"
 #include "NoLintDirectiveHandler.h"
+#include "aliases/ClangTidyAliases.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Attr.h"
@@ -216,8 +217,20 @@ bool ClangTidyContext::shouldSuppressDiagnostic(
     SmallVectorImpl<tooling::Diagnostic> &NoLintErrors, bool AllowIO,
     bool EnableNoLintBlocks) {
   const std::string CheckName = getCheckName(Info.getID());
-  return NoLintHandler.shouldSuppress(DiagLevel, Info, CheckName, NoLintErrors,
-                                      AllowIO, EnableNoLintBlocks);
+  if (NoLintHandler.shouldSuppress(DiagLevel, Info, CheckName, NoLintErrors,
+                                   AllowIO, EnableNoLintBlocks))
+    return true;
+  // Also check if the alias name for this check is suppressed.
+  StringRef Alias = ClangTidyAliases::getAliasForCanonical(CheckName);
+  if (!Alias.empty() &&
+      NoLintHandler.shouldSuppress(DiagLevel, Info, std::string(Alias),
+                                   NoLintErrors, AllowIO, EnableNoLintBlocks)) 
{
+    if (NotifyAliases)
+      llvm::errs() << "note: '" << Alias << "' is an alias for canonical name 
'"
+                   << CheckName << "' [checker-alias]\n";
+    return true;
+  }
+  return false;
 }
 
 void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
@@ -236,11 +249,85 @@ static bool 
parseFileExtensions(llvm::ArrayRef<std::string> AllFileExtensions,
   return true;
 }
 
+/// Expand check alias patterns in the checks string.
+/// For each glob pattern, if it matches an alias name, also add the canonical
+/// name (and vice versa) with the same +/- prefix. This ensures that disabling
+/// either name disables both.
+static std::string expandCheckAliases(StringRef Checks) {
+  if (Checks.empty())
+    return std::string(Checks);
+
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  bool First = true;
+
+  StringRef Remaining = Checks;
+  while (!Remaining.empty()) {
+    // Trim leading whitespace/commas.
+    Remaining = Remaining.ltrim(" \t\n");
+    if (Remaining.empty())
+      break;
+    if (Remaining.front() == ',') {
+      Remaining = Remaining.drop_front();
+      continue;
+    }
+
+    // Extract the prefix (- or nothing).
+    bool IsNegative = Remaining.consume_front("-");
+    // Extract the glob text up to the next comma or newline.
+    StringRef Glob = Remaining.substr(0, 
Remaining.find_first_of(",\n")).trim();
+    Remaining = Remaining.substr(Glob.size());
+
+    if (Glob.empty())
+      continue;
+
+    // Write the original pattern.
+    if (!First)
+      OS << ',';
+    if (IsNegative)
+      OS << '-';
+    OS << Glob;
+    First = false;
+
+    // Check if this glob matches any alias or canonical name.
+    // Create a regex from the glob for matching.
+    SmallString<128> RegexText("^");
+    for (char C : Glob) {
+      if (C == '*')
+        RegexText.append(".*");
+      else if (StringRef("()^$|+?.[]\\{}").contains(C)) {
+        RegexText.push_back('\\');
+        RegexText.push_back(C);
+      } else {
+        RegexText.push_back(C);
+      }
+    }
+    RegexText.push_back('$');
+    llvm::Regex Re(RegexText);
+
+    for (const auto &[Alias, Canonical] : ClangTidyAliases::getReference()) {
+      if (Re.match(Alias)) {
+        // Alias enabled or disabled: also enable/disable the canonical.
+        OS << ',';
+        if (IsNegative)
+          OS << '-';
+        OS << Canonical;
+      } else if (IsNegative && Re.match(Canonical)) {
+        // Canonical disabled: also disable the alias.
+        OS << ",-";
+        OS << Alias;
+      }
+    }
+  }
+
+  return Result;
+}
+
 void ClangTidyContext::setCurrentFile(StringRef File) {
   CurrentFile = std::string(File);
   CurrentOptions = getOptionsForFile(CurrentFile);
-  CheckFilter = std::make_unique<CachedGlobList>(
-      StringRef(getOptions().Checks.value_or("")));
+  ExpandedChecks = expandCheckAliases(getOptions().Checks.value_or(""));
+  CheckFilter = std::make_unique<CachedGlobList>(StringRef(ExpandedChecks));
   WarningAsErrorFilter = std::make_unique<CachedGlobList>(
       StringRef(getOptions().WarningsAsErrors.value_or("")));
   static const std::vector<std::string> EmptyFileExtensions;
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h 
b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index c76f58bc4cc86..6fb5120db7cca 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -150,6 +150,9 @@ class ClangTidyContext {
   /// exposed as a 'clang-diagnostic-*' check.
   bool isCompilerDiagnostic(unsigned DiagnosticID) const;
 
+  /// Enable alias usage notifications.
+  void setNotifyAliases(bool Notify) { NotifyAliases = Notify; }
+
   /// Returns \c true if the check is enabled for the \c CurrentFile.
   ///
   /// The \c CurrentFile can be changed using \c setCurrentFile.
@@ -247,9 +250,12 @@ class ClangTidyContext {
   std::string CurrentFile;
   ClangTidyOptions CurrentOptions;
 
+  std::string ExpandedChecks;
   std::unique_ptr<CachedGlobList> CheckFilter;
   std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
 
+  bool NotifyAliases = false;
+
   FileExtensionsSet HeaderFileExtensions;
   FileExtensionsSet ImplementationFileExtensions;
 
diff --git a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h 
b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
index 2450384016e25..590f24fb61a65 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
@@ -18,6 +18,11 @@ extern volatile int AbseilModuleAnchorSource;
 [[maybe_unused]] static int AbseilModuleAnchorDestination =
     AbseilModuleAnchorSource;
 
+// This anchor is used to force the linker to link the AliasesModule.
+extern volatile int AliasesModuleAnchorSource;
+[[maybe_unused]] static int AliasesModuleAnchorDestination =
+    AliasesModuleAnchorSource;
+
 // This anchor is used to force the linker to link the AlteraModule.
 extern volatile int AlteraModuleAnchorSource;
 [[maybe_unused]] static int AlteraModuleAnchorDestination =
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
index 976e87dffb0bf..3ac9da9dd0928 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
@@ -12,9 +12,16 @@
 
 #include "ClangTidyModule.h"
 #include "ClangTidyCheck.h"
+#include "aliases/ClangTidyAliases.h"
 
 namespace clang::tidy {
 
+/// Returns true if CheckName is an alias whose canonical check is also 
enabled.
+static bool isRedundantAlias(StringRef CheckName, ClangTidyContext *Context) {
+  StringRef Canonical = ClangTidyAliases::getCanonicalForAlias(CheckName);
+  return !Canonical.empty() && Context->isCheckEnabled(Canonical);
+}
+
 void ClangTidyCheckFactories::registerCheckFactory(StringRef Name,
                                                    CheckFactory Factory) {
   Factories.insert_or_assign(Name, std::move(Factory));
@@ -24,7 +31,8 @@ std::vector<std::unique_ptr<ClangTidyCheck>>
 ClangTidyCheckFactories::createChecks(ClangTidyContext *Context) const {
   std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
   for (const auto &[CheckName, Factory] : Factories)
-    if (Context->isCheckEnabled(CheckName))
+    if (Context->isCheckEnabled(CheckName) &&
+        !isRedundantAlias(CheckName, Context))
       Checks.emplace_back(Factory(CheckName, Context));
   return Checks;
 }
@@ -37,6 +45,8 @@ ClangTidyCheckFactories::createChecksForLanguage(
   for (const auto &[CheckName, Factory] : Factories) {
     if (!Context->isCheckEnabled(CheckName))
       continue;
+    if (isRedundantAlias(CheckName, Context))
+      continue;
     std::unique_ptr<ClangTidyCheck> Check = Factory(CheckName, Context);
     if (Check->isLanguageVersionSupported(LO))
       Checks.push_back(std::move(Check));
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.h 
b/clang-tools-extra/clang-tidy/ClangTidyModule.h
index 3db92c2dab981..dfbeb5e3d85aa 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModule.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModule.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H
 
 #include "ClangTidyOptions.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Registry.h"
@@ -65,6 +66,23 @@ class ClangTidyCheckFactories {
 
   void eraseCheck(StringRef CheckName) { Factories.erase(CheckName); }
 
+  /// Registers \p AliasName as an alias for check \p CanonicalName.
+  /// The alias is resolved after all modules have registered their checks.
+  void registerCheckAlias(StringRef AliasName, StringRef CanonicalName) {
+    PendingAliases.emplace_back(AliasName, CanonicalName);
+  }
+
+  /// Resolves all pending aliases. Must be called after all modules have
+  /// registered their check factories.
+  void resolveAliases() {
+    for (const auto &[Alias, Canonical] : PendingAliases) {
+      auto It = Factories.find(Canonical);
+      if (It != Factories.end())
+        Factories[Alias] = It->second;
+    }
+    PendingAliases.clear();
+  }
+
   /// Create instances of checks that are enabled.
   std::vector<std::unique_ptr<ClangTidyCheck>>
   createChecks(ClangTidyContext *Context) const;
@@ -80,6 +98,7 @@ class ClangTidyCheckFactories {
 
 private:
   FactoryMap Factories;
+  SmallVector<std::pair<std::string, std::string>> PendingAliases;
 };
 
 /// A clang-tidy module groups a number of \c ClangTidyChecks and gives
diff --git a/clang-tools-extra/clang-tidy/aliases/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/aliases/CMakeLists.txt
new file mode 100644
index 0000000000000..4e39b71827121
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/aliases/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  FrontendOpenMP
+  )
+
+add_clang_library(clangTidyAliasesModule STATIC
+  ClangTidyAliases.cpp
+
+  LINK_LIBS
+  clangTidy
+  clangTidyUtils
+
+  DEPENDS
+  omp_gen
+  ClangDriverOptions
+  )
+
+clang_target_link_libraries(clangTidyAliasesModule
+  PRIVATE
+  clangBasic
+  )
diff --git a/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.cpp 
b/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.cpp
new file mode 100644
index 0000000000000..2cc0fadc1b617
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.cpp
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyAliases.h"
+#include "../ClangTidyModule.h"
+#include "llvm/ADT/StringMap.h"
+#include <cassert>
+
+namespace clang::tidy {
+
+/// Alias table. Kept sorted by alias name for readability.
+static constexpr std::pair<StringRef, StringRef> AliasTable[] = {
+    // Permanent aliases.
+    {"cert-dcl03-c", "misc-static-assert"},
+    {"cert-oop11-cpp", "performance-move-constructor-init"},
+    // Deprecated aliases: keeping for backward compatibility.
+    {"hicpp-avoid-c-arrays", "modernize-avoid-c-arrays"},
+    {"hicpp-avoid-goto", "cppcoreguidelines-avoid-goto"},
+    {"hicpp-braces-around-statements", "readability-braces-around-statements"},
+    {"hicpp-deprecated-headers", "modernize-deprecated-headers"},
+    {"hicpp-exception-baseclass", "bugprone-std-exception-baseclass"},
+    {"hicpp-explicit-conversions", "misc-explicit-constructor"},
+    {"hicpp-function-size", "readability-function-size"},
+    {"hicpp-ignored-remove-result", "bugprone-unused-return-value"},
+    {"hicpp-invalid-access-moved", "bugprone-use-after-move"},
+    {"hicpp-member-init", "cppcoreguidelines-pro-type-member-init"},
+    {"hicpp-move-const-arg", "performance-move-const-arg"},
+    {"hicpp-multiway-paths-covered", "bugprone-unhandled-code-paths"},
+    {"hicpp-named-parameter", "readability-named-parameter"},
+    {"hicpp-new-delete-operators", "misc-new-delete-overloads"},
+    {"hicpp-no-array-decay",
+     "cppcoreguidelines-pro-bounds-array-to-pointer-decay"},
+    {"hicpp-no-assembler", "portability-no-assembler"},
+    {"hicpp-no-malloc", "cppcoreguidelines-no-malloc"},
+    {"hicpp-noexcept-move", "performance-noexcept-move-constructor"},
+    {"hicpp-signed-bitwise", "bugprone-signed-bitwise"},
+    {"hicpp-special-member-functions",
+     "cppcoreguidelines-special-member-functions"},
+    {"hicpp-static-assert", "misc-static-assert"},
+    {"hicpp-undelegated-constructor", "bugprone-undelegated-constructor"},
+    {"hicpp-uppercase-literal-suffix", "readability-uppercase-literal-suffix"},
+    {"hicpp-use-auto", "modernize-use-auto"},
+    {"hicpp-use-emplace", "modernize-use-emplace"},
+    {"hicpp-use-equals-default", "modernize-use-equals-default"},
+    {"hicpp-use-equals-delete", "modernize-use-equals-delete"},
+    {"hicpp-use-noexcept", "modernize-use-noexcept"},
+    {"hicpp-use-nullptr", "modernize-use-nullptr"},
+    {"hicpp-use-override", "modernize-use-override"},
+    {"hicpp-vararg", "cppcoreguidelines-pro-type-vararg"},
+};
+
+ArrayRef<std::pair<StringRef, StringRef>> ClangTidyAliases::getReference() {
+  return AliasTable;
+}
+
+StringRef ClangTidyAliases::getCanonicalForAlias(StringRef Alias) {
+  static const auto *Map = [] {
+    auto *M = new llvm::StringMap<StringRef>();
+    for (const auto &[A, Canonical] : AliasTable) {
+      auto Result = M->try_emplace(A, Canonical);
+      assert(Result.second && "Duplicate alias in ClangTidyAliases table");
+    }
+    return M;
+  }();
+  auto It = Map->find(Alias);
+  if (It != Map->end())
+    return It->second;
+  return {};
+}
+
+StringRef ClangTidyAliases::getAliasForCanonical(StringRef Canonical) {
+  static const auto *ReverseMap = [] {
+    auto *M = new llvm::StringMap<StringRef>();
+    for (const auto &[Alias, Canon] : AliasTable) {
+      auto Result = M->try_emplace(Canon, Alias);
+      assert(Result.second &&
+             "Duplicate canonical name in ClangTidyAliases table");
+    }
+    return M;
+  }();
+  auto It = ReverseMap->find(Canonical);
+  if (It != ReverseMap->end())
+    return It->second;
+  return {};
+}
+
+namespace aliases {
+namespace {
+
+class AliasesModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    for (const auto &[Alias, Canonical] : AliasTable)
+      CheckFactories.registerCheckAlias(Alias, Canonical);
+  }
+};
+
+} // namespace
+
+static ClangTidyModuleRegistry::Add<AliasesModule>
+    X("aliases-module", "Adds check aliases for backward compatibility.");
+
+} // namespace aliases
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the AliasesModule.
+volatile int AliasesModuleAnchorSource = 0;
+
+} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.h 
b/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.h
new file mode 100644
index 0000000000000..d110c806fabe1
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/aliases/ClangTidyAliases.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYALIASES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYALIASES_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <utility>
+
+namespace clang::tidy {
+
+class ClangTidyAliases {
+public:
+  /// Look up the canonical name for an alias.
+  static StringRef getCanonicalForAlias(StringRef Alias);
+
+  /// Look up the alias for a canonical name.
+  static StringRef getAliasForCanonical(StringRef Canonical);
+
+  /// Get a reference to the full alias table for iteration.
+  static ArrayRef<std::pair<StringRef, StringRef>> getReference();
+};
+
+} // namespace clang::tidy
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYALIASES_H
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp 
b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index ee1ce59d80b0d..3a56f5b1f9393 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -35,11 +35,9 @@
 #include "../misc/NewDeleteOverloadsCheck.h"
 #include "../misc/NonCopyableObjectsCheck.h"
 #include "../misc/PredictableRandCheck.h"
-#include "../misc/StaticAssertCheck.h"
 #include "../misc/ThrowByValueCatchByReferenceCheck.h"
 #include "../modernize/AvoidSetjmpLongjmpCheck.h"
 #include "../modernize/AvoidVariadicFunctionsCheck.h"
-#include "../performance/MoveConstructorInitCheck.h"
 #include "../readability/EnumInitialValueCheck.h"
 #include "../readability/UppercaseLiteralSuffixCheck.h"
 
@@ -275,8 +273,6 @@ class CERTModule : public ClangTidyModule {
     CheckFactories.registerCheck<bugprone::SignalHandlerCheck>(
         "cert-msc54-cpp");
     // OOP
-    CheckFactories.registerCheck<performance::MoveConstructorInitCheck>(
-        "cert-oop11-cpp");
     CheckFactories.registerCheck<bugprone::UnhandledSelfAssignmentCheck>(
         "cert-oop54-cpp");
     CheckFactories.registerCheck<bugprone::RawMemoryCallOnNonTrivialTypeCheck>(
@@ -292,7 +288,6 @@ class CERTModule : public ClangTidyModule {
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con36-c");
     // DCL
-    CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
     CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
         "cert-dcl16-c");
     CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>(
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 949a88f0fd50d..ba7b77aca6eac 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -18,6 +18,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyForceLinker.h" // IWYU pragma: keep
 #include "../GlobList.h"
+#include "../aliases/ClangTidyAliases.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/CommandLine.h"
@@ -237,6 +238,12 @@ line or a specific configuration file.
 )"),
                                    cl::init(false), 
cl::cat(ClangTidyCategory));
 
+static cl::opt<bool> NotifyAliases("notify-aliases", desc(R"(
+Emit a note for each check alias used in --checks
+or NOLINT comments, showing the canonical check name.
+)"),
+                                   cl::init(false), 
cl::cat(ClangTidyCategory));
+
 static cl::opt<std::string> Config("config", desc(R"(
 Specifies a configuration in YAML/JSON format:
   -config="{Checks: '*',
@@ -658,6 +665,16 @@ int clangTidyMain(int argc, const char **argv) {
       getCheckNames(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers,
                     ExperimentalCustomChecks);
 
+  if (NotifyAliases) {
+    GlobList OriginalFilter(StringRef(EffectiveOptions.Checks.value_or("")),
+                            false);
+    for (const auto &[Alias, Canonical] : ClangTidyAliases::getReference())
+      if (OriginalFilter.contains(Alias))
+        llvm::errs() << "note: '" << Alias
+                     << "' is an alias for canonical name '" << Canonical
+                     << "' [checker-alias]\n";
+  }
+
   if (ExplainConfig) {
     // FIXME: Show other ClangTidyOptions' fields, like ExtraArg.
     std::vector<ClangTidyOptionsProvider::OptionsSource> RawOptions =
@@ -737,6 +754,7 @@ int clangTidyMain(int argc, const char **argv) {
   ClangTidyContext Context(
       std::move(OwningOptionsProvider), AllowEnablingAnalyzerAlphaCheckers,
       EnableModuleHeadersParsing, ExperimentalCustomChecks);
+  Context.setNotifyAliases(NotifyAliases);
   std::vector<ClangTidyError> Errors =
       runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
                    FixNotes, EnableCheckProfile, ProfilePrefix, Quiet);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index b1b786cfc4593..41ae4d2a78638 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -185,6 +185,16 @@ Improvements to clang-query
 Improvements to clang-tidy
 --------------------------
 
+- Added a check alias framework that allows registering alternative names for
+  existing checks. Aliases support bidirectional disable semantics (disabling
+  either the alias or canonical name disables both) and NOLINT suppression
+  using alias names. Added ``--notify-aliases`` option that emits a note for
+  each alias used in ``--checks`` or ``NOLINT`` comments, showing the canonical
+  check name.
+
+- Preserved all 31 ``hicpp-*`` check aliases that were removed for backward
+  compatibility.
+
 - Improved :program:`check_clang_tidy.py` script by adding the `-check-header`
   argument to simplify testing of header files. This argument automatically
   manages the creation of temporary header files and ensures that diagnostics
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst 
b/clang-tools-extra/docs/clang-tidy/index.rst
index 908dee6c18a7f..0d0ead0aad773 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -190,6 +190,9 @@ An overview of all the command-line options:
     --explain-config                 - For each enabled check explains, where 
it is
                                        enabled, i.e. in clang-tidy binary, 
command
                                        line or a specific configuration file.
+    --notify-aliases                 - Emit a note for each check alias used in
+                                       --checks or NOLINT comments, showing the
+                                       canonical check name.
     --export-fixes=<filename>        - YAML file to store suggested fixes in. 
The
                                        stored fixes can be applied to the 
input source
                                        code with clang-apply-replacements.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cert/oop11-cpp.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/cert/oop11-cpp.cpp
index f7f3a64867598..e7a8c5706e7b1 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cert/oop11-cpp.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cert/oop11-cpp.cpp
@@ -11,7 +11,7 @@ struct B {
 struct D {
   B b;
 
-  // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: move constructor initializes 
class member by calling a copy constructor [cert-oop11-cpp]
+  // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: move constructor initializes 
class member by calling a copy constructor [performance-move-constructor-init]
   D(D &&d) : b(d.b) {}
 
   // This should not produce a diagnostic because it is not covered under
diff --git a/clang-tools-extra/test/clang-tidy/checkers/check-aliasing.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/check-aliasing.cpp
new file mode 100644
index 0000000000000..589708f838d1d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/check-aliasing.cpp
@@ -0,0 +1,41 @@
+// Test the clang-tidy check alias framework using permanent cert aliases.
+//
+// Test: enabling alias enables canonical check.
+// RUN: clang-tidy --list-checks --checks='-*,cert-oop11-cpp' 2>&1 | FileCheck 
-check-prefix=ENABLE %s
+//
+// Test: disabling canonical disables alias.
+// RUN: clang-tidy --list-checks --allow-no-checks 
--checks='-*,cert-oop11-cpp,-performance-move-constructor-init' 2>&1 | 
FileCheck -check-prefix=DISABLE %s
+//
+// Test: disabling alias disables canonical.
+// RUN: clang-tidy --list-checks --allow-no-checks 
--checks='-*,performance-move-constructor-init,-cert-oop11-cpp' 2>&1 | 
FileCheck -check-prefix=DISABLE-REVERSE %s
+//
+// Test: --notify-aliases emits note for alias in --checks.
+// RUN: clang-tidy %s --notify-aliases --checks='-*,cert-dcl03-c' -- 
-std=c++11 2>&1 | FileCheck -check-prefix=NOTIFY %s
+//
+// Test: NOLINT with alias name suppresses canonical diagnostic.
+// RUN: clang-tidy %s --checks='-*,cert-oop11-cpp' -- -std=c++11 2>&1 | 
FileCheck --allow-empty -check-prefix=NOLINT-ALIAS %s
+
+// ENABLE-DAG: cert-oop11-cpp
+// ENABLE-DAG: performance-move-constructor-init
+
+// DISABLE-NOT: cert-oop11-cpp
+// DISABLE-NOT: performance-move-constructor-init
+
+// DISABLE-REVERSE-NOT: cert-oop11-cpp
+// DISABLE-REVERSE-NOT: performance-move-constructor-init
+
+// NOTIFY: note: 'cert-dcl03-c' is an alias for canonical name 
'misc-static-assert' [checker-alias]
+
+// NOLINT-ALIAS-NOT: warning:
+
+struct B {
+  B(B &&) noexcept = default;
+  B(const B &) = default;
+  B &operator=(const B &) = default;
+  ~B() {}
+};
+
+struct D {
+  B b;
+  D(D &&d) : b(d.b) {} // NOLINT(cert-oop11-cpp)
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/hicpp-aliases.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/hicpp-aliases.cpp
new file mode 100644
index 0000000000000..fe556bfa8a5cd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/hicpp-aliases.cpp
@@ -0,0 +1,120 @@
+// Test that all 31 hicpp aliases are properly registered and that
+// enable/disable semantics work correctly with bidirectional alias expansion.
+//
+// Test enable: hicpp-use-override triggers the check.
+// RUN: clang-tidy %s --checks='-*,hicpp-use-override' -- -std=c++11 2>&1 | 
FileCheck -check-prefix=ENABLE %s
+//
+// Test disable: enabling alias then disabling canonical disables both.
+// RUN: clang-tidy %s --allow-no-checks 
--checks='-*,hicpp-use-override,-modernize-use-override' -- -std=c++11 2>&1 | 
FileCheck --allow-empty -check-prefix=DISABLE %s
+//
+// Verify all 31 aliases are listed.
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*' 2>&1 | FileCheck 
-check-prefix=LIST %s
+//
+// Verify disable-by-canonical works for each alias (disabling canonical 
removes alias from list).
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-modernize-avoid-c-arrays' 2>&1 | FileCheck 
-check-prefix=NO-AVOID-C-ARRAYS %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-avoid-goto' 2>&1 | FileCheck 
-check-prefix=NO-AVOID-GOTO %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-readability-braces-around-statements' 2>&1 | FileCheck 
-check-prefix=NO-BRACES %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-modernize-deprecated-headers' 2>&1 | FileCheck 
-check-prefix=NO-DEPRECATED-HEADERS %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-std-exception-baseclass' 2>&1 | FileCheck 
-check-prefix=NO-EXCEPTION %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-misc-explicit-constructor' 2>&1 | FileCheck 
-check-prefix=NO-EXPLICIT %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-readability-function-size' 2>&1 | FileCheck 
-check-prefix=NO-FUNCTION-SIZE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-unused-return-value' 2>&1 | FileCheck 
-check-prefix=NO-IGNORED-REMOVE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-signed-bitwise' 2>&1 | FileCheck 
-check-prefix=NO-SIGNED-BITWISE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-readability-named-parameter' 2>&1 | FileCheck 
-check-prefix=NO-NAMED-PARAM %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-use-after-move' 2>&1 | FileCheck 
-check-prefix=NO-INVALID-ACCESS %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-pro-type-member-init' 2>&1 | FileCheck 
-check-prefix=NO-MEMBER-INIT %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-performance-move-const-arg' 2>&1 | FileCheck 
-check-prefix=NO-MOVE-CONST %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-misc-new-delete-overloads' 2>&1 | FileCheck 
-check-prefix=NO-NEW-DELETE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-performance-noexcept-move-constructor' 2>&1 | FileCheck 
-check-prefix=NO-NOEXCEPT-MOVE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay' 2>&1 
| FileCheck -check-prefix=NO-ARRAY-DECAY %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-unhandled-code-paths' 2>&1 | FileCheck 
-check-prefix=NO-MULTIWAY %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-portability-no-assembler' 2>&1 | FileCheck 
-check-prefix=NO-ASSEMBLER %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-no-malloc' 2>&1 | FileCheck 
-check-prefix=NO-MALLOC %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-special-member-functions' 2>&1 | 
FileCheck -check-prefix=NO-SPECIAL-MEMBER %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-misc-static-assert' 
2>&1 | FileCheck -check-prefix=NO-STATIC-ASSERT %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-modernize-use-auto' 
2>&1 | FileCheck -check-prefix=NO-USE-AUTO %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-bugprone-undelegated-constructor' 2>&1 | FileCheck 
-check-prefix=NO-UNDELEGATED %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-modernize-use-emplace' 
2>&1 | FileCheck -check-prefix=NO-USE-EMPLACE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-modernize-use-equals-default' 2>&1 | FileCheck 
-check-prefix=NO-USE-EQUALS-DEFAULT %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-modernize-use-equals-delete' 2>&1 | FileCheck 
-check-prefix=NO-USE-EQUALS-DELETE %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-modernize-use-noexcept' 
2>&1 | FileCheck -check-prefix=NO-USE-NOEXCEPT %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-modernize-use-nullptr' 
2>&1 | FileCheck -check-prefix=NO-USE-NULLPTR %s
+// RUN: clang-tidy --list-checks --checks='-*,hicpp-*,-modernize-use-override' 
2>&1 | FileCheck -check-prefix=NO-USE-OVERRIDE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-readability-uppercase-literal-suffix' 2>&1 | FileCheck 
-check-prefix=NO-UPPERCASE %s
+// RUN: clang-tidy --list-checks 
--checks='-*,hicpp-*,-cppcoreguidelines-pro-type-vararg' 2>&1 | FileCheck 
-check-prefix=NO-VARARG %s
+
+// ENABLE: warning: annotate this function with 'override'
+// DISABLE-NOT: warning:
+
+// LIST-DAG: hicpp-avoid-c-arrays
+// LIST-DAG: hicpp-avoid-goto
+// LIST-DAG: hicpp-braces-around-statements
+// LIST-DAG: hicpp-deprecated-headers
+// LIST-DAG: hicpp-exception-baseclass
+// LIST-DAG: hicpp-explicit-conversions
+// LIST-DAG: hicpp-function-size
+// LIST-DAG: hicpp-ignored-remove-result
+// LIST-DAG: hicpp-invalid-access-moved
+// LIST-DAG: hicpp-member-init
+// LIST-DAG: hicpp-move-const-arg
+// LIST-DAG: hicpp-multiway-paths-covered
+// LIST-DAG: hicpp-named-parameter
+// LIST-DAG: hicpp-new-delete-operators
+// LIST-DAG: hicpp-no-array-decay
+// LIST-DAG: hicpp-no-assembler
+// LIST-DAG: hicpp-no-malloc
+// LIST-DAG: hicpp-noexcept-move
+// LIST-DAG: hicpp-signed-bitwise
+// LIST-DAG: hicpp-special-member-functions
+// LIST-DAG: hicpp-static-assert
+// LIST-DAG: hicpp-undelegated-constructor
+// LIST-DAG: hicpp-uppercase-literal-suffix
+// LIST-DAG: hicpp-use-auto
+// LIST-DAG: hicpp-use-emplace
+// LIST-DAG: hicpp-use-equals-default
+// LIST-DAG: hicpp-use-equals-delete
+// LIST-DAG: hicpp-use-noexcept
+// LIST-DAG: hicpp-use-nullptr
+// LIST-DAG: hicpp-use-override
+// LIST-DAG: hicpp-vararg
+
+// NO-AVOID-C-ARRAYS-NOT: hicpp-avoid-c-arrays
+// NO-AVOID-GOTO-NOT: hicpp-avoid-goto
+// NO-BRACES-NOT: hicpp-braces-around-statements
+// NO-DEPRECATED-HEADERS-NOT: hicpp-deprecated-headers
+// NO-EXCEPTION-NOT: hicpp-exception-baseclass
+// NO-EXPLICIT-NOT: hicpp-explicit-conversions
+// NO-FUNCTION-SIZE-NOT: hicpp-function-size
+// NO-IGNORED-REMOVE-NOT: hicpp-ignored-remove-result
+// NO-SIGNED-BITWISE-NOT: hicpp-signed-bitwise
+// NO-NAMED-PARAM-NOT: hicpp-named-parameter
+// NO-INVALID-ACCESS-NOT: hicpp-invalid-access-moved
+// NO-MEMBER-INIT-NOT: hicpp-member-init
+// NO-MOVE-CONST-NOT: hicpp-move-const-arg
+// NO-NEW-DELETE-NOT: hicpp-new-delete-operators
+// NO-NOEXCEPT-MOVE-NOT: hicpp-noexcept-move
+// NO-ARRAY-DECAY-NOT: hicpp-no-array-decay
+// NO-MULTIWAY-NOT: hicpp-multiway-paths-covered
+// NO-ASSEMBLER-NOT: hicpp-no-assembler
+// NO-MALLOC-NOT: hicpp-no-malloc
+// NO-SPECIAL-MEMBER-NOT: hicpp-special-member-functions
+// NO-STATIC-ASSERT-NOT: hicpp-static-assert
+// NO-USE-AUTO-NOT: hicpp-use-auto
+// NO-UNDELEGATED-NOT: hicpp-undelegated-constructor
+// NO-USE-EMPLACE-NOT: hicpp-use-emplace
+// NO-USE-EQUALS-DEFAULT-NOT: hicpp-use-equals-default
+// NO-USE-EQUALS-DELETE-NOT: hicpp-use-equals-delete
+// NO-USE-NOEXCEPT-NOT: hicpp-use-noexcept
+// NO-USE-NULLPTR-NOT: hicpp-use-nullptr
+// NO-USE-OVERRIDE-NOT: hicpp-use-override
+// NO-UPPERCASE-NOT: hicpp-uppercase-literal-suffix
+// NO-VARARG-NOT: hicpp-vararg
+
+struct Base {
+  virtual void foo();
+  virtual ~Base();
+};
+
+struct Derived : Base {
+  void foo();
+};

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to