Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang-tidy] Add readability-redundant-casting check #70595

Merged

Conversation

PiotrZSL
Copy link
Member

Detects explicit type casting operations that involve the same source and destination types, and subsequently recommend their removal. Covers a range of explicit casting operations. Its primary objective is to enhance code readability and maintainability by eliminating unnecessary type casting.

Closes #67534

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 29, 2023

@llvm/pr-subscribers-clang-tidy

Author: Piotr Zegar (PiotrZSL)

Changes

Detects explicit type casting operations that involve the same source and destination types, and subsequently recommend their removal. Covers a range of explicit casting operations. Its primary objective is to enhance code readability and maintainability by eliminating unnecessary type casting.

Closes #67534


Patch is 25.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/70595.diff

10 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/readability/CMakeLists.txt (+1)
  • (modified) clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp (+3)
  • (added) clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp (+242)
  • (added) clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h (+38)
  • (modified) clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp (+5)
  • (modified) clang-tools-extra/clang-tidy/utils/FixItHintUtils.h (+4)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6)
  • (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1)
  • (added) clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst (+37)
  • (added) clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp (+200)
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 5452c2d48a46173..52f873d2a14b700 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -33,6 +33,7 @@ add_clang_library(clangTidyReadabilityModule
   QualifiedAutoCheck.cpp
   ReadabilityTidyModule.cpp
   RedundantAccessSpecifiersCheck.cpp
+  RedundantCastingCheck.cpp
   RedundantControlFlowCheck.cpp
   RedundantDeclarationCheck.cpp
   RedundantFunctionPtrDereferenceCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index b8e6e6414320600..d33d429f64c4421 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -36,6 +36,7 @@
 #include "OperatorsRepresentationCheck.h"
 #include "QualifiedAutoCheck.h"
 #include "RedundantAccessSpecifiersCheck.h"
+#include "RedundantCastingCheck.h"
 #include "RedundantControlFlowCheck.h"
 #include "RedundantDeclarationCheck.h"
 #include "RedundantFunctionPtrDereferenceCheck.h"
@@ -111,6 +112,8 @@ class ReadabilityModule : public ClangTidyModule {
         "readability-qualified-auto");
     CheckFactories.registerCheck<RedundantAccessSpecifiersCheck>(
         "readability-redundant-access-specifiers");
+    CheckFactories.registerCheck<RedundantCastingCheck>(
+        "readability-redundant-casting");
     CheckFactories.registerCheck<RedundantFunctionPtrDereferenceCheck>(
         "readability-redundant-function-ptr-dereference");
     CheckFactories.registerCheck<RedundantMemberInitCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
new file mode 100644
index 000000000000000..ab18b6b7dd886f7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -0,0 +1,242 @@
+//===--- RedundantCastingCheck.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 "RedundantCastingCheck.h"
+#include "../utils/FixItHintUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static bool areTypesEquals(QualType S, QualType D) {
+  if (S == D)
+    return true;
+
+  const auto *TS = S->getAs<TypedefType>();
+  const auto *TD = D->getAs<TypedefType>();
+  if (TS != TD)
+    return false;
+
+  QualType PtrS = S->getPointeeType();
+  QualType PtrD = D->getPointeeType();
+
+  if (!PtrS.isNull() && !PtrD.isNull())
+    return areTypesEquals(PtrS, PtrD);
+
+  const DeducedType *DT = S->getContainedDeducedType();
+  if (DT && DT->isDeduced())
+    return D == DT->getDeducedType();
+
+  return false;
+}
+
+static bool areTypesEquals(QualType TypeS, QualType TypeD,
+                           bool IgnoreTypeAliases) {
+  const QualType CTypeS = TypeS.getCanonicalType();
+  const QualType CTypeD = TypeD.getCanonicalType();
+  if (CTypeS != CTypeD)
+    return false;
+
+  return IgnoreTypeAliases || areTypesEquals(TypeS.getLocalUnqualifiedType(),
+                                             TypeD.getLocalUnqualifiedType());
+}
+
+static bool areBinaryOperatorOperandsTypesEqual(const Expr *E,
+                                                bool IgnoreTypeAliases) {
+  if (!E)
+    return false;
+  const Expr *WithoutImplicitAndParen = E->IgnoreParenImpCasts();
+  if (!WithoutImplicitAndParen)
+    return false;
+  if (const auto *B = dyn_cast<BinaryOperator>(WithoutImplicitAndParen)) {
+    const QualType NonReferenceType =
+        WithoutImplicitAndParen->getType().getNonReferenceType();
+    if (!areTypesEquals(
+            B->getLHS()->IgnoreImplicit()->getType().getNonReferenceType(),
+            NonReferenceType, IgnoreTypeAliases))
+      return true;
+    if (!areTypesEquals(
+            B->getRHS()->IgnoreImplicit()->getType().getNonReferenceType(),
+            NonReferenceType, IgnoreTypeAliases))
+      return true;
+  }
+  return false;
+}
+
+static const Decl *getSourceExprDecl(const Expr *SourceExpr) {
+  const Expr *CleanSourceExpr = SourceExpr->IgnoreParenImpCasts();
+  if (const auto *E = dyn_cast<DeclRefExpr>(CleanSourceExpr)) {
+    return E->getDecl();
+  }
+
+  if (const auto *E = dyn_cast<CallExpr>(CleanSourceExpr)) {
+    return E->getCalleeDecl();
+  }
+
+  if (const auto *E = dyn_cast<MemberExpr>(CleanSourceExpr)) {
+    return E->getMemberDecl();
+  }
+  return nullptr;
+}
+
+RedundantCastingCheck::RedundantCastingCheck(StringRef Name,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
+      IgnoreTypeAliases(Options.getLocalOrGlobal("IgnoreTypeAliases", false)) {}
+
+void RedundantCastingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+  Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases);
+}
+
+void RedundantCastingCheck::registerMatchers(MatchFinder *Finder) {
+
+  auto SimpleType = qualType(hasCanonicalType(
+      qualType(anyOf(builtinType(), references(builtinType()),
+                     references(pointsTo(qualType())), pointsTo(qualType())))));
+
+  auto BitfieldMemberExpr = memberExpr(member(fieldDecl(isBitField())));
+
+  Finder->addMatcher(
+      explicitCastExpr(
+          unless(hasCastKind(CK_ConstructorConversion)),
+          unless(hasCastKind(CK_UserDefinedConversion)),
+          unless(cxxFunctionalCastExpr(hasDestinationType(unless(SimpleType)))),
+
+          hasDestinationType(qualType().bind("type2")),
+          hasSourceExpression(anyOf(
+              expr(unless(initListExpr()), unless(BitfieldMemberExpr),
+                   hasType(qualType().bind("type1")))
+                  .bind("source"),
+              initListExpr(unless(hasInit(1, expr())),
+                           hasInit(0, expr(unless(BitfieldMemberExpr),
+                                           hasType(qualType().bind("type1")))
+                                          .bind("source"))))))
+          .bind("cast"),
+      this);
+}
+
+void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *SourceExpr = Result.Nodes.getNodeAs<Expr>("source");
+  auto TypeD = *Result.Nodes.getNodeAs<QualType>("type2");
+
+  if (SourceExpr->getValueKind() == VK_LValue &&
+      TypeD.getCanonicalType()->isRValueReferenceType())
+    return;
+
+  const auto TypeS =
+      Result.Nodes.getNodeAs<QualType>("type1")->getNonReferenceType();
+  TypeD = TypeD.getNonReferenceType();
+
+  if (!areTypesEquals(TypeS, TypeD, IgnoreTypeAliases))
+    return;
+
+  if (areBinaryOperatorOperandsTypesEqual(SourceExpr, IgnoreTypeAliases))
+    return;
+
+  const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
+  if (IgnoreMacros &&
+      (CastExpr->getBeginLoc().isMacroID() ||
+       CastExpr->getEndLoc().isMacroID() || CastExpr->getExprLoc().isMacroID()))
+    return;
+
+  {
+    auto Diag = diag(CastExpr->getExprLoc(),
+                     "redundant explicit casting to the same type %0 as the "
+                     "sub-expression, remove this casting");
+    Diag << TypeD;
+
+    const SourceManager &SM = *Result.SourceManager;
+    const SourceLocation SourceExprBegin =
+        SM.getExpansionLoc(SourceExpr->getBeginLoc());
+    const SourceLocation SourceExprEnd =
+        SM.getExpansionLoc(SourceExpr->getEndLoc());
+
+    if (SourceExprBegin != CastExpr->getBeginLoc())
+      Diag << FixItHint::CreateRemoval(SourceRange(
+          CastExpr->getBeginLoc(), SourceExprBegin.getLocWithOffset(-1)));
+
+    const SourceLocation NextToken = Lexer::getLocForEndOfToken(
+        SourceExprEnd, 0U, SM, Result.Context->getLangOpts());
+
+    if (SourceExprEnd != CastExpr->getEndLoc()) {
+      Diag << FixItHint::CreateRemoval(
+          SourceRange(NextToken, CastExpr->getEndLoc()));
+    }
+
+    if (utils::fixit::needParens(*SourceExpr)) {
+
+      Diag << FixItHint::CreateInsertion(SourceExprBegin, "(")
+           << FixItHint::CreateInsertion(NextToken, ")");
+    }
+  }
+
+  const auto *SourceExprDecl = getSourceExprDecl(SourceExpr);
+  if (!SourceExprDecl)
+    return;
+
+  if (const auto *D = dyn_cast<CXXConstructorDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from the invocation of this constructor",
+         DiagnosticIDs::Note);
+    return;
+  }
+
+  if (const auto *D = dyn_cast<FunctionDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from the invocation of this "
+         "%select{function|method}0",
+         DiagnosticIDs::Note)
+        << isa<CXXMethodDecl>(D) << D->getReturnTypeSourceRange();
+    return;
+  }
+
+  if (const auto *D = dyn_cast<FieldDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from referencing this member",
+         DiagnosticIDs::Note)
+        << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
+    return;
+  }
+
+  if (const auto *D = dyn_cast<ParmVarDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from referencing this parameter",
+         DiagnosticIDs::Note)
+        << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
+    return;
+  }
+
+  if (const auto *D = dyn_cast<VarDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from referencing this variable",
+         DiagnosticIDs::Note)
+        << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
+    return;
+  }
+
+  if (const auto *D = dyn_cast<EnumConstantDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from referencing this enum constant",
+         DiagnosticIDs::Note);
+    return;
+  }
+
+  if (const auto *D = dyn_cast<BindingDecl>(SourceExprDecl)) {
+    diag(D->getLocation(),
+         "source type originates from referencing this bound variable",
+         DiagnosticIDs::Note);
+    return;
+  }
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
new file mode 100644
index 000000000000000..fdcfede05d43696
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
@@ -0,0 +1,38 @@
+//===--- RedundantCastingCheck.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_READABILITY_REDUNDANTCASTINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCASTINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Detects explicit type casting operations that involve the same source and
+/// destination types, and subsequently recommend their removal.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-casting.html
+class RedundantCastingCheck : public ClangTidyCheck {
+public:
+  RedundantCastingCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  const bool IgnoreMacros;
+  const bool IgnoreTypeAliases;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCASTINGCHECK_H
diff --git a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
index 226dd60b5bf5f54..11f5ad94ef1b0cb 100644
--- a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
@@ -240,6 +240,11 @@ static bool needParensAfterUnaryOperator(const Expr &ExprNode) {
   return false;
 }
 
+bool needParens(const Expr &ExprNode) {
+  return !isa<clang::ParenExpr>(&ExprNode) &&
+         needParensAfterUnaryOperator(ExprNode);
+}
+
 // Format a pointer to an expression: prefix with '*' but simplify
 // when it already begins with '&'.  Return empty string on failure.
 std::string formatDereference(const Expr &ExprNode, const ASTContext &Context) {
diff --git a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
index 15894c4bf5cf8f2..41535079f4e2f34 100644
--- a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
@@ -47,6 +47,10 @@ addQualifierToVarDecl(const VarDecl &Var, const ASTContext &Context,
 
 // \brief Format a pointer to an expression
 std::string formatDereference(const Expr &ExprNode, const ASTContext &Context);
+
+// \brief Returns ``true`` if ExprNode ought to be enclosed within parentheses.
+bool needParens(const Expr &ExprNode);
+
 } // namespace clang::tidy::utils::fixit
 
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 5ce38ab48bf295f..f7b3cdfff12755c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -191,6 +191,12 @@ New checks
   Recommends the smallest possible underlying type for an ``enum`` or ``enum``
   class based on the range of its enumerators.
 
+- New :doc:`readability-redundant-casting
+  <clang-tidy/checks/readability/redundant-casting>` check.
+
+  Detects explicit type casting operations that involve the same source and
+  destination types, and subsequently recommend their removal.
+
 - New :doc:`readability-reference-to-constructed-temporary
   <clang-tidy/checks/readability/reference-to-constructed-temporary>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 6f987ba1672e3f2..82fff6e387a3a41 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -359,6 +359,7 @@ Clang-Tidy Checks
    :doc:`readability-operators-representation <readability/operators-representation>`, "Yes"
    :doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
    :doc:`readability-redundant-access-specifiers <readability/redundant-access-specifiers>`, "Yes"
+   :doc:`readability-redundant-casting <readability/redundant-casting>`, "Yes"
    :doc:`readability-redundant-control-flow <readability/redundant-control-flow>`, "Yes"
    :doc:`readability-redundant-declaration <readability/redundant-declaration>`, "Yes"
    :doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst
new file mode 100644
index 000000000000000..23eaa225f03a3ce
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-casting.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - readability-redundant-casting
+
+readability-redundant-casting
+=============================
+
+Detects explicit type casting operations that involve the same source and
+destination types, and subsequently recommend their removal. Covers a range of
+explicit casting operations, including ``static_cast``, ``const_cast``, C-style
+casts, and ``reinterpret_cast``. Its primary objective is to enhance code
+readability and maintainability by eliminating unnecessary type casting.
+
+.. code-block:: c++
+
+  int value = 42;
+  int result = static_cast<int>(value);
+
+In this example, the ``static_cast<int>(value)`` is redundant, as it performs
+a cast from an ``int`` to another ``int``.
+
+Casting operations involving constructor conversions, user-defined conversions,
+functional casts, type-dependent casts, casts between distinct type aliases that
+refer to the same underlying type, as well as bitfield-related casts and casts
+directly from lvalue to rvalue, are all disregarded by the check.
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+   If set to `true`, the check will not give warnings inside macros. Default
+   is `true`.
+
+.. option:: IgnoreTypeAliases
+
+   When set to `false`, the check will consider type aliases, and when set to
+   `true`, it will resolve all type aliases and operate on the underlying
+   types. Default is `false`.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
new file mode 100644
index 000000000000000..7dca6921298d38f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-casting.cpp
@@ -0,0 +1,200 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-casting %t
+// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=,MACROS %s readability-redundant-casting %t -- \
+// RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreMacros: false }}'
+// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
+// RUN:   -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}'
+
+struct A {};
+struct B : A {};
+A getA();
+
+void testRedundantStaticCasting(A& value) {
+  A& a1 = static_cast<A&>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-3]]:36: note: source type originates from referencing this parameter
+  // CHECK-FIXES: {{^}}  A& a1 = value;
+}
+
+void testRedundantConstCasting1(A& value) {
+  A& a2 = const_cast<A&>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-3]]:36: note: source type originates from referencing this parameter
+  // CHECK-FIXES: {{^}}  A& a2 = value;
+}
+
+void testRedundantConstCasting2(const A& value) {
+  const A& a3 = const_cast<const A&>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant explicit casting to the same type 'const A' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-3]]:42: note: source type originates from referencing this parameter
+  // CHECK-FIXES: {{^}}  const A& a3 = value;
+}
+
+void testRedundantReinterpretCasting(A& value) {
+  A& a4 = reinterpret_cast<A&>(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-3]]:41: note: source type originates from referencing this parameter
+  // CHECK-FIXES: {{^}}  A& a4 = value;
+}
+
+void testRedundantCCasting(A& value) {
+  A& a5 = (A&)(value);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
+  // CHECK-MESSAGES: :[[@LINE-3]]:31: note: source type originates from referencing this parameter
+  // CHECK-FIXES: {{^}}  A& a5 = value;
+}
+
+void testDoubleCasting(A& value) {
+  A& a6 = static_cast<A&>(reinterpret_cast<A&>(value));
+  // CHECK-M...
[truncated]

@PiotrZSL
Copy link
Member Author

431 issues found in llvm.

Example:

clang/lib/Sema/SemaAttr.cpp:332:21: warning: redundant explicit casting to the same type 'Expr *' as the sub-expression, remove this casting [readability-redundant-casting]
 332 |   Expr *Alignment = static_cast<Expr *>(alignment);
     |                     ^~~~~~~~~~~~~~~~~~~~         ~
clang/lib/Sema/SemaAttr.cpp:323:55: note: source type originates from referencing this parameter
 323 |                            StringRef SlotLabel, Expr *alignment) {
     |                                                 ~~~~~~^

@PiotrZSL PiotrZSL self-assigned this Jan 7, 2024
Detects explicit type casting operations that involve the same source and
destination types, and subsequently recommend their removal. Covers a range
of explicit casting operations. Its primary objective is to enhance code
readability and maintainability by eliminating unnecessary type casting.
@PiotrZSL PiotrZSL force-pushed the 67534-clang-tidy-readability-redundant-casting branch from e17c6f3 to fab960f Compare January 16, 2024 18:13
Copy link
Member Author

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased code, changed utils::fixit::needParens into recently added more generic utils::fixit::areParensNeededForStatement. Renamed areTypesEquals into areTypesEqual.git dif

Copy link
Contributor

@5chmidti 5chmidti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found only this one issue

Copy link
Contributor

@5chmidti 5chmidti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@PiotrZSL PiotrZSL merged commit 1ad1f98 into llvm:main Jan 20, 2024
5 checks passed
@PiotrZSL PiotrZSL deleted the 67534-clang-tidy-readability-redundant-casting branch January 20, 2024 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang-tidy] Detect more redundant casts (google-readability-casting)
4 participants