https://github.com/JungPhilipp updated https://github.com/llvm/llvm-project/pull/138282
>From 414fd293764c04bc86154f2d7b42c31a3a0ea693 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 01/11] 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 0cf59b6e0216a..05308f2436f7a 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>( 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 19ccd1790e757..162ac484acf8f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -148,6 +148,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 5a79d61b1fd7e..6ffdaf09a5b0c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -303,6 +303,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 baeed94d3613187960b75aa0b4cb8b5bab69c774 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 02/11] 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 | 4 +--- 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, 27 insertions(+), 26 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 4dd9b0904f075..8d3355566b3a8 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 05308f2436f7a..b3417cca78ccc 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" @@ -112,8 +111,7 @@ class ModernizeModule : public ClangTidyModule { "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<UseEqualsDefaultCheck>("modernize-use-equals-default"); CheckFactories.registerCheck<UseEqualsDeleteCheck>( "modernize-use-equals-delete"); CheckFactories.registerCheck<UseNodiscardCheck>("modernize-use-nodiscard"); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 162ac484acf8f..9f817e457b91b 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -148,8 +148,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 6ffdaf09a5b0c..76f25295238de 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -212,6 +212,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" @@ -303,7 +304,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 61665e0f7d535b15c8baa4b1d14095f9d61431dc 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 03/11] 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 b9454d4b2c0bd18283534b37b6995cbf9a1f0091 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 04/11] 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 96cb2fb70a3c5096e49e4ac319fd43e431aad76b 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 05/11] 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 9f817e457b91b..f914da2fe485f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -151,7 +151,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 b024d6e339bedef7feeb2ad10b2c351f5574c9a8 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 06/11] Address review comments --- .../CppCoreGuidelinesTidyModule.cpp | 4 ++-- clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++----- .../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, 31 insertions(+), 22 deletions(-) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index 8d3355566b3a8..4b3b7bf963fdc 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 f914da2fe485f..69db72e34f89a 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. @@ -148,11 +153,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 ^^^^^^^^^^^^^^^^^ 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 76f25295238de..ccb78ee45e9c4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -212,7 +212,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; >From 19a799a2e49a5e291b1240926f5d14f23f9a6642 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Mon, 12 May 2025 09:56:25 +0200 Subject: [PATCH 07/11] Fix order of checks in docu --- clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 69db72e34f89a..106582372d664 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -117,11 +117,6 @@ 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. @@ -141,6 +136,11 @@ New checks Finds unintended character output from ``unsigned char`` and ``signed char`` to an ``ostream``. +- 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:`portability-avoid-pragma-once <clang-tidy/checks/portability/avoid-pragma-once>` check. >From 7bb104364b356319f30cc48bdacafd234b3f79e2 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Mon, 12 May 2025 09:57:57 +0200 Subject: [PATCH 08/11] Revert remove whitespace --- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 106582372d664..2e4bf8c60c258 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -243,7 +243,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 >From 7432684c8cbfc98b4e4c50b2467bc7aad105f8a8 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Mon, 19 May 2025 11:18:54 +0200 Subject: [PATCH 09/11] Make release notes match docu --- clang-tools-extra/docs/ReleaseNotes.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 2e4bf8c60c258..b3d15d6907dc5 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -139,7 +139,8 @@ 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 unscoped (non-class) ``enum`` declarations and suggests using + ``enum class`` instead. - New :doc:`portability-avoid-pragma-once <clang-tidy/checks/portability/avoid-pragma-once>` check. >From 1c2ee4409fb7f75d41278c980054bc2dd366e762 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 13 Jun 2025 15:09:14 +0200 Subject: [PATCH 10/11] Move checks for use-enum-class to single file --- .../cppcoreguidelines/UseEnumClassCheck.h | 4 +-- ...class-ignore-unscoped-enums-in-classes.cpp | 18 ----------- .../cppcoreguidelines/use-enum-class.cpp | 30 +++++++++++++------ 3 files changed, 23 insertions(+), 29 deletions(-) delete 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.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/UseEnumClassCheck.h index bfcdebe705627..dfa4b7e3fda62 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 and suggest to use scoped enums (enum class). -/// Optionally, ignore unscoped enums in classes via IgnoreUnscopedEnumsInClasses +/// Finds unscoped (non-class) enum declarations and suggests using enum class +/// instead. /// /// 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/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 deleted file mode 100644 index 66e1ab073110d..0000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/use-enum-class-ignore-unscoped-enums-in-classes.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// 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 - -enum class EC {}; - -struct S { - enum E {}; - // 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 c1525e233cdbf..f53d787f80efa 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,53 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s cppcoreguidelines-use-enum-class %t +// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=ALL,DEFAULT %s \ +// RUN: cppcoreguidelines-use-enum-class %t -- + +// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=ALL %s \ +// RUN: cppcoreguidelines-use-enum-class %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: cppcoreguidelines-use-enum-class.IgnoreUnscopedEnumsInClasses: true \ +// RUN: }}" -- enum E {}; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; +enum struct ES {}; + struct S { enum E {}; - // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: enum 'E' is unscoped, use 'enum class' instead + // CHECK-MESSAGES-DEFAULT: :[[@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 + // CHECK-MESSAGES-DEFAULT: :[[@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 + // CHECK-MESSAGES-DEFAULT: :[[@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 + // CHECK-MESSAGES-DEFAULT: :[[@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 +// CHECK-MESSAGES-ALL: :[[@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 +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'E' is unscoped, use 'enum class' instead enum class EC {}; } // namespace N @@ -46,5 +55,8 @@ template<enum ::EC> static void foo(); enum ForwardE : int; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead +// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: enum 'ForwardE' is unscoped, use 'enum class' instead + enum class ForwardEC : int; + +enum struct ForwardES : int; >From 4f2ea3fb5cd78f3a21994fbaab14a8ed05f4eec3 Mon Sep 17 00:00:00 2001 From: Philipp Jung <philipp.jun...@sap.com> Date: Fri, 13 Jun 2025 15:23:05 +0200 Subject: [PATCH 11/11] Fixup formatting after rebase --- .../clang-tidy/modernize/ModernizeTidyModule.cpp | 3 ++- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index b3417cca78ccc..27bbbcea6c181 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -111,7 +111,8 @@ class ModernizeModule : public ClangTidyModule { "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<UseEqualsDefaultCheck>( + "modernize-use-equals-default"); CheckFactories.registerCheck<UseEqualsDeleteCheck>( "modernize-use-equals-delete"); CheckFactories.registerCheck<UseNodiscardCheck>("modernize-use-nodiscard"); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index b3d15d6907dc5..6d358cd841a92 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -141,7 +141,7 @@ New checks Finds unscoped (non-class) ``enum`` declarations and suggests using ``enum class`` instead. - + - New :doc:`portability-avoid-pragma-once <clang-tidy/checks/portability/avoid-pragma-once>` check. @@ -244,7 +244,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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits