https://github.com/JungPhilipp updated https://github.com/llvm/llvm-project/pull/138282
>From 0567bc8e1168bb409ee759dd5505861a644a8ead Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 2 May 2025 15:22:40 +0200 Subject: [PATCH 1/6] Add check 'modernize-use-enum-class' Warn on non-class enum definitions as suggested by the Core Guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class --- .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 2 + .../modernize/UseEnumClassCheck.cpp | 34 +++++++++++ .../clang-tidy/modernize/UseEnumClassCheck.h | 34 +++++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../docs/clang-tidy/checks/list.rst | 1 + .../checks/modernize/use-enum-class.rst | 26 +++++++++ .../checkers/modernize/use-enum-class.cpp | 58 +++++++++++++++++++ 8 files changed, 161 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index bab1167fb15ff..ea19586b1f08c 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -34,6 +34,7 @@ add_clang_library(clangTidyModernizeModule STATIC UseDefaultMemberInitCheck.cpp UseDesignatedInitializersCheck.cpp UseEmplaceCheck.cpp + UseEnumClassCheck.cpp UseEqualsDefaultCheck.cpp UseEqualsDeleteCheck.cpp UseIntegerSignComparisonCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index fc46c72982fdc..1f77c9a94d25a 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -35,6 +35,7 @@ #include "UseDefaultMemberInitCheck.h" #include "UseDesignatedInitializersCheck.h" #include "UseEmplaceCheck.h" +#include "UseEnumClassCheck.h" #include "UseEqualsDefaultCheck.h" #include "UseEqualsDeleteCheck.h" #include "UseIntegerSignComparisonCheck.h" @@ -110,6 +111,7 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck<UseDefaultMemberInitCheck>( "modernize-use-default-member-init"); CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace"); + CheckFactories.registerCheck<UseEnumClassCheck>("modernize-use-enum-class"); CheckFactories.registerCheck<UseEqualsDefaultCheck>("modernize-use-equals-default"); CheckFactories.registerCheck<UseEqualsDeleteCheck>( "modernize-use-equals-delete"); diff --git a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp new file mode 100644 index 0000000000000..9fc3614aaf498 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp @@ -0,0 +1,34 @@ +//===--- UseEnumClassCheck.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 "UseEnumClassCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +void UseEnumClassCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + traverse(TK_AsIs, + enumDecl(unless(isScoped()), unless(hasParent(recordDecl())))) + .bind("unscoped_enum"), + this); +} + +void UseEnumClassCheck::check(const MatchFinder::MatchResult &Result) { + const auto *UnscopedEnum = Result.Nodes.getNodeAs<EnumDecl>("unscoped_enum"); + + diag(UnscopedEnum->getLocation(), + "enum %0 is unscoped, use enum class instead") + << UnscopedEnum; + diag(UnscopedEnum->getLocation(), "insert 'class'", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(UnscopedEnum->getLocation(), "class "); +} + +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h new file mode 100644 index 0000000000000..9cfb2024b9cfd --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h @@ -0,0 +1,34 @@ +//===--- UseEnumClassCheck.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_MODERNIZE_USEENUMCLASSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEENUMCLASSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::modernize { + +/// Check for unscoped enums that are not contained in classes/structs. +/// Suggest to use scoped enums (enum class) instead. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-enum-class.html +class UseEnumClassCheck : public ClangTidyCheck { +public: + UseEnumClassCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_ENUM_CLASS_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 579fca54924d5..b34a4d3d31b9c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,6 +136,11 @@ New checks Finds potentially erroneous calls to ``reset`` method on smart pointers when the pointee type also has a ``reset`` method. +- New :doc:`modernize-use-enum-class + <clang-tidy/checks/modernize/use-enum-class>` check. + + Finds plain non-class enum definitions that could use ``enum class``. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 18f1467285fab..c358419efd7b9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -302,6 +302,7 @@ Clang-Tidy Checks :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes" :doc:`modernize-use-designated-initializers <modernize/use-designated-initializers>`, "Yes" :doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes" + :doc:`modernize-use-enum-class <modernize/use-enum-class>`, "Yes" :doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes" :doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes" :doc:`modernize-use-integer-sign-comparison <modernize/use-integer-sign-comparison>`, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst new file mode 100644 index 0000000000000..3adb6e204ad92 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst @@ -0,0 +1,26 @@ +.. title:: clang-tidy - modernize-use-enum-class + +modernize-use-enum-class +============================= + +Scoped enums (enum class) should be preferred over unscoped enums: +https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class + +Unscoped enums in classes are not reported since it is a well +established pattern to limit the scope of plain enums. + +Example: + +.. code-block:: c++ + + enum E {}; // use "enum class E {};" instead + enum class E {}; // OK + + struct S { + enum E {}; // OK, scope already limited + }; + + namespace N { + enum E {}; // use "enum class E {};" instead + // report since it is hard to detect how large the surrounding namespace is + } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp new file mode 100644 index 0000000000000..9712fbc0aac4a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp @@ -0,0 +1,58 @@ +// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-enum-class %t + +enum E {}; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + +enum class EC {}; + +struct S { + enum E {}; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // Ignore unscoped enums in recordDecl + enum class EC {}; +}; + +class C { + enum E {}; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // Ignore unscoped enums in recordDecl + enum class EC {}; +}; + +template<class T> +class TC { + enum E {}; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // Ignore unscoped enums in recordDecl + enum class EC {}; +}; + +union U { + enum E {}; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // Ignore unscoped enums in recordDecl + enum class EC {}; +}; + +namespace { +enum E {}; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] +enum class EC {}; +} // namespace + +namespace N { +enum E {}; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] +enum class EC {}; +} // namespace N + +template<enum ::EC> +static void foo(); + +using enum S::E; +using enum S::EC; + +enum ForwardE : int; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use enum class instead [modernize-use-enum-class] + +enum class ForwardEC : int; >From a4afe4aed98c7a38e4e7b0b0592bb2ff6b703f00 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 9 May 2025 09:56:01 +0200 Subject: [PATCH 2/6] Move check to cppcoreguidelines- section --- .../cppcoreguidelines/CMakeLists.txt | 1 + .../CppCoreGuidelinesTidyModule.cpp | 3 +++ .../UseEnumClassCheck.cpp | 4 ++-- .../UseEnumClassCheck.h | 12 ++++++------ .../clang-tidy/modernize/CMakeLists.txt | 1 - .../modernize/ModernizeTidyModule.cpp | 2 -- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- .../use-enum-class.rst | 4 ++-- .../docs/clang-tidy/checks/list.rst | 2 +- .../use-enum-class.cpp | 18 +++++++++--------- 10 files changed, 26 insertions(+), 25 deletions(-) rename clang-tools-extra/clang-tidy/{modernize => cppcoreguidelines}/UseEnumClassCheck.cpp (92%) rename clang-tools-extra/clang-tidy/{modernize => cppcoreguidelines}/UseEnumClassCheck.h (70%) rename clang-tools-extra/docs/clang-tidy/checks/{modernize => cppcoreguidelines}/use-enum-class.rst (87%) rename clang-tools-extra/test/clang-tidy/checkers/{modernize => cppcoreguidelines}/use-enum-class.cpp (66%) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt index b023f76a25432..2fb4d7f1d7349 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -33,6 +33,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule STATIC RvalueReferenceParamNotMovedCheck.cpp SlicingCheck.cpp SpecialMemberFunctionsCheck.cpp + UseEnumClassCheck.cpp VirtualClassDestructorCheck.cpp LINK_LIBS diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index 6adef04264347..409ebbf19349e 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -48,6 +48,7 @@ #include "RvalueReferenceParamNotMovedCheck.h" #include "SlicingCheck.h" #include "SpecialMemberFunctionsCheck.h" +#include "UseEnumClassCheck.h" #include "VirtualClassDestructorCheck.h" namespace clang::tidy { @@ -59,6 +60,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule { void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck<AvoidCapturingLambdaCoroutinesCheck>( "cppcoreguidelines-avoid-capturing-lambda-coroutines"); + CheckFactories.registerCheck<UseEnumClassCheck>( + "cppcoreguidelines-use-enum-class"); CheckFactories.registerCheck<modernize::AvoidCArraysCheck>( "cppcoreguidelines-avoid-c-arrays"); CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>( diff --git a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp similarity index 92% rename from clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp rename to clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp index 9fc3614aaf498..c64d0d5046a18 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp @@ -11,7 +11,7 @@ using namespace clang::ast_matchers; -namespace clang::tidy::modernize { +namespace clang::tidy::cppcoreguidelines { void UseEnumClassCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( @@ -31,4 +31,4 @@ void UseEnumClassCheck::check(const MatchFinder::MatchResult &Result) { << FixItHint::CreateInsertion(UnscopedEnum->getLocation(), "class "); } -} // namespace clang::tidy::modernize +} // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h similarity index 70% rename from clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h rename to clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h index 9cfb2024b9cfd..136ac7f3f253b 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEnumClassCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h @@ -6,18 +6,18 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEENUMCLASSCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEENUMCLASSCHECK_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H #include "../ClangTidyCheck.h" -namespace clang::tidy::modernize { +namespace clang::tidy::cppcoreguidelines { /// Check for unscoped enums that are not contained in classes/structs. /// Suggest to use scoped enums (enum class) instead. /// /// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-enum-class.html +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/use-enum-class.html class UseEnumClassCheck : public ClangTidyCheck { public: UseEnumClassCheck(StringRef Name, ClangTidyContext *Context) @@ -29,6 +29,6 @@ class UseEnumClassCheck : public ClangTidyCheck { } }; -} // namespace clang::tidy::modernize +} // namespace clang::tidy::cppcoreguidelines -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_ENUM_CLASS_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USEENUMCLASSCHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index ea19586b1f08c..bab1167fb15ff 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -34,7 +34,6 @@ add_clang_library(clangTidyModernizeModule STATIC UseDefaultMemberInitCheck.cpp UseDesignatedInitializersCheck.cpp UseEmplaceCheck.cpp - UseEnumClassCheck.cpp UseEqualsDefaultCheck.cpp UseEqualsDeleteCheck.cpp UseIntegerSignComparisonCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index 1f77c9a94d25a..fc46c72982fdc 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -35,7 +35,6 @@ #include "UseDefaultMemberInitCheck.h" #include "UseDesignatedInitializersCheck.h" #include "UseEmplaceCheck.h" -#include "UseEnumClassCheck.h" #include "UseEqualsDefaultCheck.h" #include "UseEqualsDeleteCheck.h" #include "UseIntegerSignComparisonCheck.h" @@ -111,7 +110,6 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck<UseDefaultMemberInitCheck>( "modernize-use-default-member-init"); CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace"); - CheckFactories.registerCheck<UseEnumClassCheck>("modernize-use-enum-class"); CheckFactories.registerCheck<UseEqualsDefaultCheck>("modernize-use-equals-default"); CheckFactories.registerCheck<UseEqualsDeleteCheck>( "modernize-use-equals-delete"); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index b34a4d3d31b9c..603368f9aaf07 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,8 +136,8 @@ New checks Finds potentially erroneous calls to ``reset`` method on smart pointers when the pointee type also has a ``reset`` method. -- New :doc:`modernize-use-enum-class - <clang-tidy/checks/modernize/use-enum-class>` check. +- New :doc:`cppcoreguidelines-use-enum-class + <clang-tidy/checks/cppcoreguidelines/use-enum-class>` check. Finds plain non-class enum definitions that could use ``enum class``. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst similarity index 87% rename from clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst rename to clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst index 3adb6e204ad92..01d620a5a795f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-enum-class.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst @@ -1,6 +1,6 @@ -.. title:: clang-tidy - modernize-use-enum-class +.. title:: clang-tidy - cppcoreguidelines-use-enum-class -modernize-use-enum-class +cppcoreguidelines-use-enum-class ============================= Scoped enums (enum class) should be preferred over unscoped enums: diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index c358419efd7b9..6cb79c1f58c3c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -211,6 +211,7 @@ Clang-Tidy Checks :doc:`cppcoreguidelines-rvalue-reference-param-not-moved <cppcoreguidelines/rvalue-reference-param-not-moved>`, :doc:`cppcoreguidelines-slicing <cppcoreguidelines/slicing>`, :doc:`cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions>`, + :doc:`cppcoreguidelines-use-enum-class <cppcoreguidelines/use-enum-class>`, "Yes" :doc:`cppcoreguidelines-virtual-class-destructor <cppcoreguidelines/virtual-class-destructor>`, "Yes" :doc:`darwin-avoid-spinlock <darwin/avoid-spinlock>`, :doc:`darwin-dispatch-once-nonstatic <darwin/dispatch-once-nonstatic>`, "Yes" @@ -302,7 +303,6 @@ Clang-Tidy Checks :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes" :doc:`modernize-use-designated-initializers <modernize/use-designated-initializers>`, "Yes" :doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes" - :doc:`modernize-use-enum-class <modernize/use-enum-class>`, "Yes" :doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes" :doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes" :doc:`modernize-use-integer-sign-comparison <modernize/use-integer-sign-comparison>`, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp similarity index 66% rename from clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp rename to clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp index 9712fbc0aac4a..924ef3d3140ac 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-enum-class.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp @@ -1,20 +1,20 @@ -// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-enum-class %t +// RUN: %check_clang_tidy -std=c++17-or-later %s cppcoreguidelines-use-enum-class %t enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] enum class EC {}; struct S { enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] // Ignore unscoped enums in recordDecl enum class EC {}; }; class C { enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] // Ignore unscoped enums in recordDecl enum class EC {}; }; @@ -22,27 +22,27 @@ class C { template<class T> class TC { enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] // Ignore unscoped enums in recordDecl enum class EC {}; }; union U { enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] // Ignore unscoped enums in recordDecl enum class EC {}; }; namespace { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] enum class EC {}; } // namespace namespace N { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [modernize-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] enum class EC {}; } // namespace N @@ -53,6 +53,6 @@ using enum S::E; using enum S::EC; enum ForwardE : int; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use enum class instead [modernize-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] enum class ForwardEC : int; >From 129b95dd41593dc73cb5fcc69f1af24968c134f0 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 9 May 2025 14:28:37 +0200 Subject: [PATCH 3/6] Remove traverse call --- .../clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp | 3 +-- .../clang-tidy/cppcoreguidelines/UseEnumClassCheck.h | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp index c64d0d5046a18..759ff3f437bd9 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp @@ -15,8 +15,7 @@ namespace clang::tidy::cppcoreguidelines { void UseEnumClassCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - traverse(TK_AsIs, - enumDecl(unless(isScoped()), unless(hasParent(recordDecl())))) + enumDecl(unless(isScoped()), unless(hasParent(recordDecl()))) .bind("unscoped_enum"), this); } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h index 136ac7f3f253b..445ffaa675f82 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h @@ -27,6 +27,9 @@ class UseEnumClassCheck : public ClangTidyCheck { bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TraversalKind::TK_IgnoreUnlessSpelledInSource; + } }; } // namespace clang::tidy::cppcoreguidelines >From 723c91371c27ce32a9f0a8717837ea06a6a13988 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 9 May 2025 16:04:38 +0200 Subject: [PATCH 4/6] Add option to ignore unscoped enums in classes --- .../cppcoreguidelines/UseEnumClassCheck.cpp | 23 ++++++---- .../cppcoreguidelines/UseEnumClassCheck.h | 9 ++-- ...class-ignore-unscoped-enums-in-classes.cpp | 13 ++++++ .../cppcoreguidelines/use-enum-class.cpp | 42 ++++++++----------- 4 files changed, 52 insertions(+), 35 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp index 759ff3f437bd9..ec7d9237afa3c 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.cpp @@ -13,21 +13,30 @@ using namespace clang::ast_matchers; namespace clang::tidy::cppcoreguidelines { +UseEnumClassCheck::UseEnumClassCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreUnscopedEnumsInClasses( + Options.get("IgnoreUnscopedEnumsInClasses", false)) {} + +void UseEnumClassCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreUnscopedEnumsInClasses", + IgnoreUnscopedEnumsInClasses); +} + void UseEnumClassCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - enumDecl(unless(isScoped()), unless(hasParent(recordDecl()))) - .bind("unscoped_enum"), - this); + auto EnumDecl = + IgnoreUnscopedEnumsInClasses + ? enumDecl(unless(isScoped()), unless(hasParent(recordDecl()))) + : enumDecl(unless(isScoped())); + Finder->addMatcher(EnumDecl.bind("unscoped_enum"), this); } void UseEnumClassCheck::check(const MatchFinder::MatchResult &Result) { const auto *UnscopedEnum = Result.Nodes.getNodeAs<EnumDecl>("unscoped_enum"); diag(UnscopedEnum->getLocation(), - "enum %0 is unscoped, use enum class instead") + "enum %0 is unscoped, use 'enum class' instead") << UnscopedEnum; - diag(UnscopedEnum->getLocation(), "insert 'class'", DiagnosticIDs::Note) - << FixItHint::CreateInsertion(UnscopedEnum->getLocation(), "class "); } } // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h index 445ffaa675f82..d259171031932 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h @@ -20,16 +20,19 @@ namespace clang::tidy::cppcoreguidelines { /// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/use-enum-class.html class UseEnumClassCheck : public ClangTidyCheck { public: - UseEnumClassCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + UseEnumClassCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus; + return LangOpts.CPlusPlus11; } std::optional<TraversalKind> getCheckTraversalKind() const override { return TraversalKind::TK_IgnoreUnlessSpelledInSource; } + +private: + const bool IgnoreUnscopedEnumsInClasses; }; } // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp new file mode 100644 index 0000000000000..b467e84a07082 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp @@ -0,0 +1,13 @@ +// RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t -- -config="{CheckOptions: {cppcoreguidelines-use-enum-class.IgnoreUnscopedEnumsInClasses: true}}" -- + +enum E {}; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + +enum class EC {}; + +struct S { + enum E {}; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // Ignore unscoped enums in recordDecl + enum class EC {}; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp index 924ef3d3140ac..9620bfa28ab40 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp @@ -1,58 +1,50 @@ -// RUN: %check_clang_tidy -std=c++17-or-later %s cppcoreguidelines-use-enum-class %t +// RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] enum class EC {}; struct S { - enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] - // Ignore unscoped enums in recordDecl - enum class EC {}; + enum E {}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + enum class EC {}; }; class C { - enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] - // Ignore unscoped enums in recordDecl - enum class EC {}; + enum E {}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + enum class EC {}; }; template<class T> class TC { - enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] - // Ignore unscoped enums in recordDecl - enum class EC {}; + enum E {}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + enum class EC {}; }; union U { - enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] - // Ignore unscoped enums in recordDecl - enum class EC {}; + enum E {}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + enum class EC {}; }; namespace { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] enum class EC {}; } // namespace namespace N { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] enum class EC {}; } // namespace N template<enum ::EC> static void foo(); -using enum S::E; -using enum S::EC; - enum ForwardE : int; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use enum class instead [cppcoreguidelines-use-enum-class] - +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] enum class ForwardEC : int; >From f7463f6a661d9a4721f1776e066ae83a5b5d4d35 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 9 May 2025 16:07:15 +0200 Subject: [PATCH 5/6] Improve documentation --- .../cppcoreguidelines/UseEnumClassCheck.h | 4 ++-- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- .../checks/cppcoreguidelines/use-enum-class.rst | 17 +++++++++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h index d259171031932..bfcdebe705627 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h @@ -13,8 +13,8 @@ namespace clang::tidy::cppcoreguidelines { -/// Check for unscoped enums that are not contained in classes/structs. -/// Suggest to use scoped enums (enum class) instead. +/// Check for unscoped enums and suggest to use scoped enums (enum class). +/// Optionally, ignore unscoped enums in classes via IgnoreUnscopedEnumsInClasses /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/use-enum-class.html diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 603368f9aaf07..f5136f3e5e171 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -139,7 +139,7 @@ New checks - New :doc:`cppcoreguidelines-use-enum-class <clang-tidy/checks/cppcoreguidelines/use-enum-class>` check. - Finds plain non-class enum definitions that could use ``enum class``. + Finds plain non-class ``enum`` definitions that could use ``enum class``. New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst index 01d620a5a795f..3e36f45e0d4cd 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst @@ -3,11 +3,11 @@ cppcoreguidelines-use-enum-class ============================= -Scoped enums (enum class) should be preferred over unscoped enums: -https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class +Finds plain non-class ``enum`` definitions that could use ``enum class``. -Unscoped enums in classes are not reported since it is a well -established pattern to limit the scope of plain enums. +This check implements `Enum.3 +<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class>`_ +from the C++ Core Guidelines." Example: @@ -17,10 +17,15 @@ Example: enum class E {}; // OK struct S { - enum E {}; // OK, scope already limited + enum E {}; // use "enum class E {};" instead + // OK with option IgnoreUnscopedEnumsInClasses }; namespace N { enum E {}; // use "enum class E {};" instead - // report since it is hard to detect how large the surrounding namespace is } + + +.. option:: IgnoreUnscopedEnumsInClasses + + When `true` (default is `false`), ignores unscoped ``enum`` declarations in classes. >From a5c1437c650f3b506038b5f8898a8c363a95a827 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 9 May 2025 20:45:52 +0200 Subject: [PATCH 6/6] Address review comments --- .../CppCoreGuidelinesTidyModule.cpp | 4 ++-- clang-tools-extra/docs/ReleaseNotes.rst | 12 ++++++------ .../checks/cppcoreguidelines/use-enum-class.rst | 10 +++++++--- .../docs/clang-tidy/checks/list.rst | 2 +- ...um-class-ignore-unscoped-enums-in-classes.cpp | 11 ++++++++--- .../cppcoreguidelines/use-enum-class.cpp | 16 ++++++++-------- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index 409ebbf19349e..ca9dc4f4f8fed 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -60,8 +60,6 @@ class CppCoreGuidelinesModule : public ClangTidyModule { void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck<AvoidCapturingLambdaCoroutinesCheck>( "cppcoreguidelines-avoid-capturing-lambda-coroutines"); - CheckFactories.registerCheck<UseEnumClassCheck>( - "cppcoreguidelines-use-enum-class"); CheckFactories.registerCheck<modernize::AvoidCArraysCheck>( "cppcoreguidelines-avoid-c-arrays"); CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>( @@ -134,6 +132,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule { CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing"); CheckFactories.registerCheck<modernize::UseDefaultMemberInitCheck>( "cppcoreguidelines-use-default-member-init"); + CheckFactories.registerCheck<UseEnumClassCheck>( + "cppcoreguidelines-use-enum-class"); CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>( "cppcoreguidelines-c-copy-assignment-signature"); CheckFactories.registerCheck<VirtualClassDestructorCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index f5136f3e5e171..dc99dfbfe77ee 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -117,6 +117,11 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`cppcoreguidelines-use-enum-class + <clang-tidy/checks/cppcoreguidelines/use-enum-class>` check. + + Finds plain non-class ``enum`` definitions that could use ``enum class``. + - New :doc:`bugprone-capturing-this-in-member-variable <clang-tidy/checks/bugprone/capturing-this-in-member-variable>` check. @@ -136,11 +141,6 @@ New checks Finds potentially erroneous calls to ``reset`` method on smart pointers when the pointee type also has a ``reset`` method. -- New :doc:`cppcoreguidelines-use-enum-class - <clang-tidy/checks/cppcoreguidelines/use-enum-class>` check. - - Finds plain non-class ``enum`` definitions that could use ``enum class``. - New check aliases ^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ Changes in existing checks diagnosing designated initializers for ``std::array`` initializations. - Improved :doc:`modernize-use-ranges - <clang-tidy/checks/modernize/use-ranges>` check by updating suppress + <clang-tidy/checks/modernize/use-ranges>` check by updating suppress warnings logic for ``nullptr`` in ``std::find``. - Improved :doc:`modernize-use-starts-ends-with diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst index 3e36f45e0d4cd..9e9f4c99dc240 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/use-enum-class.rst @@ -1,9 +1,10 @@ .. title:: clang-tidy - cppcoreguidelines-use-enum-class cppcoreguidelines-use-enum-class -============================= +================================ -Finds plain non-class ``enum`` definitions that could use ``enum class``. +Finds unscoped (non-class) ``enum`` declarations and suggests using +``enum class`` instead. This check implements `Enum.3 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class>`_ @@ -25,7 +26,10 @@ Example: enum E {}; // use "enum class E {};" instead } +Options +------- .. option:: IgnoreUnscopedEnumsInClasses - When `true` (default is `false`), ignores unscoped ``enum`` declarations in classes. + When `true`, ignores unscoped ``enum`` declarations in classes. + Default is `false`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 6cb79c1f58c3c..7523648fc66ad 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -211,7 +211,7 @@ Clang-Tidy Checks :doc:`cppcoreguidelines-rvalue-reference-param-not-moved <cppcoreguidelines/rvalue-reference-param-not-moved>`, :doc:`cppcoreguidelines-slicing <cppcoreguidelines/slicing>`, :doc:`cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions>`, - :doc:`cppcoreguidelines-use-enum-class <cppcoreguidelines/use-enum-class>`, "Yes" + :doc:`cppcoreguidelines-use-enum-class <cppcoreguidelines/use-enum-class>`, :doc:`cppcoreguidelines-virtual-class-destructor <cppcoreguidelines/virtual-class-destructor>`, "Yes" :doc:`darwin-avoid-spinlock <darwin/avoid-spinlock>`, :doc:`darwin-dispatch-once-nonstatic <darwin/dispatch-once-nonstatic>`, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp index b467e84a07082..66e1ab073110d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp @@ -1,13 +1,18 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t -- -config="{CheckOptions: {cppcoreguidelines-use-enum-class.IgnoreUnscopedEnumsInClasses: true}}" -- +// RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t -- \ +// RUN: -config="{CheckOptions: {cppcoreguidelines-use-enum-class.IgnoreUnscopedEnumsInClasses: true}}" -- enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; struct S { enum E {}; - // CHECK-MESSAGES-NOT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead // Ignore unscoped enums in recordDecl enum class EC {}; }; + +enum ForwardE : int; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead +enum class ForwardEC : int; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp index 9620bfa28ab40..c1525e233cdbf 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class.cpp @@ -1,44 +1,44 @@ // RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; struct S { enum E {}; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; }; class C { enum E {}; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; }; template<class T> class TC { enum E {}; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; }; union U { enum E {}; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; }; namespace { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; } // namespace namespace N { enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; } // namespace N @@ -46,5 +46,5 @@ template<enum ::EC> static void foo(); enum ForwardE : int; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead [cppcoreguidelines-use-enum-class] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead enum class ForwardEC : int; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits