logan-5 updated this revision to Diff 236891. logan-5 marked 3 inline comments as done. logan-5 added a comment.
Added tests for template parameters. 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,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/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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits