logan-5 updated this revision to Diff 237433.
logan-5 marked 4 inline comments as done.
logan-5 added a comment.

Added a TODO comment for catching more reserved names. Added links in 
documentation to CERT guidelines covered by the check. Pulled strings into 
named constants and made that logic easier to read.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72378/new/

https://reviews.llvm.org/D72378

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  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

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp
===================================================================
--- /dev/null
+++ 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 reserved identifier '_MACRO', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define MACRO(m) int m = 0{{$}}
+
+namespace _Ns {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses reserved identifier '_Ns', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace Ns {{{$}}
+
+class _Object {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '_Object', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class Object {{{$}}
+  int _Member;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '_Member', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int Member;{{$}}
+};
+
+float _Global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '_Global', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float Global;{{$}}
+
+void _Function() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses reserved identifier '_Function', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void Function() {}{{$}}
+
+using _Alias = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '_Alias', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using Alias = int;{{$}}
+
+template <typename _TemplateParam>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses reserved identifier '_TemplateParam', which causes undefined behavior [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 reserved identifier '__macro', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define macro(m) int m = 0{{$}}
+
+namespace __ns {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses reserved identifier '__ns', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace ns {{{$}}
+class __object {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '__object', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class _object {{{$}}
+  int __member;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '__member', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int _member;{{$}}
+};
+
+float __global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '__global', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float _global;{{$}}
+
+void __function() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses reserved identifier '__function', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void _function() {}{{$}}
+
+using __alias = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier '__alias', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using _alias = int;{{$}}
+
+template <typename __templateParam>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses reserved identifier '__templateParam', which causes undefined behavior [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 reserved identifier 'macro___m', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}#define macro_m(m) int m = 0{{$}}
+
+namespace ns___n {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration uses reserved identifier 'ns___n', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}namespace ns_n {{{$}}
+class object___o {
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier 'object___o', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}class object_o {{{$}}
+  int member___m;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier 'member___m', which causes undefined behavior [bugprone-reserved-identifier]
+  // CHECK-FIXES: {{^}}  int member_m;{{$}}
+};
+
+float global___g;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier 'global___g', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}float global_g;{{$}}
+
+void function___f() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses reserved identifier 'function___f', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void function_f() {}{{$}}
+
+using alias___a = int;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration uses reserved identifier 'alias___a', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}using alias_a = int;{{$}}
+
+template <typename templateParam___t>
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses reserved identifier 'templateParam___t', which causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior [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; this causes undefined behavior; 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 reserved identifier 'SOME__MACRO', which causes undefined behavior; 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 reserved identifier '_TWO__PROBLEMS', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void TWO_PROBLEMS() {}{{$}}
+void _two__problems() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration uses reserved identifier '_two__problems', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void two_problems() {}{{$}}
+
+int __;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses reserved identifier '__', which causes undefined behavior; cannot be fixed automatically [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}int __;{{$}}
+
+int _________;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: declaration uses reserved identifier '_________', which causes undefined behavior; 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; this causes undefined behavior; 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_ {};
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-invert.cpp
===================================================================
--- /dev/null
+++ 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.Whitelist, 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
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier-c.c
===================================================================
--- /dev/null
+++ 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 reserved identifier '__foo', which causes undefined behavior [bugprone-reserved-identifier]
+// CHECK-FIXES: {{^}}void foo();{{$}}
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/user-header.h
===================================================================
--- /dev/null
+++ 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;
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-reserved-identifier/system/system-header.h
===================================================================
--- /dev/null
+++ 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
Index: clang-tools-extra/docs/clang-tidy/checks/cert-dcl51-cpp.rst
===================================================================
--- /dev/null
+++ 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.
Index: clang-tools-extra/docs/clang-tidy/checks/cert-dcl37-c.rst
===================================================================
--- /dev/null
+++ 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.
Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
@@ -0,0 +1,52 @@
+.. 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 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:: Whitelist
+
+   Semicolon-separated list of names that the check ignores. Default is an 
+   empty list.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -94,6 +94,11 @@
   Finds function calls where it is possible to cause a not null-terminated
   result.
 
+- New :doc:`bugprone-reserved-identifier
+  <clang-tidy/checks/bugprone-reserved-identifier>` check.
+
+  Checks for usages of identifiers reserved for use by the C++ implementation.
+
 - New :doc:`bugprone-signed-char-misuse
   <clang-tidy/checks/bugprone-signed-char-misuse>` check.
 
@@ -174,6 +179,16 @@
 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.
+
 - New alias :doc:`cert-pos44-c
   <clang-tidy/checks/cert-pos44-c>` to
   :doc:`bugprone-bad-signal-to-kill-thread
Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ 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 @@
     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 @@
     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
Index: clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
===================================================================
--- /dev/null
+++ 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> Whitelist;
+
+public:
+  ReservedIdentifierCheck(StringRef Name, ClangTidyContext *Context);
+
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+protected:
+  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
Index: clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp
@@ -0,0 +1,182 @@
+//===--- 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 NonReservedMessage[] =
+    "declaration uses identifier '%0', which is not a reserved "
+    "identifier";
+static const char GlobalUnderscoreMessage[] =
+    "declaration uses identifier '%0', which is reserved in the global "
+    "namespace; this causes undefined behavior";
+static const char DefaultMessage[] = "declaration uses reserved identifier "
+                                     "'%0', which causes undefined behavior";
+
+ReservedIdentifierCheck::ReservedIdentifierCheck(StringRef Name,
+                                                 ClangTidyContext *Context)
+    : RenamerClangTidyCheck(Name, Context),
+      Invert(Options.get("Invert", false)),
+      Whitelist(utils::options::parseStringList(Options.get("Whitelist", ""))) {
+}
+
+void ReservedIdentifierCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Invert", Invert);
+  Options.store(Opts, "Whitelist",
+                utils::options::serializeStringList(Whitelist));
+}
+
+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> Whitelist) {
+  assert(!Name.empty());
+  if (llvm::is_contained(Whitelist, 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, Whitelist);
+}
+
+Optional<RenamerClangTidyCheck::FailureInfo>
+ReservedIdentifierCheck::GetMacroFailureInfo(const Token &MacroNameTok,
+                                             const SourceManager &) const {
+  return getFailureInfoImpl(MacroNameTok.getIdentifierInfo()->getName(), true,
+                            getLangOpts(), Invert, Whitelist);
+}
+
+static std::string getDiagText(StringRef FixupTag) {
+  if (FixupTag == NonReservedTag)
+    return NonReservedMessage;
+  if (FixupTag == GlobalUnderscoreTag)
+    return GlobalUnderscoreMessage;
+  return DefaultMessage;
+}
+
+RenamerClangTidyCheck::DiagInfo
+ReservedIdentifierCheck::GetDiagInfo(const NamingCheckId &ID,
+                                     const NamingCheckFailure &Failure) const {
+  return DiagInfo{getDiagText(Failure.Info.KindName),
+                  [&](DiagnosticBuilder &diag) { diag << ID.second; }};
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -28,6 +28,7 @@
   NotNullTerminatedResultCheck.cpp
   ParentVirtualCallCheck.cpp
   PosixReturnCheck.cpp
+  ReservedIdentifierCheck.cpp
   SignedCharMisuseCheck.cpp
   SizeofContainerCheck.cpp
   SizeofExpressionCheck.cpp
Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ 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 @@
         "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>(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to