diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "RedundantStringCStrCheck.h" +#include "../utils/FixItHintUtils.h" #include "../utils/Matchers.h" #include "../utils/OptionsUtils.h" #include "clang/Lex/Lexer.h" @@ -22,49 +23,6 @@ namespace { -// Return true if expr needs to be put in parens when it is an argument of a -// prefix unary operator, e.g. when it is a binary or ternary operator -// syntactically. -bool needParensAfterUnaryOperator(const Expr &ExprNode) { - if (isa(&ExprNode) || - isa(&ExprNode)) { - return true; - } - if (const auto *Op = dyn_cast(&ExprNode)) { - return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus && - Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call && - Op->getOperator() != OO_Subscript; - } - return false; -} - -// Format a pointer to an expression: prefix with '*' but simplify -// when it already begins with '&'. Return empty string on failure. -std::string -formatDereference(const ast_matchers::MatchFinder::MatchResult &Result, - const Expr &ExprNode) { - if (const auto *Op = dyn_cast(&ExprNode)) { - if (Op->getOpcode() == UO_AddrOf) { - // Strip leading '&'. - return std::string(tooling::fixit::getText( - *Op->getSubExpr()->IgnoreParens(), *Result.Context)); - } - } - StringRef Text = tooling::fixit::getText(ExprNode, *Result.Context); - - if (Text.empty()) - return std::string(); - - // Remove remaining '->' from overloaded operator call - Text.consume_back("->"); - - // Add leading '*'. - if (needParensAfterUnaryOperator(ExprNode)) { - return (llvm::Twine("*(") + Text + ")").str(); - } - return (llvm::Twine("*") + Text).str(); -} - AST_MATCHER(MaterializeTemporaryExpr, isBoundToLValue) { return Node.isBoundToLvalueReference(); } @@ -217,7 +175,7 @@ // Replace the "call" node with the "arg" node, prefixed with '*' // if the call was using '->' rather than '.'. std::string ArgText = - Arrow ? formatDereference(Result, *Arg) + Arrow ? utils::fixit::formatDereference(*Arg, *Result.Context) : tooling::fixit::getText(*Arg, *Result.Context).str(); if (ArgText.empty()) return; diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -37,5 +37,6 @@ clangBasic clangLex clangSema + clangTooling clangTransformer ) diff --git a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h --- a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h +++ b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h @@ -44,6 +44,9 @@ DeclSpec::TQ Qualifier, QualifierTarget CT = QualifierTarget::Pointee, QualifierPolicy CP = QualifierPolicy::Left); + +// \brief Format a pointer to an expression +std::string formatDereference(const Expr &ExprNode, const ASTContext &Context); } // namespace clang::tidy::utils::fixit #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H diff --git a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp --- a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp @@ -9,7 +9,9 @@ #include "FixItHintUtils.h" #include "LexerUtils.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" +#include "clang/Tooling/FixIt.h" #include namespace clang::tidy::utils::fixit { @@ -221,4 +223,46 @@ return std::nullopt; } + +// Return true if expr needs to be put in parens when it is an argument of a +// prefix unary operator, e.g. when it is a binary or ternary operator +// syntactically. +static bool needParensAfterUnaryOperator(const Expr &ExprNode) { + if (isa(&ExprNode) || + isa(&ExprNode)) { + return true; + } + if (const auto *Op = dyn_cast(&ExprNode)) { + return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus && + Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call && + Op->getOperator() != OO_Subscript; + } + return false; +} + +// 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) { + if (const auto *Op = dyn_cast(&ExprNode)) { + if (Op->getOpcode() == UO_AddrOf) { + // Strip leading '&'. + return std::string( + tooling::fixit::getText(*Op->getSubExpr()->IgnoreParens(), Context)); + } + } + StringRef Text = tooling::fixit::getText(ExprNode, Context); + + if (Text.empty()) + return std::string(); + + // Remove remaining '->' from overloaded operator call + Text.consume_back("->"); + + // Add leading '*'. + if (needParensAfterUnaryOperator(ExprNode)) { + return (llvm::Twine("*(") + Text + ")").str(); + } + return (llvm::Twine("*") + Text).str(); +} + } // namespace clang::tidy::utils::fixit