https://github.com/voyager-jhk updated https://github.com/llvm/llvm-project/pull/198085
>From efe3fe07924778cedff93c3f29a5b1e5f9e01fe8 Mon Sep 17 00:00:00 2001 From: voyager-jhk <[email protected]> Date: Sat, 16 May 2026 20:50:59 +0800 Subject: [PATCH] [clang-tidy] Fix false positive in misc-redundant-expression with type aliases The `misc-redundant-expression` check previously flagged expressions as redundant if their underlying `DeclRefExpr` pointed to the same declaration. This caused false positives when comparing identical values accessed through distinct type aliases (sugared types). This patch uses `printPretty` to compare the source-level spellings of the expressions, ensuring nested name specifiers and explicit template arguments are correctly differentiated. Fixes #145415 --- .../misc/RedundantExpressionCheck.cpp | 44 +++++++++++++++++-- clang-tools-extra/docs/ReleaseNotes.rst | 5 +++ .../redundant-expression-type-aliases.cpp | 26 +++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-type-aliases.cpp diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 9db297990b274..f16d056ee8815 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -97,9 +97,47 @@ static bool areEquivalentExpr(const Expr *Left, const Expr *Right) { return false; return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() == cast<DependentScopeDeclRefExpr>(Right)->getQualifier(); - case Stmt::DeclRefExprClass: - return cast<DeclRefExpr>(Left)->getDecl() == - cast<DeclRefExpr>(Right)->getDecl(); + case Stmt::DeclRefExprClass: { + const auto *L = cast<DeclRefExpr>(Left); + const auto *R = cast<DeclRefExpr>(Right); + + if (L->getDecl() != R->getDecl() || L->getFoundDecl() != R->getFoundDecl()) + return false; + + ASTContext &Ctx = L->getDecl()->getASTContext(); + const SourceManager &SM = Ctx.getSourceManager(); + const LangOptions &LO = Ctx.getLangOpts(); + + auto GetRawText = [&](SourceRange Range) -> StringRef { + if (Range.isInvalid()) + return ""; + return Lexer::getSourceText(CharSourceRange::getTokenRange(Range), SM, + LO); + }; + + if (L->hasQualifier() != R->hasQualifier()) + return false; + if (L->hasQualifier()) { + StringRef LQual = GetRawText(L->getQualifierLoc().getSourceRange()); + StringRef RQual = GetRawText(R->getQualifierLoc().getSourceRange()); + if (LQual != RQual) + return false; + } + + if (L->hasExplicitTemplateArgs() != R->hasExplicitTemplateArgs()) + return false; + if (L->hasExplicitTemplateArgs()) { + if (L->getNumTemplateArgs() != R->getNumTemplateArgs()) + return false; + for (unsigned I = 0, E = L->getNumTemplateArgs(); I != E; ++I) { + StringRef LArg = GetRawText(L->getTemplateArgs()[I].getSourceRange()); + StringRef RArg = GetRawText(R->getTemplateArgs()[I].getSourceRange()); + if (LArg != RArg) + return false; + } + } + return true; + } case Stmt::MemberExprClass: return cast<MemberExpr>(Left)->getMemberDecl() == cast<MemberExpr>(Right)->getMemberDecl(); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 89fb1684bba7c..c4f9b86bdd87c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -500,6 +500,11 @@ Changes in existing checks <clang-tidy/checks/misc/multiple-inheritance>` by avoiding false positives when virtual inheritance causes concrete bases to be counted more than once. +- Improved :doc:`misc-redundant-expression + <clang-tidy/checks/misc/redundant-expression>` check to avoid false + positives when comparing expressions that are structurally identical but + use different type aliases. + - Improved :doc:`misc-throw-by-value-catch-by-reference <clang-tidy/checks/misc/throw-by-value-catch-by-reference>` check: diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-type-aliases.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-type-aliases.cpp new file mode 100644 index 0000000000000..30a16e64fbac6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-type-aliases.cpp @@ -0,0 +1,26 @@ +// RUN: %check_clang_tidy -std=c++17-or-later %s misc-redundant-expression %t + +namespace std { +template <class T, int N> struct array {}; +template <class T> struct tuple_size; +template <class T, int N> struct tuple_size<array<T, N>> { + static constexpr int value = N; +}; +template <class T> constexpr int tuple_size_v = tuple_size<T>::value; +} // namespace std + +using MonthArray = std::array<int, 12>; +using ZodiacArray = std::array<int, 12>; + +void test() { + // False positive cases (Should NOT warn): + bool b1 = std::tuple_size<MonthArray>::value == std::tuple_size<ZodiacArray>::value; + bool b2 = std::tuple_size_v<MonthArray> == std::tuple_size_v<ZodiacArray>; + + // True positive cases (Should warn): + bool b3 = std::tuple_size<MonthArray>::value == std::tuple_size<MonthArray>::value; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: both sides of operator are equivalent [misc-redundant-expression] + + bool b4 = std::tuple_size_v<MonthArray> == std::tuple_size_v<MonthArray>; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: both sides of operator are equivalent [misc-redundant-expression] +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
