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 = cxxRecordDecl(hasName(
"::std::basic_string"));
81 const auto StringExpr =
82 expr(anyOf(hasType(StringDecl), hasType(qualType(pointsTo(StringDecl)))));
85 const auto StringConstructorExpr = expr(anyOf(
86 cxxConstructExpr(argumentCountIs(1),
87 hasDeclaration(cxxMethodDecl(hasName(
"basic_string")))),
90 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
93 hasArgument(1, cxxDefaultArgExpr()))));
96 const auto StringCStrCallExpr =
97 cxxMemberCallExpr(on(StringExpr.bind(
"arg")),
98 callee(memberExpr().bind(
"member")),
99 callee(cxxMethodDecl(hasAnyName(
"c_str",
"data"))))
103 Finder->addMatcher(cxxConstructExpr(StringConstructorExpr,
104 hasArgument(0, StringCStrCallExpr)),
111 hasOverloadedOperatorName(
"<"), hasOverloadedOperatorName(
">"),
112 hasOverloadedOperatorName(
">="), hasOverloadedOperatorName(
"<="),
113 hasOverloadedOperatorName(
"!="), hasOverloadedOperatorName(
"=="),
114 hasOverloadedOperatorName(
"+")),
115 anyOf(allOf(hasArgument(0, StringExpr),
116 hasArgument(1, StringCStrCallExpr)),
117 allOf(hasArgument(0, StringCStrCallExpr),
118 hasArgument(1, StringExpr)))),
123 Finder->addMatcher(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName(
"="),
124 hasOverloadedOperatorName(
"+=")),
125 hasArgument(0, StringExpr),
126 hasArgument(1, StringCStrCallExpr)),
131 cxxMemberCallExpr(on(StringExpr), callee(decl(cxxMethodDecl(hasAnyName(
132 "append",
"assign",
"compare")))),
133 argumentCountIs(1), hasArgument(0, StringCStrCallExpr)),
138 cxxMemberCallExpr(on(StringExpr),
139 callee(decl(cxxMethodDecl(hasName(
"compare")))),
140 argumentCountIs(3), hasArgument(2, StringCStrCallExpr)),
145 cxxMemberCallExpr(on(StringExpr),
146 callee(decl(cxxMethodDecl(hasAnyName(
147 "find",
"find_first_not_of",
"find_first_of",
148 "find_last_not_of",
"find_last_of",
"rfind")))),
149 anyOf(argumentCountIs(1), argumentCountIs(2)),
150 hasArgument(0, StringCStrCallExpr)),
155 cxxMemberCallExpr(on(StringExpr),
156 callee(decl(cxxMethodDecl(hasName(
"insert")))),
157 argumentCountIs(2), hasArgument(1, StringCStrCallExpr)),
167 hasDeclaration(cxxMethodDecl(hasAnyName(
168 "::llvm::StringRef::StringRef",
"::llvm::Twine::Twine"))),
175 hasArgument(0, StringCStrCallExpr)),
179 void RedundantStringCStrCheck::check(
const MatchFinder::MatchResult &Result) {
180 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
181 const auto *Arg = Result.Nodes.getNodeAs<Expr>(
"arg");
182 const auto *Member = Result.Nodes.getNodeAs<MemberExpr>(
"member");
183 bool Arrow = Member->isArrow();
186 std::string ArgText =
187 Arrow ? formatDereference(Result, *Arg) : getText(Result, *Arg).str();
191 diag(Call->getLocStart(),
"redundant call to %0")
192 << Member->getMemberDecl()
193 << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
std::unique_ptr< ast_matchers::MatchFinder > Finder