[clang-tools-extra] 42a0355 - Add `bugprone-reserved-identifier`

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 17 05:44:43 PST 2020


Author: Logan Smith
Date: 2020-01-17T08:44:21-05:00
New Revision: 42a0355816d3bc125d59cbd07052c8886e78ca86

URL: https://github.com/llvm/llvm-project/commit/42a0355816d3bc125d59cbd07052c8886e78ca86
DIFF: https://github.com/llvm/llvm-project/commit/42a0355816d3bc125d59cbd07052c8886e78ca86.diff

LOG: Add `bugprone-reserved-identifier`

This patch adds bugprone-reserved-identifier, which flags uses of __names _Like
::_this, which are reserved for the implementation. The check can optionally be
inverted, i.e. configured to flag any names that are _not_ reserved, which may
be useful for e.g. standard library implementors.

Added: 
    clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
    clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
    clang-tools-extra/docs/clang-tidy/checks/cert-dcl37-c.rst
    clang-tools-extra/docs/clang-tidy/checks/cert-dcl51-cpp.rst
    clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/system/system-header.h
    clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/user-header.h
    clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-c.c
    clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-invert.cpp
    clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp

Modified: 
    clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
    clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
    clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
    clang-tools-extra/docs/ReleaseNotes.rst

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 771cfc18a6ba..831f5f4e3b62 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -36,6 +36,7 @@
 #include "NotNullTerminatedResultCheck.h"
 #include "ParentVirtualCallCheck.h"
 #include "PosixReturnCheck.h"
+#include "ReservedIdentifierCheck.h"
 #include "SignedCharMisuseCheck.h"
 #include "SizeofContainerCheck.h"
 #include "SizeofExpressionCheck.h"
@@ -120,6 +121,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-parent-virtual-call");
     CheckFactories.registerCheck<PosixReturnCheck>(
         "bugprone-posix-return");
+    CheckFactories.registerCheck<ReservedIdentifierCheck>(
+        "bugprone-reserved-identifier");
     CheckFactories.registerCheck<SignedCharMisuseCheck>(
         "bugprone-signed-char-misuse");
     CheckFactories.registerCheck<SizeofContainerCheck>(

diff  --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 2cb28f4e8f19..efb97a5318bb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -28,6 +28,7 @@ add_clang_library(clangTidyBugproneModule
   NotNullTerminatedResultCheck.cpp
   ParentVirtualCallCheck.cpp
   PosixReturnCheck.cpp
+  ReservedIdentifierCheck.cpp
   SignedCharMisuseCheck.cpp
   SizeofContainerCheck.cpp
   SizeofExpressionCheck.cpp

diff  --git a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
new file mode 100644
index 000000000000..699f46dd2722
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
@@ -0,0 +1,178 @@
+//===--- ReservedIdentifierCheck.cpp - clang-tidy -------------------------===//
+//
+// 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 "ReservedIdentifierCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+static const char DoubleUnderscoreTag[] = "du";
+static const char UnderscoreCapitalTag[] = "uc";
+static const char GlobalUnderscoreTag[] = "global-under";
+static const char NonReservedTag[] = "non-reserved";
+
+static const char Message[] =
+    "declaration uses identifier '%0', which is %select{a reserved "
+    "identifier|not a reserved identifier|reserved in the global namespace}1";
+
+static int getMessageSelectIndex(StringRef Tag) {
+  if (Tag == NonReservedTag)
+    return 1;
+  if (Tag == GlobalUnderscoreTag)
+    return 2;
+  return 0;
+}
+
+ReservedIdentifierCheck::ReservedIdentifierCheck(StringRef Name,
+                                                 ClangTidyContext *Context)
+    : RenamerClangTidyCheck(Name, Context),
+      Invert(Options.get("Invert", false)),
+      AllowedIdentifiers(utils::options::parseStringList(
+          Options.get("AllowedIdentifiers", ""))) {}
+
+void ReservedIdentifierCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Invert", Invert);
+  Options.store(Opts, "AllowedIdentifiers",
+                utils::options::serializeStringList(AllowedIdentifiers));
+}
+
+static std::string collapseConsecutive(StringRef Str, char C) {
+  std::string Result;
+  std::unique_copy(Str.begin(), Str.end(), std::back_inserter(Result),
+                   [C](char A, char B) { return A == C && B == C; });
+  return Result;
+}
+
+static bool hasReservedDoubleUnderscore(StringRef Name,
+                                        const LangOptions &LangOpts) {
+  if (LangOpts.CPlusPlus)
+    return Name.find("__") != StringRef::npos;
+  return Name.startswith("__");
+}
+
+static Optional<std::string>
+getDoubleUnderscoreFixup(StringRef Name, const LangOptions &LangOpts) {
+  if (hasReservedDoubleUnderscore(Name, LangOpts))
+    return collapseConsecutive(Name, '_');
+  return None;
+}
+
+static bool startsWithUnderscoreCapital(StringRef Name) {
+  return Name.size() >= 2 && Name[0] == '_' && std::isupper(Name[1]);
+}
+
+static Optional<std::string> getUnderscoreCapitalFixup(StringRef Name) {
+  if (startsWithUnderscoreCapital(Name))
+    return std::string(Name.drop_front(1));
+  return None;
+}
+
+static bool startsWithUnderscoreInGlobalNamespace(StringRef Name,
+                                                  bool IsInGlobalNamespace) {
+  return IsInGlobalNamespace && Name.size() >= 1 && Name[0] == '_';
+}
+
+static Optional<std::string>
+getUnderscoreGlobalNamespaceFixup(StringRef Name, bool IsInGlobalNamespace) {
+  if (startsWithUnderscoreInGlobalNamespace(Name, IsInGlobalNamespace))
+    return std::string(Name.drop_front(1));
+  return None;
+}
+
+static std::string getNonReservedFixup(std::string Name) {
+  assert(!Name.empty());
+  if (Name[0] == '_' || std::isupper(Name[0]))
+    Name.insert(Name.begin(), '_');
+  else
+    Name.insert(Name.begin(), 2, '_');
+  return Name;
+}
+
+static Optional<RenamerClangTidyCheck::FailureInfo>
+getFailureInfoImpl(StringRef Name, bool IsInGlobalNamespace,
+                   const LangOptions &LangOpts, bool Invert,
+                   ArrayRef<std::string> AllowedIdentifiers) {
+  assert(!Name.empty());
+  if (llvm::is_contained(AllowedIdentifiers, Name))
+    return None;
+
+  // TODO: Check for names identical to language keywords, and other names
+  // specifically reserved by language standards, e.g. C++ 'zombie names' and C
+  // future library directions
+
+  using FailureInfo = RenamerClangTidyCheck::FailureInfo;
+  if (!Invert) {
+    Optional<FailureInfo> Info;
+    auto AppendFailure = [&](StringRef Kind, std::string &&Fixup) {
+      if (!Info) {
+        Info = FailureInfo{Kind, std::move(Fixup)};
+      } else {
+        Info->KindName += Kind;
+        Info->Fixup = std::move(Fixup);
+      }
+    };
+    auto InProgressFixup = [&] {
+      return Info
+          .map([](const FailureInfo &Info) { return StringRef(Info.Fixup); })
+          .getValueOr(Name);
+    };
+    if (auto Fixup = getDoubleUnderscoreFixup(InProgressFixup(), LangOpts))
+      AppendFailure(DoubleUnderscoreTag, *std::move(Fixup));
+    if (auto Fixup = getUnderscoreCapitalFixup(InProgressFixup()))
+      AppendFailure(UnderscoreCapitalTag, *std::move(Fixup));
+    if (auto Fixup = getUnderscoreGlobalNamespaceFixup(InProgressFixup(),
+                                                       IsInGlobalNamespace))
+      AppendFailure(GlobalUnderscoreTag, *std::move(Fixup));
+
+    return Info;
+  }
+  if (!(hasReservedDoubleUnderscore(Name, LangOpts) ||
+        startsWithUnderscoreCapital(Name) ||
+        startsWithUnderscoreInGlobalNamespace(Name, IsInGlobalNamespace)))
+    return FailureInfo{NonReservedTag, getNonReservedFixup(Name)};
+  return None;
+}
+
+Optional<RenamerClangTidyCheck::FailureInfo>
+ReservedIdentifierCheck::GetDeclFailureInfo(const NamedDecl *Decl,
+                                            const SourceManager &) const {
+  assert(Decl && Decl->getIdentifier() && !Decl->getName().empty() &&
+         !Decl->isImplicit() &&
+         "Decl must be an explicit identifier with a name.");
+  return getFailureInfoImpl(Decl->getName(),
+                            isa<TranslationUnitDecl>(Decl->getDeclContext()),
+                            getLangOpts(), Invert, AllowedIdentifiers);
+}
+
+Optional<RenamerClangTidyCheck::FailureInfo>
+ReservedIdentifierCheck::GetMacroFailureInfo(const Token &MacroNameTok,
+                                             const SourceManager &) const {
+  return getFailureInfoImpl(MacroNameTok.getIdentifierInfo()->getName(), true,
+                            getLangOpts(), Invert, AllowedIdentifiers);
+}
+
+RenamerClangTidyCheck::DiagInfo
+ReservedIdentifierCheck::GetDiagInfo(const NamingCheckId &ID,
+                                     const NamingCheckFailure &Failure) const {
+  return DiagInfo{Message, [&](DiagnosticBuilder &diag) {
+                    diag << ID.second
+                         << getMessageSelectIndex(Failure.Info.KindName);
+                  }};
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang

diff  --git a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
new file mode 100644
index 000000000000..fa570902f778
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
@@ -0,0 +1,57 @@
+//===--- ReservedIdentifierCheck.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_BUGPRONE_RESERVEDIDENTIFIERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_RESERVEDIDENTIFIERCHECK_H
+
+#include "../utils/RenamerClangTidyCheck.h"
+#include "llvm/ADT/Optional.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks for usages of identifiers reserved for use by the implementation.
+///
+/// The C and C++ standards both reserve the following names for such use:
+/// * identifiers that begin with an underscore followed by an uppercase letter;
+/// * identifiers in the global namespace that begin with an underscore.
+///
+/// The C standard additionally reserves names beginning with a double
+/// underscore, while the C++ standard strengthens this to reserve names with a
+/// double underscore occurring anywhere.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-reserved-identifier.html
+class ReservedIdentifierCheck final : public RenamerClangTidyCheck {
+  const bool Invert;
+  const std::vector<std::string> AllowedIdentifiers;
+
+public:
+  ReservedIdentifierCheck(StringRef Name, ClangTidyContext *Context);
+
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  llvm::Optional<FailureInfo>
+  GetDeclFailureInfo(const NamedDecl *Decl,
+                     const SourceManager &SM) const override;
+  llvm::Optional<FailureInfo>
+  GetMacroFailureInfo(const Token &MacroNameTok,
+                      const SourceManager &SM) const override;
+  DiagInfo GetDiagInfo(const NamingCheckId &ID,
+                       const NamingCheckFailure &Failure) const override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_RESERVEDIDENTIFIERCHECK_H

diff  --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index 26f0bdab5345..ab1fbbe94402 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -9,8 +9,9 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
-#include "../bugprone/UnhandledSelfAssignmentCheck.h"
 #include "../bugprone/BadSignalToKillThreadCheck.h"
+#include "../bugprone/ReservedIdentifierCheck.h"
+#include "../bugprone/UnhandledSelfAssignmentCheck.h"
 #include "../google/UnnamedNamespaceInHeaderCheck.h"
 #include "../misc/NewDeleteOverloadsCheck.h"
 #include "../misc/NonCopyableObjects.h"
@@ -44,6 +45,8 @@ class CERTModule : public ClangTidyModule {
     CheckFactories.registerCheck<PostfixOperatorCheck>(
         "cert-dcl21-cpp");
     CheckFactories.registerCheck<VariadicFunctionDefCheck>("cert-dcl50-cpp");
+    CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>(
+        "cert-dcl51-cpp");
     CheckFactories.registerCheck<misc::NewDeleteOverloadsCheck>(
         "cert-dcl54-cpp");
     CheckFactories.registerCheck<DontModifyStdNamespaceCheck>(
@@ -78,6 +81,8 @@ class CERTModule : public ClangTidyModule {
     CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
     CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
         "cert-dcl16-c");
+    CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>(
+        "cert-dcl37-c");
     // ENV
     CheckFactories.registerCheck<CommandProcessorCheck>("cert-env33-c");
     // FLP

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 74829f0618da..49f0afc73c78 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -70,10 +70,23 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-reserved-identifier
+  <clang-tidy/checks/bugprone-reserved-identifier>` check.
+
+  Checks for usages of identifiers reserved for use by the implementation.
 
 New aliases
 ^^^^^^^^^^^
 
+- New alias :doc:`cert-dcl37-c
+  <clang-tidy/checks/cert-dcl37-c>` to
+  :doc:`bugprone-reserved-identifier
+  <clang-tidy/checks/bugprone-reserved-identifier>` was added.
+
+- New alias :doc:`cert-dcl51-cpp
+  <clang-tidy/checks/cert-dcl51-cpp>` to
+  :doc:`bugprone-reserved-identifier
+  <clang-tidy/checks/bugprone-reserved-identifier>` was added.
 
 Changes in existing checks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
new file mode 100644
index 000000000000..203b1f4df9c1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
@@ -0,0 +1,56 @@
+.. title:: clang-tidy - bugprone-reserved-identifier
+
+bugprone-reserved-identifier
+============================
+
+`cert-dcl37-c` and `cert-dcl51-cpp` redirect here as an alias for this check.
+
+Checks for usages of identifiers reserved for use by the implementation. 
+
+The C and C++ standards both reserve the following names for such use:
+* identifiers that begin with an underscore followed by an uppercase letter;
+* identifiers in the global namespace that begin with an underscore.
+
+The C standard additionally reserves names beginning with a double underscore,
+while the C++ standard strengthens this to reserve names with a double 
+underscore occurring anywhere.
+
+Violating the naming rules above results in undefined behavior.
+
+.. code-block:: c++
+
+  namespace NS { 
+    void __f(); // name is not allowed in user code
+    using _Int = int; // same with this
+    #define cool__macro // also this
+  }
+  int _g(); // disallowed in global namespace only
+
+The check can also be inverted, i.e. it can be configured to flag any 
+identifier that is _not_ a reserved identifier. This mode is for use by e.g. 
+standard library implementors, to ensure they don't infringe on the user 
+namespace.
+
+This check does not (yet) check for other reserved names, e.g. macro names 
+identical to language keywords, and names specifically reserved by language 
+standards, e.g. C++ 'zombie names' and C future library directions.
+
+This check corresponds to CERT C Coding Standard rule `DCL37-C. Do not declare 
+or define a reserved identifier
+<https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier>`_
+as well as its C++ counterpart, `DCL51-CPP. Do not declare or define a reserved
+identifier 
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL51-CPP.+Do+not+declare+or+define+a+reserved+identifier>`_.
+
+Options
+-------
+
+.. option:: Invert
+
+   If non-zero, inverts the check, i.e. flags names that are not reserved. 
+   Default is `0`.
+
+.. option:: AllowedIdentifiers
+
+   Semicolon-separated list of names that the check ignores. Default is an 
+   empty list.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/cert-dcl37-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl37-c.rst
new file mode 100644
index 000000000000..f99330304c49
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl37-c.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-dcl37-c
+.. meta::
+   :http-equiv=refresh: 5;URL=bugprone-reserved-identifier.html
+
+cert-dcl37-c
+============
+
+The cert-dcl37-c check is an alias, please see
+`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more 
+information.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/cert-dcl51-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl51-cpp.rst
new file mode 100644
index 000000000000..b3a4870df5f1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl51-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-dcl51-cpp
+.. meta::
+   :http-equiv=refresh: 5;URL=bugprone-reserved-identifier.html
+
+cert-dcl51-cpp
+==============
+
+The cert-dcl51-cpp check is an alias, please see
+`bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_ for more 
+information.

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/system/system-header.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/system/system-header.h
new file mode 100644
index 000000000000..9697dd17c252
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/system/system-header.h
@@ -0,0 +1,33 @@
+namespace std {
+
+void __f() {}
+
+template <class _Tp>
+class reference_wrapper {
+public:
+  typedef _Tp type;
+
+private:
+  type *__f_;
+
+public:
+  reference_wrapper(type &__f)
+      : __f_(&__f) {}
+  // access
+  operator type &() const { return *__f_; }
+  type &get() const { return *__f_; }
+};
+
+template <class _Tp>
+inline reference_wrapper<_Tp>
+ref(_Tp &__t) noexcept {
+  return reference_wrapper<_Tp>(__t);
+}
+
+template <class _Tp>
+inline reference_wrapper<_Tp>
+ref(reference_wrapper<_Tp> __t) noexcept {
+  return ref(__t.get());
+}
+
+} // namespace std

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/user-header.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/user-header.h
new file mode 100644
index 000000000000..ec1a7ceb0ba7
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/user-header.h
@@ -0,0 +1,58 @@
+#define _HEADER_MACRO(m) int m = 0
+
+namespace _Header_Ns {
+class _Header_Object {
+  int _Header_Member;
+};
+
+float _Header_Global;
+
+void _Header_Function() {}
+
+using _Header_Alias = int;
+} // namespace _Header_Ns
+
+//
+
+#define __header_macro(m) int m = 0
+
+namespace __header_ns {
+class __header_object {
+  int __header_member;
+};
+
+float __header_global;
+
+void __header_function() {}
+
+using __header_alias = int;
+} // namespace __header_ns
+
+//
+
+#define header_macro__m(m) int m = 0
+
+namespace header_ns__n {
+class header_object__o {
+  int header_member__m;
+};
+
+float header_global__g;
+
+void header_function__f() {}
+
+using header_alias__a = int;
+} // namespace header_ns__n
+
+//
+
+#define _header_macro(m) int m = 0
+
+namespace _header_ns {}
+class _header_object {};
+
+float _header_global;
+
+void _header_function() {}
+
+using _header_alias = int;

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-c.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-c.c
new file mode 100644
index 000000000000..53c1bdc34dcd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-c.c
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t
+
+// in C, double underscores are fine except at the beginning
+
+void foo__();
+void f__o__o();
+void f_________oo();
+void __foo();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '__foo', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void foo();{{$}}

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-invert.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-invert.cpp
new file mode 100644
index 000000000000..f8a2662bebf1
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-invert.cpp
@@ -0,0 +1,70 @@
+// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t -- \
+// RUN:   -config='{CheckOptions: [ \
+// RUN:     {key: bugprone-reserved-identifier.Invert, value: 1}, \
+// RUN:     {key: bugprone-reserved-identifier.AllowedIdentifiers, value: std;reference_wrapper;ref;cref;type;get}, \
+// RUN:   ]}' -- \
+// RUN:   -I%S/Inputs/bugprone-reserved-identifier \
+// RUN:   -isystem %S/Inputs/bugprone-reserved-identifier/system
+
+namespace std {
+
+void __f() {}
+
+void f();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier 'f', which is not a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void __f();{{$}}
+struct helper {};
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration uses identifier 'helper', which is not a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}struct __helper {};{{$}}
+struct Helper {};
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration uses identifier 'Helper', which is not a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}struct _Helper {};{{$}}
+struct _helper2 {};
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration uses identifier '_helper2', which is not a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}struct __helper2 {};{{$}}
+
+template <class _Tp>
+class reference_wrapper {
+public:
+  typedef _Tp type;
+
+private:
+  type *__f_;
+
+public:
+  reference_wrapper(type &__f)
+      : __f_(&__f) {}
+  // access
+  operator type &() const { return *__f_; }
+  type &get() const { return *__f_; }
+};
+
+template <class _Tp>
+inline reference_wrapper<_Tp>
+ref(_Tp &__t) noexcept {
+  return reference_wrapper<_Tp>(__t);
+}
+
+template <class _Tp>
+inline reference_wrapper<_Tp>
+ref(reference_wrapper<_Tp> __t) noexcept {
+  return ref(__t.get());
+}
+
+template <class Up>
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: declaration uses identifier 'Up', which is not a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}template <class _Up>{{$}}
+inline reference_wrapper<const Up>
+cref(const Up &u) noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: declaration uses identifier 'u', which is not a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}cref(const Up &__u) noexcept {{{$}}
+  return reference_wrapper<const Up>(u);
+}
+
+template <class _Tp>
+inline reference_wrapper<_Tp>
+cref(reference_wrapper<const _Tp> __t) noexcept {
+  return cref(__t.get());
+}
+
+} // namespace std

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp
new file mode 100644
index 000000000000..555c673a3f43
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp
@@ -0,0 +1,206 @@
+// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t -- -- \
+// RUN:   -I%S/Inputs/bugprone-reserved-identifier \
+// RUN:   -isystem %S/Inputs/bugprone-reserved-identifier/system
+
+// no warnings expected without -header-filter=
+#include "user-header.h"
+#include <system-header.h>
+
+#define _MACRO(m) int m = 0
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration uses identifier '_MACRO', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define MACRO(m) int m = 0{{$}}
+
+namespace _Ns {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses identifier '_Ns', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace Ns {{{$}}
+
+class _Object {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_Object', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class Object {{{$}}
+  int _Member;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_Member', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int Member;{{$}}
+};
+
+float _Global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_Global', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float Global;{{$}}
+
+void _Function() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '_Function', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void Function() {}{{$}}
+
+using _Alias = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_Alias', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using Alias = int;{{$}}
+
+template <typename _TemplateParam>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier '_TemplateParam', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}template <typename TemplateParam>{{$}}
+struct S {};
+
+} // namespace _Ns
+
+//
+
+#define __macro(m) int m = 0
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration uses identifier '__macro', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define macro(m) int m = 0{{$}}
+
+namespace __ns {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses identifier '__ns', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace ns {{{$}}
+class __object {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '__object', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class _object {{{$}}
+  int __member;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '__member', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int _member;{{$}}
+};
+
+float __global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '__global', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float _global;{{$}}
+
+void __function() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '__function', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void _function() {}{{$}}
+
+using __alias = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '__alias', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using _alias = int;{{$}}
+
+template <typename __templateParam>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier '__templateParam', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}template <typename _templateParam>{{$}}
+struct S {};
+
+} // namespace __ns
+
+//
+
+#define macro___m(m) int m = 0
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration uses identifier 'macro___m', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define macro_m(m) int m = 0{{$}}
+
+namespace ns___n {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses identifier 'ns___n', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace ns_n {{{$}}
+class object___o {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier 'object___o', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class object_o {{{$}}
+  int member___m;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier 'member___m', which is a reserved identifier [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int member_m;{{$}}
+};
+
+float global___g;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier 'global___g', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float global_g;{{$}}
+
+void function___f() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier 'function___f', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void function_f() {}{{$}}
+
+using alias___a = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier 'alias___a', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using alias_a = int;{{$}}
+
+template <typename templateParam___t>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier 'templateParam___t', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}template <typename templateParam_t>{{$}}
+struct S {};
+
+} // namespace ns___n
+
+//
+
+#define _macro(m) int m = 0
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: declaration uses identifier '_macro', which is reserved in the global namespace [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define macro(m) int m = 0{{$}}
+
+namespace _ns {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses identifier '_ns', which is reserved in the global namespace [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace ns {{{$}}
+int _i;
+// no warning
+} // namespace _ns
+class _object {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_object', which is reserved in the global namespace [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class object {{{$}}
+  int _member;
+  // no warning
+};
+float _global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_global', which is reserved in the global namespace [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float global;{{$}}
+void _function() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '_function', which is reserved in the global namespace [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void function() {}{{$}}
+using _alias = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses identifier '_alias', which is reserved in the global namespace [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using alias = int;{{$}}
+template <typename _templateParam> // no warning, template params are not in the global namespace
+struct S {};
+
+void _float() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '_float', which is reserved in the global namespace; cannot be fixed because 'float' would conflict with a keyword [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void _float() {}{{$}}
+
+#define SOME_MACRO
+int SOME__MACRO;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses identifier 'SOME__MACRO', which is a reserved identifier; cannot be fixed because 'SOME_MACRO' would conflict with a macro definition [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}int SOME__MACRO;{{$}}
+
+void _TWO__PROBLEMS() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '_TWO__PROBLEMS', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void TWO_PROBLEMS() {}{{$}}
+void _two__problems() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses identifier '_two__problems', which is a reserved identifier [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void two_problems() {}{{$}}
+
+int __;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses identifier '__', which is a reserved identifier; cannot be fixed automatically [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}int __;{{$}}
+
+int _________;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses identifier '_________', which is a reserved identifier; cannot be fixed automatically [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}int _________;{{$}}
+
+int _;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses identifier '_', which is reserved in the global namespace; cannot be fixed automatically [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}int _;{{$}}
+
+// these should pass
+#define MACRO(m) int m = 0
+
+namespace Ns {
+class Object {
+  int Member;
+};
+float Global;
+
+void Function() {}
+using Alias = int;
+template <typename TemplateParam>
+struct S {};
+} // namespace Ns
+namespace ns_ {
+class object_ {
+  int member_;
+};
+float global_;
+void function_() {}
+using alias_ = int;
+template <typename templateParam_>
+struct S {};
+} // namespace ns_
+
+class object_ {
+  int member_;
+};
+float global_;
+void function_() {}
+using alias_ = int;
+template <typename templateParam_>
+struct S_ {};


        


More information about the cfe-commits mailing list