Author: Zeyi Xu Date: 2026-06-23T19:06:04+08:00 New Revision: 3abbf06dd15df2288de06749f0bb8dddc4189294
URL: https://github.com/llvm/llvm-project/commit/3abbf06dd15df2288de06749f0bb8dddc4189294 DIFF: https://github.com/llvm/llvm-project/commit/3abbf06dd15df2288de06749f0bb8dddc4189294.diff LOG: [clang-tidy] Avoid token merging in redundant-parentheses fix-its (#202365) The readability-redundant-parentheses check emitted fix-its that simply removed both parentheses. Tools that apply those fix-its directly could join adjacent tokens and produce invalid code, e.g. `return(0)` becoming `return0`. Replace the opening parenthesis with a space when removing it would merge identifier characters across the removed token. AI Usage: Test assisted by Codex. Closes https://github.com/llvm/llvm-project/issues/185108 Added: Modified: clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp clang-tools-extra/docs/ReleaseNotes.rst Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp index c177c07b95a75..639e183f434b2 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp @@ -13,6 +13,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" +#include "clang/Lex/Lexer.h" #include <cassert> using namespace clang::ast_matchers; @@ -34,6 +35,23 @@ AST_MATCHER(ParenExpr, isInMacro) { } // namespace +static FixItHint createSpacedRemoval(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + if (Loc.isValid() && !Loc.isMacroID()) { + auto LocInfo = SM.getDecomposedLoc(Loc); + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (!Invalid && LocInfo.second > 0 && LocInfo.second + 1 < Buffer.size() && + Lexer::isAsciiIdentifierContinueChar(Buffer[LocInfo.second - 1], + LangOpts) && + Lexer::isAsciiIdentifierContinueChar(Buffer[LocInfo.second + 1], + LangOpts)) + return FixItHint::CreateReplacement(SourceRange(Loc, Loc), " "); + } + return FixItHint::CreateRemoval(Loc); +} + RedundantParenthesesCheck::RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -66,7 +84,8 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) { void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) { const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup"); diag(PE->getBeginLoc(), "redundant parentheses around expression") - << FixItHint::CreateRemoval(PE->getLParen()) + << createSpacedRemoval(PE->getLParen(), *Result.SourceManager, + getLangOpts()) << FixItHint::CreateRemoval(PE->getRParen()); } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 4258f7faf34fd..6d91ac1ef1e8e 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -359,6 +359,29 @@ TEST(DiagnosticsTest, ClangTidy) { "function 'bar' is within a recursive call chain")))); } +TEST(DiagnosticsTest, ClangTidyRedundantParenthesesFix) { + Annotations Test(R"cpp( + int func() { + return$lparen[[(]]0$rparen[[)]]; + } + )cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.ClangTidyProvider = addTidyChecks("readability-redundant-parentheses"); + + clangd::Fix ExpectedFix; + ExpectedFix.Message = "redundant parentheses around expression"; + ExpectedFix.Edits.push_back(TextEdit{Test.range("lparen"), " "}); + ExpectedFix.Edits.push_back(TextEdit{Test.range("rparen"), ""}); + + EXPECT_THAT( + TU.build().getDiagnostics(), + ifTidyChecks(ElementsAre(AllOf( + Diag(Test.range("lparen"), "redundant parentheses around expression"), + diagSource(Diag::ClangTidy), + diagName("readability-redundant-parentheses"), + withFix(equalToFix(ExpectedFix)))))); +} + TEST(DiagnosticsTest, ClangTidyEOF) { // clang-format off Annotations Test(R"cpp( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index bbd4f8f5b3c58..8871b37ddb1bf 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -848,9 +848,13 @@ Changes in existing checks macros that may expand diff erently in other configurations. - Improved :doc:`readability-redundant-parentheses - <clang-tidy/checks/readability/redundant-parentheses>` check by fixing a - false positive for parentheses present around an overloaded operator in the - context of a binary operation. + <clang-tidy/checks/readability/redundant-parentheses>` check: + + - Fixed a false positive for parentheses present around an overloaded operator + in the context of a binary operation. + + - Fixed a bug where clients that apply fix-its without :program:`clang-tidy`'s + cleanup could produce invalid code by joining adjacent tokens. - Improved :doc:`readability-redundant-preprocessor <clang-tidy/checks/readability/redundant-preprocessor>` check by fixing a _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
