15 #include "clang/Lex/Lexer.h"
17 using namespace clang::ast_matchers;
21 namespace readability {
26 StringRef getText(
const ast_matchers::MatchFinder::MatchResult &
Result,
28 return Lexer::getSourceText(
29 CharSourceRange::getTokenRange(Node.getSourceRange()),
30 *Result.SourceManager, Result.Context->getLangOpts());
36 bool needParensAfterUnaryOperator(
const Expr &ExprNode) {
37 if (isa<clang::BinaryOperator>(&ExprNode) ||
38 isa<clang::ConditionalOperator>(&ExprNode)) {
41 if (
const auto *Op = dyn_cast<CXXOperatorCallExpr>(&ExprNode)) {
42 return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
43 Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
44 Op->getOperator() != OO_Subscript;
52 formatDereference(
const ast_matchers::MatchFinder::MatchResult &Result,
53 const Expr &ExprNode) {
54 if (
const auto *Op = dyn_cast<clang::UnaryOperator>(&ExprNode)) {
55 if (Op->getOpcode() == UO_AddrOf) {
57 return getText(Result, *Op->getSubExpr()->IgnoreParens());
60 StringRef Text = getText(Result, ExprNode);
64 if (needParensAfterUnaryOperator(ExprNode)) {
65 return (llvm::Twine(
"*(") + Text +
")").str();
67 return (llvm::Twine(
"*") + Text).str();
72 void RedundantStringCStrCheck::registerMatchers(
73 ast_matchers::MatchFinder *
Finder) {
76 if (!getLangOpts().CPlusPlus)
80 const auto StringDecl =
81 cxxRecordDecl(hasName(
"::std::basic_string"));
82 const auto StringExpr =
83 expr(anyOf(hasType(StringDecl),
84 hasType(qualType(pointsTo(StringDecl)))));
87 const auto StringConstructorExpr = expr(anyOf(
90 hasDeclaration(cxxMethodDecl(hasName(
"basic_string")))),
93 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
96 hasArgument(1, cxxDefaultArgExpr()))));
99 const auto StringCStrCallExpr =
100 cxxMemberCallExpr(on(StringExpr.bind(
"arg")),
101 callee(memberExpr().bind(
"member")),
102 callee(cxxMethodDecl(hasName(
"c_str"))))
107 cxxConstructExpr(StringConstructorExpr,
108 hasArgument(0, StringCStrCallExpr)),
114 anyOf(hasOverloadedOperatorName(
"<"),
115 hasOverloadedOperatorName(
">"),
116 hasOverloadedOperatorName(
">="),
117 hasOverloadedOperatorName(
"<="),
118 hasOverloadedOperatorName(
"!="),
119 hasOverloadedOperatorName(
"=="),
120 hasOverloadedOperatorName(
"+")),
121 anyOf(allOf(hasArgument(0, StringExpr),
122 hasArgument(1, StringCStrCallExpr)),
123 allOf(hasArgument(0, StringCStrCallExpr),
124 hasArgument(1, StringExpr)))),
131 anyOf(hasOverloadedOperatorName(
"="),
132 hasOverloadedOperatorName(
"+=")),
133 hasArgument(0, StringExpr),
134 hasArgument(1, StringCStrCallExpr)),
139 cxxMemberCallExpr(on(StringExpr),
140 callee(decl(cxxMethodDecl(
141 hasAnyName(
"append",
"assign",
"compare")))),
143 hasArgument(0, StringCStrCallExpr)),
148 cxxMemberCallExpr(on(StringExpr),
149 callee(decl(cxxMethodDecl(hasName(
"compare")))),
151 hasArgument(2, StringCStrCallExpr)),
156 cxxMemberCallExpr(on(StringExpr),
157 callee(decl(cxxMethodDecl(
158 hasAnyName(
"find",
"find_first_not_of",
"find_first_of",
159 "find_last_not_of",
"find_last_of",
"rfind")))),
160 anyOf(argumentCountIs(1), argumentCountIs(2)),
161 hasArgument(0, StringCStrCallExpr)),
166 cxxMemberCallExpr(on(StringExpr),
167 callee(decl(cxxMethodDecl(hasName(
"insert")))),
169 hasArgument(1, StringCStrCallExpr)),
180 cxxMethodDecl(hasAnyName(
"::llvm::StringRef::StringRef",
181 "::llvm::Twine::Twine"))),
188 hasArgument(0, StringCStrCallExpr)),
192 void RedundantStringCStrCheck::check(
const MatchFinder::MatchResult &Result) {
193 const auto *Call = Result.Nodes.getStmtAs<CallExpr>(
"call");
194 const auto *Arg = Result.Nodes.getStmtAs<Expr>(
"arg");
195 bool Arrow = Result.Nodes.getStmtAs<MemberExpr>(
"member")->isArrow();
198 std::string ArgText =
199 Arrow ? formatDereference(Result, *Arg) : getText(Result, *Arg).str();
203 diag(Call->getLocStart(),
"redundant call to `c_str()`")
204 << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
std::unique_ptr< ast_matchers::MatchFinder > Finder