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 "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" #include "StringConstructorCheck.h" @@ -119,6 +120,8 @@ "bugprone-parent-virtual-call"); CheckFactories.registerCheck( "bugprone-posix-return"); + CheckFactories.registerCheck( + "bugprone-reserved-identifier"); CheckFactories.registerCheck( "bugprone-sizeof-container"); 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 SizeofContainerCheck.cpp SizeofExpressionCheck.cpp StringConstructorCheck.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,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 +#include + +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 Whitelist; + +public: + ReservedIdentifierCheck(StringRef Name, ClangTidyContext *Context); + + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +protected: + 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,173 @@ +//===--- 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 { + +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 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 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 +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 +getFailureInfoImpl(const StringRef Name, const bool IsInGlobalNamespace, + const bool Invert, const ArrayRef Whitelist) { + assert(!Name.empty()); + if (std::find(Whitelist.begin(), Whitelist.end(), Name) != Whitelist.end()) + return None; + + 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())) { + 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 +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()), + Invert, Whitelist); +} + +Optional +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 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 @@ -94,6 +94,17 @@ Without the null terminator it can result in undefined behaviour when the string is read. +- New :doc:`bugprone-reserved-identifier + ` check. + + 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. + - New :doc:`cert-mem57-cpp ` check. 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,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. 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-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.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 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,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 + +#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;