llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Divvela Rakesh (divvelarakesh1)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/167144.diff


3 Files Affected:

- (added) clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.cpp (+80) 
- (added) clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.h (+36) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-to-underlying.cpp 
(+89) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.cpp
new file mode 100644
index 0000000000000..23513e72dab10
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "UseToUnderlyingCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Error.h" // You'll want this for the inserter
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+//Constructor
+UseToUnderlyingCheck::UseToUnderlyingCheck(StringRef Name, 
+                                           ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Inserter(Options.getLocalOrGlobal("IncludeStyle", 
+               utils::IncludeSorter::IS_LLVM),
+               areDiagsSelfContained()) {}
+//
+void UseToUnderlyingCheck::registerPPCallbacks(const SourceManager &SM,
+                                               Preprocessor *PP,
+                                               Preprocessor *ModuleExpanderPP) 
{
+  Inserter.registerPreprocessor(PP);
+}
+//
+void UseToUnderlyingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IncludeStyle", Inserter.getStyle());
+}
+//Language version compatibility checking
+bool UseToUnderlyingCheck::isLanguageVersionSupported(const LangOptions 
&LangOpts) const{
+  return LangOpts.CPlusPlus23;
+}
+
+//
+void UseToUnderlyingCheck::registerMatchers(MatchFinder *Finder) {
+  // FIXME: Add matchers.
+ Finder->addMatcher(
+      cxxStaticCastExpr(   //C++ cast
+          hasDestinationType(isInteger()), //casting to any type of integer 
(int,long,etc)
+          hasSourceExpression(                 //is an enum class
+              expr(hasType(enumType(hasDeclaration(enumDecl(isScoped())))))
+                  .bind("enumExpr"))) //giving the name enumExpr
+          .bind("castExpr"),   //giving the name castExpr
+      this);
+}
+\
+void UseToUnderlyingCheck::check(const MatchFinder::MatchResult &Result) {
+  //Acquiring the enumExpr and castExpr using getNodeAS
+  const auto *Enum = Result.Nodes.getNodeAs<Expr>("enumExpr");
+  const auto *Cast = Result.Nodes.getNodeAs<CXXStaticCastExpr>("castExpr");
+   
+  //getting contents of that node using getsourcetext
+  StringRef EnumExprText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Enum->getSourceRange()),
+      *Result.SourceManager, getLangOpts());
+  //Suggestion to the user regarding the cast expr
+std::string Replacement = ("std::to_underlying(" + EnumExprText + ")").str();
+// gives and watring message if static cast is used instead to_underlying
+auto Diag=diag(Cast->getBeginLoc(), "use 'std::to_underlying' instead of 
'static_cast' for 'enum class'");
+//suggest and hint for fixing it.
+Diag<< FixItHint::CreateReplacement(Cast->getSourceRange(), Replacement);
+
+ Diag << Inserter.createIncludeInsertion(
+      Result.Context->getSourceManager().getFileID(Cast->getBeginLoc()),
+      "<utility>");
+
+
+  // Required error handling for the Inserter
+
+}
+
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.h 
b/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.h
new file mode 100644
index 0000000000000..55d73361d531c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseToUnderlyingCheck.h
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_USETOUNDERLYINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USETOUNDERLYINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::modernize {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-to-underlying.html
+class UseToUnderlyingCheck : public ClangTidyCheck {
+public:
+  UseToUnderlyingCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                          Preprocessor *ModuleExpanderPP) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+private:
+utils::IncludeInserter Inserter;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USETOUNDERLYINGCHECK_H
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-to-underlying.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-to-underlying.cpp
new file mode 100644
index 0000000000000..53b4668599f5d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-to-underlying.cpp
@@ -0,0 +1,89 @@
+// RUN: %check_clang_tidy -std=c++23 %s modernize-use-to-underlying %t
+
+// Mock std::to_underlying for testing
+namespace std {
+template<typename T>
+constexpr auto to_underlying(T value) noexcept {
+  return static_cast<__underlying_type(T)>(value);
+}
+}
+
+// Test case 1: Basic enum class to int cast - should warn
+enum class MyEnum { A = 1, B = 2 };
+
+void test_basic_cast() {
+  int value = static_cast<int>(MyEnum::A);
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: int value = std::to_underlying(MyEnum::A);
+}
+
+// Test case 2: enum class to long cast - should warn
+void test_long_cast() {
+  long value = static_cast<long>(MyEnum::B);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: long value = std::to_underlying(MyEnum::B);
+}
+
+// Test case 3: enum class in expression - should warn
+void test_expression() {
+  int result = static_cast<int>(MyEnum::A) + 10;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: int result = std::to_underlying(MyEnum::A) + 10;
+}
+
+// Test case 4: Already using std::to_underlying - should NOT warn
+void test_already_correct() {
+  int value = std::to_underlying(MyEnum::B);
+  // No warning expected
+}
+
+// Test case 5: Casting float to int - should NOT warn (not an enum)
+void test_float_cast() {
+  float y = 8.34;
+  int z = static_cast<int>(y);
+  // No warning expected
+}
+
+// Test case 6: Regular (non-scoped) enum - should NOT warn
+enum RegularEnum { X = 1, Y = 2 };
+
+void test_regular_enum() {
+  int value = static_cast<int>(RegularEnum::X);
+  // No warning expected (only enum class should trigger)
+}
+
+// Test case 7: Multiple casts in same function - should warn for each
+void test_multiple_casts() {
+  int a = static_cast<int>(MyEnum::A);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: int a = std::to_underlying(MyEnum::A);
+  
+  int b = static_cast<int>(MyEnum::B);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: int b = std::to_underlying(MyEnum::B);
+}
+
+// Test case 8: enum class with underlying type specified
+enum class TypedEnum : unsigned int { First = 0, Second = 1 };
+
+void test_typed_enum() {
+  unsigned int val = static_cast<unsigned int>(TypedEnum::First);
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: unsigned int val = std::to_underlying(TypedEnum::First);
+}
+
+// Test case 9: Casting to unsigned - should warn
+void test_unsigned_cast() {
+  unsigned value = static_cast<unsigned>(MyEnum::A);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: unsigned value = std::to_underlying(MyEnum::A);
+}
+
+// Test case 10: Nested in function call - should warn
+void some_function(int x) {}
+
+void test_nested_call() {
+  some_function(static_cast<int>(MyEnum::A));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'std::to_underlying' 
instead of 'static_cast' for 'enum class' [modernize-use-to-underlying]
+  // CHECK-FIXES: some_function(std::to_underlying(MyEnum::A));
+}
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/167144
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to