[clang-tools-extra] 5b37cdd - [clang-tidy] Introduce HeaderFileExtensions and ImplementationFileExtensions options

Carlos Galvez via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 19 05:44:21 PST 2023


Author: Carlos Galvez
Date: 2023-02-19T13:44:11Z
New Revision: 5b37cddff8e0140420ad776066529cf8f41d64d2

URL: https://github.com/llvm/llvm-project/commit/5b37cddff8e0140420ad776066529cf8f41d64d2
DIFF: https://github.com/llvm/llvm-project/commit/5b37cddff8e0140420ad776066529cf8f41d64d2.diff

LOG: [clang-tidy] Introduce HeaderFileExtensions and ImplementationFileExtensions options

Re-introduce the patch that was reverted previously.
In the first attempt, the checks would not be able to
read from the global option, since getLocalOrGlobal
only works with string types. Additional logic is needed
in order to support both use cases in the transition
period. All that logic will be removed when the local
options are fully removed.

We have a number of checks designed to analyze problems
in header files only, for example:

bugprone-suspicious-include
google-build-namespaces
llvm-header-guard
misc-definitions-in-header
...

All these checks duplicate the same logic and options
to determine whether a location is placed in the main
source file or in the header. More checks are coming
up with similar requirements.

Thus, to remove duplication, let's move this option
to the top-level configuration of clang-tidy (since
it's something all checks should share).

Add a deprecation notice for all checks that use the
local option, prompting to update to the global option.

Differential Revision: https://reviews.llvm.org/D142655

Added: 
    clang-tools-extra/clang-tidy/FileExtensionsSet.h

Modified: 
    clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
    clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
    clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
    clang-tools-extra/clang-tidy/ClangTidyOptions.h
    clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
    clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h
    clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
    clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
    clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
    clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
    clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp
    clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h
    clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
    clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
    clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
    clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
    clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.cpp
    clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.h
    clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
    clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h
    clang-tools-extra/clang-tidy/utils/HeaderGuard.h
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-include.rst
    clang-tools-extra/docs/clang-tidy/checks/google/build-namespaces.rst
    clang-tools-extra/docs/clang-tidy/checks/google/global-names-in-headers.rst
    clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst
    clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl.rst
    clang-tools-extra/docs/clang-tidy/checks/misc/definitions-in-headers.rst
    clang-tools-extra/docs/clang-tidy/checks/misc/unused-using-decls.rst
    clang-tools-extra/docs/clang-tidy/checks/misc/use-anonymous-namespace.rst
    clang-tools-extra/docs/clang-tidy/index.rst
    clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp
    clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index 11ee7a09a112b..9d693bd94f40a 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Attr.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/FileManager.h"
@@ -222,12 +223,30 @@ void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
   DiagEngine->setSourceManager(SourceMgr);
 }
 
+static bool parseFileExtensions(llvm::ArrayRef<std::string> AllFileExtensions,
+                                FileExtensionsSet &FileExtensions) {
+  FileExtensions.clear();
+  for (StringRef Suffix : AllFileExtensions) {
+    StringRef Extension = Suffix.trim();
+    if (!llvm::all_of(Extension, isAlphanumeric))
+      return false;
+    FileExtensions.insert(Extension);
+  }
+  return true;
+}
+
 void ClangTidyContext::setCurrentFile(StringRef File) {
   CurrentFile = std::string(File);
   CurrentOptions = getOptionsForFile(CurrentFile);
   CheckFilter = std::make_unique<CachedGlobList>(*getOptions().Checks);
   WarningAsErrorFilter =
       std::make_unique<CachedGlobList>(*getOptions().WarningsAsErrors);
+  if (!parseFileExtensions(*getOptions().HeaderFileExtensions,
+                           HeaderFileExtensions))
+    this->configurationDiag("Invalid header file extensions");
+  if (!parseFileExtensions(*getOptions().ImplementationFileExtensions,
+                           ImplementationFileExtensions))
+    this->configurationDiag("Invalid implementation file extensions");
 }
 
 void ClangTidyContext::setASTContext(ASTContext *Context) {

diff  --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index ac5e896bcb851..15f1b672e6d42 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -11,6 +11,7 @@
 
 #include "ClangTidyOptions.h"
 #include "ClangTidyProfiling.h"
+#include "FileExtensionsSet.h"
 #include "NoLintDirectiveHandler.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Tooling/Core/Diagnostic.h"
@@ -160,6 +161,14 @@ class ClangTidyContext {
   /// \c CurrentFile.
   ClangTidyOptions getOptionsForFile(StringRef File) const;
 
+  const FileExtensionsSet &getHeaderFileExtensions() const {
+    return HeaderFileExtensions;
+  }
+
+  const FileExtensionsSet &getImplementationFileExtensions() const {
+    return ImplementationFileExtensions;
+  }
+
   /// Returns \c ClangTidyStats containing issued and ignored diagnostic
   /// counters.
   const ClangTidyStats &getStats() const { return Stats; }
@@ -221,6 +230,9 @@ class ClangTidyContext {
   std::unique_ptr<CachedGlobList> CheckFilter;
   std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
 
+  FileExtensionsSet HeaderFileExtensions;
+  FileExtensionsSet ImplementationFileExtensions;
+
   LangOptions LangOpts;
 
   ClangTidyStats Stats;

diff  --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 808929b11f796..84defccde513e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -122,6 +122,9 @@ template <> struct MappingTraits<ClangTidyOptions> {
     bool Ignored = false;
     IO.mapOptional("Checks", Options.Checks);
     IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors);
+    IO.mapOptional("HeaderFileExtensions", Options.HeaderFileExtensions);
+    IO.mapOptional("ImplementationFileExtensions",
+                   Options.ImplementationFileExtensions);
     IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
     IO.mapOptional("AnalyzeTemporaryDtors", Ignored); // deprecated
     IO.mapOptional("FormatStyle", Options.FormatStyle);
@@ -142,6 +145,8 @@ ClangTidyOptions ClangTidyOptions::getDefaults() {
   ClangTidyOptions Options;
   Options.Checks = "";
   Options.WarningsAsErrors = "";
+  Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"};
+  Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"};
   Options.HeaderFilterRegex = "";
   Options.SystemHeaders = false;
   Options.FormatStyle = "none";
@@ -178,6 +183,9 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other,
                                               unsigned Order) {
   mergeCommaSeparatedLists(Checks, Other.Checks);
   mergeCommaSeparatedLists(WarningsAsErrors, Other.WarningsAsErrors);
+  overrideValue(HeaderFileExtensions, Other.HeaderFileExtensions);
+  overrideValue(ImplementationFileExtensions,
+                Other.ImplementationFileExtensions);
   overrideValue(HeaderFilterRegex, Other.HeaderFilterRegex);
   overrideValue(SystemHeaders, Other.SystemHeaders);
   overrideValue(FormatStyle, Other.FormatStyle);

diff  --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index 4a6cdf097905b..d0df474bc38e0 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -71,6 +71,14 @@ struct ClangTidyOptions {
   /// WarningsAsErrors filter.
   std::optional<std::string> WarningsAsErrors;
 
+  /// File extensions to consider to determine if a given diagnostic is located
+  /// in a header file.
+  std::optional<std::vector<std::string>> HeaderFileExtensions;
+
+  /// File extensions to consider to determine if a given diagnostic is located
+  /// is located in an implementation file.
+  std::optional<std::vector<std::string>> ImplementationFileExtensions;
+
   /// Output warnings from headers matching this filter. Warnings from
   /// main files will always be displayed.
   std::optional<std::string> HeaderFilterRegex;

diff  --git a/clang-tools-extra/clang-tidy/FileExtensionsSet.h b/clang-tools-extra/clang-tidy/FileExtensionsSet.h
new file mode 100644
index 0000000000000..417b1b69f11f7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/FileExtensionsSet.h
@@ -0,0 +1,19 @@
+//===--- FileExtensionsSet.h - clang-tidy -----------------------*- C++ -*-===//
+//
+// 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_FILE_EXTENSIONS_SET_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FILE_EXTENSIONS_SET_H
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang::tidy {
+typedef llvm::SmallSet<llvm::StringRef, 5> FileExtensionsSet;
+} // namespace clang::tidy
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FILE_EXTENSIONS_SET_H

diff  --git a/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
index 79731ad818c65..4a467120181b4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DynamicStaticInitializersCheck.h"
+#include "../utils/FileExtensionsUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 
@@ -24,17 +25,22 @@ AST_MATCHER(clang::VarDecl, hasConstantDeclaration) {
   return false;
 }
 
-DynamicStaticInitializersCheck::DynamicStaticInitializersCheck(StringRef Name,
-                                                               ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-        "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+DynamicStaticInitializersCheck::DynamicStaticInitializersCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void DynamicStaticInitializersCheck::storeOptions(

diff  --git a/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
index b1385723ee149..d8ac31dc3b850 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
@@ -10,7 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DYNAMIC_STATIC_INITIALIZERS_CHECK_H
 
 #include "../ClangTidyCheck.h"
-#include "../utils/FileExtensionsUtils.h"
+#include "../FileExtensionsSet.h"
 
 namespace clang::tidy::bugprone {
 
@@ -34,8 +34,8 @@ class DynamicStaticInitializersCheck : public ClangTidyCheck {
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::bugprone

diff  --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp
index 13020bcc503c8..49293ab727af4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SuspiciousIncludeCheck.h"
+#include "../utils/FileExtensionsUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Lex/Preprocessor.h"
 #include <optional>
@@ -36,25 +37,35 @@ class SuspiciousIncludePPCallbacks : public PPCallbacks {
 
 SuspiciousIncludeCheck::SuspiciousIncludeCheck(StringRef Name,
                                                ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())),
-      RawStringImplementationFileExtensions(Options.getLocalOrGlobal(
-          "ImplementationFileExtensions",
-          utils::defaultImplementationFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringImplementationFileExtensions,
-                                  ImplementationFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid implementation file extension: '%0'")
-        << RawStringImplementationFileExtensions;
-  }
-
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> ImplementationFileExtensionsOption =
+      Options.get("ImplementationFileExtensions");
+  RawStringImplementationFileExtensions =
+      ImplementationFileExtensionsOption.value_or(
+          utils::defaultImplementationFileExtensions());
+  if (ImplementationFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringImplementationFileExtensions,
+                                    ImplementationFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid implementation file extension: '%0'")
+          << RawStringImplementationFileExtensions;
+    }
+  } else
+    ImplementationFileExtensions = Context->getImplementationFileExtensions();
+
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void SuspiciousIncludeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {

diff  --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h
index 07edd85069f71..0cc1639678a28 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h
@@ -40,12 +40,12 @@ class SuspiciousIncludeCheck : public ClangTidyCheck {
                            Preprocessor *ModuleExpanderPP) override;
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
-  utils::FileExtensionsSet HeaderFileExtensions;
-  utils::FileExtensionsSet ImplementationFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
+  FileExtensionsSet ImplementationFileExtensions;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  const StringRef RawStringImplementationFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  StringRef RawStringImplementationFileExtensions;
 };
 
 } // namespace clang::tidy::bugprone

diff  --git a/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
index 1c2a4e1cd3aea..59031b4e1eec5 100644
--- a/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
@@ -18,15 +18,20 @@ namespace clang::tidy::google::readability {
 
 GlobalNamesInHeadersCheck::GlobalNamesInHeadersCheck(StringRef Name,
                                                      ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void GlobalNamesInHeadersCheck::storeOptions(

diff  --git a/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h b/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
index a152e2c3606b3..625a1918fef16 100644
--- a/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
+++ b/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
@@ -35,8 +35,8 @@ class GlobalNamesInHeadersCheck : public ClangTidyCheck {
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::google::readability

diff  --git a/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp b/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
index 72de9c1e94b20..59766a1a3fd48 100644
--- a/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
@@ -17,15 +17,20 @@ namespace clang::tidy::google::build {
 
 UnnamedNamespaceInHeaderCheck::UnnamedNamespaceInHeaderCheck(
     StringRef Name, ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void UnnamedNamespaceInHeaderCheck::storeOptions(

diff  --git a/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h b/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
index ac26746a4711d..8a16e750385fd 100644
--- a/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
+++ b/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
@@ -41,8 +41,8 @@ class UnnamedNamespaceInHeaderCheck : public ClangTidyCheck {
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::google::build

diff  --git a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp
index 3f93521498ba8..803e32da5279a 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "InlineFunctionDeclCheck.h"
+#include "../utils/FileExtensionsUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 
@@ -19,30 +20,12 @@ namespace clang::tidy::llvm_libc {
 InlineFunctionDeclCheck::InlineFunctionDeclCheck(StringRef Name,
                                                  ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
-}
+      HeaderFileExtensions(Context->getHeaderFileExtensions()) {}
 
 void InlineFunctionDeclCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(decl(functionDecl()).bind("func_decl"), this);
 }
 
-void InlineFunctionDeclCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
-  Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
-}
-
 void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
 

diff  --git a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h
index a69a5dcc9c2db..85d87a59e3733 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h
+++ b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h
@@ -10,7 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_INLINEFUNCTIONDECLCHECK_H
 
 #include "../ClangTidyCheck.h"
-#include "../utils/FileExtensionsUtils.h"
+#include "../FileExtensionsSet.h"
 
 namespace clang::tidy::llvm_libc {
 
@@ -30,13 +30,11 @@ class InlineFunctionDeclCheck : public ClangTidyCheck {
     return LangOpts.CPlusPlus;
   }
 
-  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::llvm_libc

diff  --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
index c894d7edbf40b..67e1a04a35afe 100644
--- a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -16,7 +16,7 @@ namespace clang::tidy::misc {
 
 namespace {
 
-AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, utils::FileExtensionsSet,
+AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, FileExtensionsSet,
               HeaderFileExtensions) {
   return utils::isExpansionLocInHeaderFile(
       Node.getBeginLoc(), Finder->getASTContext().getSourceManager(),
@@ -28,15 +28,20 @@ AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, utils::FileExtensionsSet,
 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name,
                                                      ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+      UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void DefinitionsInHeadersCheck::storeOptions(

diff  --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
index db32cabc95642..e0095494d339b 100644
--- a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
@@ -41,8 +41,8 @@ class DefinitionsInHeadersCheck : public ClangTidyCheck {
 
 private:
   const bool UseHeaderFileExtension;
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::misc

diff  --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
index 3602aa4a247d6..8aadb8fcb1344 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -38,14 +38,20 @@ static bool shouldCheckDecl(const Decl *TargetDecl) {
 
 UnusedUsingDeclsCheck::UnusedUsingDeclsCheck(StringRef Name,
                                              ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters()))
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {

diff  --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
index 5ca7aef9dffac..212139ad28483 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
@@ -47,8 +47,8 @@ class UnusedUsingDeclsCheck : public ClangTidyCheck {
 
   std::vector<UsingDeclContext> Contexts;
 
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::misc

diff  --git a/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.cpp
index 7e4bba216f0ce..a6337f5bab834 100644
--- a/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.cpp
@@ -17,7 +17,7 @@ namespace {
 AST_POLYMORPHIC_MATCHER_P(isInHeaderFile,
                           AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
                                                           VarDecl),
-                          utils::FileExtensionsSet, HeaderFileExtensions) {
+                          FileExtensionsSet, HeaderFileExtensions) {
   return utils::isExpansionLocInHeaderFile(
       Node.getBeginLoc(), Finder->getASTContext().getSourceManager(),
       HeaderFileExtensions);
@@ -31,15 +31,20 @@ AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
 
 UseAnonymousNamespaceCheck::UseAnonymousNamespaceCheck(
     StringRef Name, ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-          "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-  if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                                  HeaderFileExtensions,
-                                  utils::defaultFileExtensionDelimiters())) {
-    this->configurationDiag("Invalid header file extension: '%0'")
-        << RawStringHeaderFileExtensions;
-  }
+    : ClangTidyCheck(Name, Context) {
+  std::optional<StringRef> HeaderFileExtensionsOption =
+      Options.get("HeaderFileExtensions");
+  RawStringHeaderFileExtensions =
+      HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
+  if (HeaderFileExtensionsOption) {
+    if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
+                                    HeaderFileExtensions,
+                                    utils::defaultFileExtensionDelimiters())) {
+      this->configurationDiag("Invalid header file extension: '%0'")
+          << RawStringHeaderFileExtensions;
+    }
+  } else
+    HeaderFileExtensions = Context->getHeaderFileExtensions();
 }
 
 void UseAnonymousNamespaceCheck::storeOptions(

diff  --git a/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.h b/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.h
index b3c10a124995f..4a5a867623872 100644
--- a/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/UseAnonymousNamespaceCheck.h
@@ -38,8 +38,8 @@ class UseAnonymousNamespaceCheck : public ClangTidyCheck {
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  const StringRef RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  StringRef RawStringHeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::misc

diff  --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index ff673e78a2836..09162995a0974 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -56,7 +56,12 @@ Configuration files:
   ExtraArgs                    - Same as '--extra-args'.
   ExtraArgsBefore              - Same as '--extra-args-before'.
   FormatStyle                  - Same as '--format-style'.
+  HeaderFileExtensions         - File extensions to consider to determine if a
+                                 given diagnostic is located in a header file.
   HeaderFilterRegex            - Same as '--header-filter-regex'.
+  ImplementationFileExtensions - File extensions to consider to determine if a
+                                 given diagnostic is located in an
+                                 implementation file.
   InheritParentConfig          - If this option is true in a config file, the
                                  configuration file in the parent directory
                                  (if any exists) will be taken and the current
@@ -74,12 +79,14 @@ Configuration files:
 
     $ clang-tidy --dump-config
     ---
-    Checks:              '-*,some-check'
-    WarningsAsErrors:    ''
-    HeaderFilterRegex:   ''
-    FormatStyle:         none
-    InheritParentConfig: true
-    User:                user
+    Checks:                       '-*,some-check'
+    WarningsAsErrors:             ''
+    HeaderFileExtensions:         ['', 'h','hh','hpp','hxx']
+    ImplementationFileExtensions: ['c','cc','cpp','cxx']
+    HeaderFilterRegex:            ''
+    FormatStyle:                  none
+    InheritParentConfig:          true
+    User:                         user
     CheckOptions:
       some-check.SomeOption: 'some value'
     ...
@@ -484,6 +491,26 @@ static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob,
   return AnyInvalid;
 }
 
+static bool verifyFileExtensions(
+    const std::vector<std::string> &HeaderFileExtensions,
+    const std::vector<std::string> &ImplementationFileExtensions,
+    StringRef Source) {
+  bool AnyInvalid = false;
+  for (const auto &HeaderExtension : HeaderFileExtensions) {
+    for (const auto &ImplementationExtension : ImplementationFileExtensions) {
+      if (HeaderExtension == ImplementationExtension) {
+        AnyInvalid = true;
+        auto &Output = llvm::WithColor::warning(llvm::errs(), Source)
+                       << "HeaderFileExtension '" << HeaderExtension << '\''
+                       << " is the same as ImplementationFileExtension '"
+                       << ImplementationExtension << '\'';
+        Output << VerifyConfigWarningEnd;
+      }
+    }
+  }
+  return AnyInvalid;
+}
+
 int clangTidyMain(int argc, const char **argv) {
   llvm::InitLLVM X(argc, argv);
 
@@ -587,6 +614,11 @@ int clangTidyMain(int argc, const char **argv) {
       if (Opts.Checks)
         AnyInvalid |= verifyChecks(Valid.Names, *Opts.Checks, Source);
 
+      if (Opts.HeaderFileExtensions && Opts.ImplementationFileExtensions)
+        AnyInvalid |=
+            verifyFileExtensions(*Opts.HeaderFileExtensions,
+                                 *Opts.ImplementationFileExtensions, Source);
+
       for (auto Key : Opts.CheckOptions.keys()) {
         if (Valid.Options.contains(Key))
           continue;

diff  --git a/clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h b/clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h
index e4299671c0ec5..e23f6b79c6af4 100644
--- a/clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FILE_EXTENSIONS_UTILS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FILE_EXTENSIONS_UTILS_H
 
+#include "../FileExtensionsSet.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/SmallSet.h"
@@ -17,8 +18,6 @@
 
 namespace clang::tidy::utils {
 
-typedef llvm::SmallSet<llvm::StringRef, 5> FileExtensionsSet;
-
 /// Checks whether expansion location of \p Loc is in header file.
 bool isExpansionLocInHeaderFile(SourceLocation Loc, const SourceManager &SM,
                                 const FileExtensionsSet &HeaderFileExtensions);

diff  --git a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h
index 89429e6a01c51..b1ce7839f36a3 100644
--- a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h
+++ b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h
@@ -25,12 +25,20 @@ namespace clang::tidy::utils {
 class HeaderGuardCheck : public ClangTidyCheck {
 public:
   HeaderGuardCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context),
-        RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
-            "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
-    utils::parseFileExtensions(RawStringHeaderFileExtensions,
-                               HeaderFileExtensions,
-                               utils::defaultFileExtensionDelimiters());
+      : ClangTidyCheck(Name, Context) {
+    std::optional<StringRef> HeaderFileExtensionsOption =
+        Options.get("HeaderFileExtensions");
+    RawStringHeaderFileExtensions = HeaderFileExtensionsOption.value_or(
+        utils::defaultHeaderFileExtensions());
+    if (HeaderFileExtensionsOption) {
+      if (!utils::parseFileExtensions(
+              RawStringHeaderFileExtensions, HeaderFileExtensions,
+              utils::defaultFileExtensionDelimiters())) {
+        this->configurationDiag("Invalid header file extension: '%0'")
+            << RawStringHeaderFileExtensions;
+      }
+    } else
+      HeaderFileExtensions = Context->getHeaderFileExtensions();
   }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
@@ -58,7 +66,7 @@ class HeaderGuardCheck : public ClangTidyCheck {
 
 private:
   std::string RawStringHeaderFileExtensions;
-  utils::FileExtensionsSet HeaderFileExtensions;
+  FileExtensionsSet HeaderFileExtensions;
 };
 
 } // namespace clang::tidy::utils

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 48e7da0741f3e..69d89c3ee6c86 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -94,6 +94,10 @@ The improvements are...
 Improvements to clang-tidy
 --------------------------
 
+- New global configuration file options `HeaderFileExtensions` and
+  `ImplementationFileExtensions`, replacing the check-local options of the
+  same name.
+
 New checks
 ^^^^^^^^^^
 
@@ -130,6 +134,41 @@ New check aliases
 Changes in existing checks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`bugprone-dynamic-static-initializers
+  <clang-tidy/checks/bugprone/dynamic-static-initializers>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions` and `ImplementationFileExtensions`
+  in :doc:`bugprone-suspicious-include
+  <clang-tidy/checks/bugprone/suspicious-include>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`google-build-namespaces
+  <clang-tidy/checks/google/build-namespaces>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`google-global-names-in-headers
+  <clang-tidy/checks/google/global-names-in-headers>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`llvm-header-guard
+  <clang-tidy/checks/llvm/header-guard>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`misc-definitions-in-headers
+  <clang-tidy/checks/misc/definitions-in-headers>` check.
+  Global options of the same name should be used instead.
+
+- Deprecated check-local options `HeaderFileExtensions`
+  in :doc:`misc-unused-using-decls
+  <clang-tidy/checks/misc/misc-unused-using-decls>` check.
+  Global options of the same name should be used instead.
+
 Removed checks
 ^^^^^^^^^^^^^^
 

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-include.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-include.rst
index 3c05f39db12d5..7abcc13164a76 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-include.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-include.rst
@@ -19,6 +19,10 @@ Options
 -------
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    Default value: ``";h;hh;hpp;hxx"``
    A semicolon-separated list of filename extensions of header files (the
    filename extensions should not contain a "." prefix). For extension-less
@@ -27,6 +31,10 @@ Options
 
 .. option:: ImplementationFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `ImplementationFileExtensions`.
+
    Default value: ``"c;cc;cpp;cxx"``
    Likewise, a semicolon-separated list of filename extensions of
    implementation files.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/google/build-namespaces.rst b/clang-tools-extra/docs/clang-tidy/checks/google/build-namespaces.rst
index ca40f99eef6fc..59b5673dbf63e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/google/build-namespaces.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/google/build-namespaces.rst
@@ -17,6 +17,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A comma-separated list of filename extensions of header files (the filename
    extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
    For header files without an extension, use an empty string (if there are no

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/google/global-names-in-headers.rst b/clang-tools-extra/docs/clang-tidy/checks/google/global-names-in-headers.rst
index 32740eade0039..e71ac46cdb35c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/google/global-names-in-headers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/google/global-names-in-headers.rst
@@ -14,6 +14,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A comma-separated list of filename extensions of header files (the filename
    extensions should not contain "." prefix). Default is "h".
    For header files without an extension, use an empty string (if there are no

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst
index b27002ad606a8..725ef637f3f78 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst
@@ -10,6 +10,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A comma-separated list of filename extensions of header files (the filename
    extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
    For header files without an extension, use an empty string (if there are no

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl.rst b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl.rst
index d3b658eddce71..da60a1fcdb112 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl.rst
@@ -6,14 +6,3 @@ llvmlibc-inline-function-decl
 Checks that all implicit and explicit inline functions in header files are
 tagged with the ``LIBC_INLINE`` macro. See the `libc style guide
 <https://libc.llvm.org/code_style.html>`_ for more information about this macro.
-
-Options
--------
-
-.. option:: HeaderFileExtensions
-
-   A comma-separated list of filename extensions of header files (the filename
-   extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
-   For header files without an extension, use an empty string (if there are no
-   other desired extensions) or leave an empty element in the list. E.g.,
-   "h,hh,hpp,hxx," (note the trailing comma).

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/misc/definitions-in-headers.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/definitions-in-headers.rst
index a1fa09a25ca0c..dcded6a42a6d9 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/definitions-in-headers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/definitions-in-headers.rst
@@ -92,6 +92,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A comma-separated list of filename extensions of header files (the filename
    extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
    For header files without an extension, use an empty string (if there are no
@@ -100,5 +104,9 @@ Options
 
 .. option:: UseHeaderFileExtension
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. The check will unconditionally use the global option
+   `HeaderFileExtensions`.
+
    When `true`, the check will use the file extension to distinguish header
    files. Default is `true`.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/misc/unused-using-decls.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/unused-using-decls.rst
index 26dcf40c01b46..11b4450e37f51 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/unused-using-decls.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/unused-using-decls.rst
@@ -22,6 +22,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A semicolon-separated list of filename extensions of header files (the filename
    extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
    For extension-less header files, use an empty string or leave an

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-anonymous-namespace.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/use-anonymous-namespace.rst
index 6b256707366cb..b825e9562dafc 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/use-anonymous-namespace.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/use-anonymous-namespace.rst
@@ -38,6 +38,10 @@ Options
 
 .. option:: HeaderFileExtensions
 
+   Note: this option is deprecated, it will be removed in :program:`clang-tidy`
+   version 19. Please use the global configuration option
+   `HeaderFileExtensions`.
+
    A semicolon-separated list of filename extensions of header files (the filename
    extensions should not include "." prefix). Default is ";h;hh;hpp;hxx".
    For extension-less header files, using an empty string or leaving an

diff  --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst
index 1db828ab32d1c..899c3ea6ed540 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -263,7 +263,12 @@ An overview of all the command-line options:
     ExtraArgs                    - Same as '--extra-args'.
     ExtraArgsBefore              - Same as '--extra-args-before'.
     FormatStyle                  - Same as '--format-style'.
+    HeaderFileExtensions         - File extensions to consider to determine if a
+                                   given diagnostic is located in a header file.
     HeaderFilterRegex            - Same as '--header-filter-regex'.
+    ImplementationFileExtensions - File extensions to consider to determine if a
+                                   given diagnostic is located in an
+                                   implementation file.
     InheritParentConfig          - If this option is true in a config file, the
                                    configuration file in the parent directory
                                    (if any exists) will be taken and the current
@@ -283,6 +288,8 @@ An overview of all the command-line options:
       ---
       Checks:              '-*,some-check'
       WarningsAsErrors:    ''
+      HeaderFileExtensions:         ['', 'h','hh','hpp','hxx']
+      ImplementationFileExtensions: ['c','cc','cpp','cxx']
       HeaderFilterRegex:   ''
       FormatStyle:         none
       InheritParentConfig: true

diff  --git a/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp
index edd6a9ee362df..e127c23cc328a 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp
@@ -3,6 +3,8 @@
 
 // RUN: not clang-tidy -verify-config \
 // RUN: --checks='-*,bad*glob,llvm*,llvm-includeorder,my-made-up-check' --config='{Checks: "readability-else-after-ret", \
+// RUN: HeaderFileExtensions: ["h", "hh", "hpp"], \
+// RUN: ImplementationFileExtensions: ["c", "cc", "hpp"], \
 // RUN: CheckOptions: [{key: "IgnoreMacros", value: "true"}, \
 // RUN:                {key: "StriceMode", value: "true"}, \
 // RUN:                {key: modernize-lop-convert.UseCxx20ReverseRanges, value: true} \
@@ -12,6 +14,7 @@
 // CHECK-VERIFY-DAG: command-line option '-config': warning: unknown check 'readability-else-after-ret'; did you mean 'readability-else-after-return' [-verify-config]
 // CHECK-VERIFY-DAG: command-line option '-config': warning: unknown check option 'modernize-lop-convert.UseCxx20ReverseRanges'; did you mean 'modernize-loop-convert.UseCxx20ReverseRanges' [-verify-config]
 // CHECK-VERIFY-DAG: command-line option '-config': warning: unknown check option 'StriceMode'; did you mean 'StrictMode' [-verify-config]
+// CHECK-VERIFY-DAG: command-line option '-config': warning: HeaderFileExtension 'hpp' is the same as ImplementationFileExtension 'hpp' [-verify-config]
 // CHECK-VERIFY: command-line option '-checks': warning: check glob 'bad*glob' doesn't match any known check [-verify-config]
 // CHECK-VERIFY: command-line option '-checks': warning: unknown check 'llvm-includeorder'; did you mean 'llvm-include-order' [-verify-config]
 // CHECK-VERIFY: command-line option '-checks': warning: unknown check 'my-made-up-check' [-verify-config]

diff  --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index 4b8810237c28c..06f27d86dea22 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -76,13 +76,20 @@ TEST(ParseLineFilter, ValidFilter) {
 
 TEST(ParseConfiguration, ValidConfiguration) {
   llvm::ErrorOr<ClangTidyOptions> Options =
-      parseConfiguration(llvm::MemoryBufferRef("Checks: \"-*,misc-*\"\n"
-                                               "HeaderFilterRegex: \".*\"\n"
-                                               "AnalyzeTemporaryDtors: true\n"
-                                               "User: some.user",
-                                               "Options"));
+      parseConfiguration(llvm::MemoryBufferRef(
+          "Checks: \"-*,misc-*\"\n"
+          "HeaderFileExtensions: [\"\",\"h\",\"hh\",\"hpp\",\"hxx\"]\n"
+          "ImplementationFileExtensions: [\"c\",\"cc\",\"cpp\",\"cxx\"]\n"
+          "HeaderFilterRegex: \".*\"\n"
+          "AnalyzeTemporaryDtors: true\n"
+          "User: some.user",
+          "Options"));
   EXPECT_TRUE(!!Options);
   EXPECT_EQ("-*,misc-*", *Options->Checks);
+  EXPECT_EQ(std::vector<std::string>({"", "h", "hh", "hpp", "hxx"}),
+            *Options->HeaderFileExtensions);
+  EXPECT_EQ(std::vector<std::string>({"c", "cc", "cpp", "cxx"}),
+            *Options->ImplementationFileExtensions);
   EXPECT_EQ(".*", *Options->HeaderFilterRegex);
   EXPECT_EQ("some.user", *Options->User);
 }
@@ -105,6 +112,8 @@ TEST(ParseConfiguration, MergeConfigurations) {
   llvm::ErrorOr<ClangTidyOptions> Options1 =
       parseConfiguration(llvm::MemoryBufferRef(R"(
       Checks: "check1,check2"
+      HeaderFileExtensions: ["h","hh"]
+      ImplementationFileExtensions: ["c","cc"]
       HeaderFilterRegex: "filter1"
       AnalyzeTemporaryDtors: true
       User: user1
@@ -117,6 +126,8 @@ TEST(ParseConfiguration, MergeConfigurations) {
   llvm::ErrorOr<ClangTidyOptions> Options2 =
       parseConfiguration(llvm::MemoryBufferRef(R"(
       Checks: "check3,check4"
+      HeaderFileExtensions: ["hpp","hxx"]
+      ImplementationFileExtensions: ["cpp","cxx"]
       HeaderFilterRegex: "filter2"
       AnalyzeTemporaryDtors: false
       User: user2
@@ -128,6 +139,10 @@ TEST(ParseConfiguration, MergeConfigurations) {
   ASSERT_TRUE(!!Options2);
   ClangTidyOptions Options = Options1->merge(*Options2, 0);
   EXPECT_EQ("check1,check2,check3,check4", *Options.Checks);
+  EXPECT_EQ(std::vector<std::string>({"hpp", "hxx"}),
+            *Options.HeaderFileExtensions);
+  EXPECT_EQ(std::vector<std::string>({"cpp", "cxx"}),
+            *Options.ImplementationFileExtensions);
   EXPECT_EQ("filter2", *Options.HeaderFilterRegex);
   EXPECT_EQ("user2", *Options.User);
   ASSERT_TRUE(Options.ExtraArgs.has_value());


        


More information about the cfe-commits mailing list