logan-5 updated this revision to Diff 236754.
logan-5 marked an inline comment as done.
logan-5 added a comment.
Addressed some nits.
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/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.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-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,183 @@
+// 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;{{$}}
+
+} // 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;{{$}}
+
+} // 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;{{$}}
+
+} // 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;{{$}}
+
+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;
+} // namespace Ns
+namespace ns_ {
+class object_ {
+ int member_;
+};
+float global_;
+void function_() {}
+using alias_ = int;
+} // namespace ns_
+
+class object_ {
+ int member_;
+};
+float global_;
+void function_() {}
+using alias_ = int;
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/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/bugprone-reserved-identifier.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone-reserved-identifier.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - bugprone-reserved-identifier
+
+bugprone-reserved-identifier
+============================
+
+Checks for usages of identifiers reserved for use by the C++ implementation.
+The C++ standard reserves the following names for such use:
+* identifiers with a double underscore anywhere;
+* identifiers that begin with an underscore followed by an uppercase letter;
+* identifiers in the global namespace that begin with an underscore.
+
+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.
+
+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 @@
Without the null terminator it can result in undefined behaviour when the
string is read.
+- 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:`cert-mem57-cpp
<clang-tidy/checks/cert-mem57-cpp>` check.
Index: clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h
@@ -0,0 +1,55 @@
+//===--- 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 C++ implementation.
+/// The C++ standard reserves the following names for such use:
+/// * identifiers with a double underscore anywhere;
+/// * identifiers that begin with an underscore followed by an uppercase letter;
+/// * identifiers in the global namespace that begin with an underscore.
+///
+/// Violating the naming rules above results in undefined behavior.
+///
+/// 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,166 @@
+//===--- 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 {
+
+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(const StringRef str, const char c) {
+ std::string result;
+ std::unique_copy(
+ str.begin(), str.end(), std::back_inserter(result),
+ [c](const char a, const char b) { return a == c && b == c; });
+ return result;
+}
+
+static bool hasDoubleUnderscore(const StringRef Name) {
+ return Name.find("__") != StringRef::npos;
+}
+
+static Optional<std::string> getDoubleUnderscoreFixup(StringRef Name) {
+ if (hasDoubleUnderscore(Name)) {
+ Name.consume_front("__");
+ return collapseConsecutive(Name, '_');
+ }
+ return None;
+}
+
+static bool startsWithUnderscoreCapital(const StringRef Name) {
+ return Name.size() >= 2 && Name[0] == '_' && std::isupper(Name[1]);
+}
+
+static Optional<std::string> getUnderscoreCapitalFixup(const StringRef Name) {
+ if (startsWithUnderscoreCapital(Name))
+ return std::string(Name.drop_front(1));
+ return None;
+}
+
+static bool
+startsWithUnderscoreInGlobalNamespace(const StringRef Name,
+ const bool IsInGlobalNamespace) {
+ return IsInGlobalNamespace && Name.size() >= 1 && Name[0] == '_';
+}
+
+static Optional<std::string>
+getUnderscoreGlobalNamespaceFixup(const StringRef Name,
+ const 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(const StringRef Name, const bool IsInGlobalNamespace,
+ const bool Invert, const ArrayRef<std::string> Whitelist) {
+ assert(!Name.empty());
+ if (std::find(Whitelist.begin(), Whitelist.end(), Name) != Whitelist.end())
+ return None;
+
+ 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()))
+ appendFailure("du", *std::move(Fixup));
+ if (auto Fixup = getUnderscoreCapitalFixup(inProgressFixup()))
+ appendFailure("uc", *std::move(Fixup));
+ if (auto Fixup = getUnderscoreGlobalNamespaceFixup(inProgressFixup(),
+ IsInGlobalNamespace))
+ appendFailure("global-under", *std::move(Fixup));
+
+ if (Info)
+ return Info;
+ } else {
+ if (!(hasDoubleUnderscore(Name) || startsWithUnderscoreCapital(Name) ||
+ startsWithUnderscoreInGlobalNamespace(Name, IsInGlobalNamespace)))
+ return FailureInfo{"non-reserved", 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()),
+ Invert, Whitelist);
+}
+
+Optional<RenamerClangTidyCheck::FailureInfo>
+ReservedIdentifierCheck::GetMacroFailureInfo(const Token &MacroNameTok,
+ const SourceManager &) const {
+ return getFailureInfoImpl(MacroNameTok.getIdentifierInfo()->getName(), true,
+ Invert, Whitelist);
+}
+
+RenamerClangTidyCheck::DiagInfo
+ReservedIdentifierCheck::GetDiagInfo(const NamingCheckId &ID,
+ const NamingCheckFailure &Failure) const {
+ return DiagInfo{
+ Failure.Info.KindName == "non-reserved"
+ ? "declaration uses identifier '%0', which is not a reserved "
+ "identifier"
+ : Failure.Info.KindName == "global-under"
+ ? "declaration uses identifier '%0', which is reserved in "
+ "the global "
+ "namespace; this causes undefined behavior"
+ : "declaration uses reserved identifier '%0', which causes "
+ "undefined "
+ "behavior",
+ [&](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
SizeofContainerCheck.cpp
SizeofExpressionCheck.cpp
StringConstructorCheck.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 "SizeofContainerCheck.h"
#include "SizeofExpressionCheck.h"
#include "StringConstructorCheck.h"
@@ -119,6 +120,8 @@
"bugprone-parent-virtual-call");
CheckFactories.registerCheck<PosixReturnCheck>(
"bugprone-posix-return");
+ CheckFactories.registerCheck<ReservedIdentifierCheck>(
+ "bugprone-reserved-identifier");
CheckFactories.registerCheck<SizeofContainerCheck>(
"bugprone-sizeof-container");
CheckFactories.registerCheck<SizeofExpressionCheck>(
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits