diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp --- 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 @@ "bugprone-parent-virtual-call"); CheckFactories.registerCheck( "bugprone-posix-return"); + CheckFactories.registerCheck( + "bugprone-reserved-identifier"); CheckFactories.registerCheck( "bugprone-signed-char-misuse"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/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 diff --git a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.h new file mode 100644 --- /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 +#include + +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 AllowedIdentifiers; + +public: + ReservedIdentifierCheck(StringRef Name, ClangTidyContext *Context); + + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + llvm::Optional + GetDeclFailureInfo(const NamedDecl *Decl, + const SourceManager &SM) const override; + llvm::Optional + 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/bugprone/ReservedIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp new file mode 100644 --- /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 + +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 +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 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 +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 +getFailureInfoImpl(StringRef Name, bool IsInGlobalNamespace, + const LangOptions &LangOpts, bool Invert, + ArrayRef 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 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 +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(Decl->getDeclContext()), + getLangOpts(), Invert, AllowedIdentifiers); +} + +Optional +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/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp --- 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 @@ CheckFactories.registerCheck( "cert-dcl21-cpp"); CheckFactories.registerCheck("cert-dcl50-cpp"); + CheckFactories.registerCheck( + "cert-dcl51-cpp"); CheckFactories.registerCheck( "cert-dcl54-cpp"); CheckFactories.registerCheck( @@ -78,6 +81,8 @@ CheckFactories.registerCheck("cert-dcl03-c"); CheckFactories.registerCheck( "cert-dcl16-c"); + CheckFactories.registerCheck( + "cert-dcl37-c"); // ENV CheckFactories.registerCheck("cert-env33-c"); // FLP diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -70,10 +70,23 @@ New checks ^^^^^^^^^^ +- New :doc:`bugprone-reserved-identifier + ` check. + + Checks for usages of identifiers reserved for use by the implementation. New aliases ^^^^^^^^^^^ +- New alias :doc:`cert-dcl37-c + ` to + :doc:`bugprone-reserved-identifier + ` was added. + +- New alias :doc:`cert-dcl51-cpp + ` to + :doc:`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 --- /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 +`_ +as well as its C++ counterpart, `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 --- /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 `_ 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 --- /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 `_ 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 --- /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 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 +inline reference_wrapper<_Tp> +ref(_Tp &__t) noexcept { + return reference_wrapper<_Tp>(__t); +} + +template +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 --- /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 --- /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 --- /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 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 +inline reference_wrapper<_Tp> +ref(_Tp &__t) noexcept { + return reference_wrapper<_Tp>(__t); +} + +template +inline reference_wrapper<_Tp> +ref(reference_wrapper<_Tp> __t) noexcept { + return ref(__t.get()); +} + +template +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: declaration uses identifier 'Up', which is not a reserved identifier [bugprone-reserved-identifier] +// CHECK-FIXES: {{^}}template {{$}} +inline reference_wrapper +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(u); +} + +template +inline reference_wrapper<_Tp> +cref(reference_wrapper __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 --- /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 + +#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 +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier '_TemplateParam', which is a reserved identifier [bugprone-reserved-identifier] +// CHECK-FIXES: {{^}}template {{$}} +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 +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier '__templateParam', which is a reserved identifier [bugprone-reserved-identifier] +// CHECK-FIXES: {{^}}template {{$}} +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 +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: declaration uses identifier 'templateParam___t', which is a reserved identifier [bugprone-reserved-identifier] +// CHECK-FIXES: {{^}}template {{$}} +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 // 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 +struct S {}; +} // namespace Ns +namespace ns_ { +class object_ { + int member_; +}; +float global_; +void function_() {} +using alias_ = int; +template +struct S {}; +} // namespace ns_ + +class object_ { + int member_; +}; +float global_; +void function_() {} +using alias_ = int; +template +struct S_ {};