summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2015-03-16 00:32:25 +0000
committerAlexander Kornienko <alexfh@google.com>2015-03-16 00:32:25 +0000
commit57a5c6b56c782d578d86cbf2e58bb403719afdee (patch)
tree640406129f00eb22d7ed054a054bf4c32f60397d /clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
parent208caf22d97e0ad26c7c5dffed1a371c2dbb3a48 (diff)
downloadbcm5719-llvm-57a5c6b56c782d578d86cbf2e58bb403719afdee.tar.gz
bcm5719-llvm-57a5c6b56c782d578d86cbf2e58bb403719afdee.zip
Move remove-cstr-calls from a standalone executable to a clang-tidy check readability-redundant-string-cstr
http://reviews.llvm.org/D7318 Patch by Richard Thomson! llvm-svn: 232338
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
new file mode 100644
index 00000000000..70819951c3f
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -0,0 +1,138 @@
+//===- RedundantStringCStrCheck.cpp - Check for redundant c_str calls -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a check for redundant calls of c_str() on strings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantStringCStrCheck.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+
+using namespace ast_matchers;
+
+namespace {
+
+template <typename T>
+StringRef getText(const ast_matchers::MatchFinder::MatchResult &Result,
+ T const &Node) {
+ return Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Node.getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts());
+}
+
+// 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<clang::BinaryOperator>(&ExprNode) ||
+ isa<clang::ConditionalOperator>(&ExprNode)) {
+ return true;
+ }
+ if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(&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<clang::UnaryOperator>(&ExprNode)) {
+ if (Op->getOpcode() == UO_AddrOf) {
+ // Strip leading '&'.
+ return getText(Result, *Op->getSubExpr()->IgnoreParens());
+ }
+ }
+ StringRef Text = getText(Result, ExprNode);
+ if (Text.empty())
+ return std::string();
+ // Add leading '*'.
+ if (needParensAfterUnaryOperator(ExprNode)) {
+ return (llvm::Twine("*(") + Text + ")").str();
+ }
+ return (llvm::Twine("*") + Text).str();
+}
+
+const char StringConstructor[] =
+ "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
+ "::basic_string";
+
+const char StringCStrMethod[] =
+ "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
+ "::c_str";
+
+} // end namespace
+
+namespace tidy {
+namespace readability {
+
+void RedundantStringCStrCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(
+ constructExpr(
+ hasDeclaration(methodDecl(hasName(StringConstructor))),
+ argumentCountIs(2),
+ // The first argument must have the form x.c_str() or p->c_str()
+ // where the method is string::c_str(). We can use the copy
+ // constructor of string instead (or the compiler might share
+ // the string object).
+ hasArgument(
+ 0, memberCallExpr(callee(memberExpr().bind("member")),
+ callee(methodDecl(hasName(StringCStrMethod))),
+ on(expr().bind("arg"))).bind("call")),
+ // The second argument is the alloc object which must not be
+ // present explicitly.
+ hasArgument(1, defaultArgExpr())),
+ this);
+ Finder->addMatcher(
+ constructExpr(
+ // Implicit constructors of these classes are overloaded
+ // wrt. string types and they internally make a StringRef
+ // referring to the argument. Passing a string directly to
+ // them is preferred to passing a char pointer.
+ hasDeclaration(
+ methodDecl(anyOf(hasName("::llvm::StringRef::StringRef"),
+ hasName("::llvm::Twine::Twine")))),
+ argumentCountIs(1),
+ // The only argument must have the form x.c_str() or p->c_str()
+ // where the method is string::c_str(). StringRef also has
+ // a constructor from string which is more efficient (avoids
+ // strlen), so we can construct StringRef from the string
+ // directly.
+ hasArgument(
+ 0, memberCallExpr(callee(memberExpr().bind("member")),
+ callee(methodDecl(hasName(StringCStrMethod))),
+ on(expr().bind("arg"))).bind("call"))),
+ this);
+}
+
+void RedundantStringCStrCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getStmtAs<CallExpr>("call");
+ const auto *Arg = Result.Nodes.getStmtAs<Expr>("arg");
+ bool Arrow = Result.Nodes.getStmtAs<MemberExpr>("member")->isArrow();
+ // Replace the "call" node with the "arg" node, prefixed with '*'
+ // if the call was using '->' rather than '.'.
+ std::string ArgText =
+ Arrow ? formatDereference(Result, *Arg) : getText(Result, *Arg).str();
+ if (ArgText.empty())
+ return;
+
+ diag(Call->getLocStart(), "redundant call to `c_str()`")
+ << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
OpenPOWER on IntegriCloud