1 //===- RedundantStringInitCheck.cpp - clang-tidy ----------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "RedundantStringInitCheck.h"
11 #include "clang/ASTMatchers/ASTMatchers.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace readability {
18 
19 namespace {
20 
21 AST_MATCHER(StringLiteral, lengthIsZero) { return Node.getLength() == 0; }
22 
23 AST_MATCHER_P(Expr, ignoringImplicit,
24               ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
25   return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder);
26 }
27 
28 } // namespace
29 
30 void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
31   if (!getLangOpts().CPlusPlus)
32     return;
33 
34   // Match string constructor.
35   const auto StringConstructorExpr = expr(anyOf(
36       cxxConstructExpr(argumentCountIs(1),
37                        hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
38       // If present, the second argument is the alloc object which must not
39       // be present explicitly.
40       cxxConstructExpr(argumentCountIs(2),
41                        hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
42                        hasArgument(1, cxxDefaultArgExpr()))));
43 
44   // Match a string constructor expression with an empty string literal.
45   const auto EmptyStringCtorExpr =
46       cxxConstructExpr(StringConstructorExpr,
47           hasArgument(0, ignoringParenImpCasts(
48                              stringLiteral(lengthIsZero()))));
49 
50   const auto EmptyStringCtorExprWithTemporaries =
51       expr(ignoringImplicit(
52           cxxConstructExpr(StringConstructorExpr,
53               hasArgument(0, ignoringImplicit(EmptyStringCtorExpr)))));
54 
55   // Match a variable declaration with an empty string literal as initializer.
56   // Examples:
57   //     string foo = "";
58   //     string bar("");
59   Finder->addMatcher(
60       namedDecl(varDecl(hasType(cxxRecordDecl(hasName("basic_string"))),
61                         hasInitializer(
62                             expr(anyOf(EmptyStringCtorExpr,
63                                        EmptyStringCtorExprWithTemporaries))
64                             .bind("expr"))))
65           .bind("decl"),
66       this);
67 }
68 
69 void RedundantStringInitCheck::check(const MatchFinder::MatchResult &Result) {
70   const auto *CtorExpr = Result.Nodes.getNodeAs<Expr>("expr");
71   const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl");
72   diag(CtorExpr->getExprLoc(), "redundant string initialization")
73       << FixItHint::CreateReplacement(CtorExpr->getSourceRange(),
74                                       Decl->getName());
75 }
76 
77 } // namespace readability
78 } // namespace tidy
79 } // namespace clang
80