1 //===- RedundantStringInitCheck.cpp - clang-tidy ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "RedundantStringInitCheck.h"
10 #include "../utils/Matchers.h"
11 #include "clang/ASTMatchers/ASTMatchers.h"
12 
13 using namespace clang::ast_matchers;
14 using namespace clang::tidy::matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace readability {
19 
20 void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
21   if (!getLangOpts().CPlusPlus)
22     return;
23 
24   // Match string constructor.
25   const auto StringConstructorExpr = expr(anyOf(
26       cxxConstructExpr(argumentCountIs(1),
27                        hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
28       // If present, the second argument is the alloc object which must not
29       // be present explicitly.
30       cxxConstructExpr(argumentCountIs(2),
31                        hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
32                        hasArgument(1, cxxDefaultArgExpr()))));
33 
34   // Match a string constructor expression with an empty string literal.
35   const auto EmptyStringCtorExpr = cxxConstructExpr(
36       StringConstructorExpr,
37       hasArgument(0, ignoringParenImpCasts(stringLiteral(hasSize(0)))));
38 
39   const auto EmptyStringCtorExprWithTemporaries =
40       cxxConstructExpr(StringConstructorExpr,
41                        hasArgument(0, ignoringImplicit(EmptyStringCtorExpr)));
42 
43   // Match a variable declaration with an empty string literal as initializer.
44   // Examples:
45   //     string foo = "";
46   //     string bar("");
47   Finder->addMatcher(
48       namedDecl(
49           varDecl(hasType(hasUnqualifiedDesugaredType(recordType(
50                       hasDeclaration(cxxRecordDecl(hasName("basic_string")))))),
51                   hasInitializer(expr(ignoringImplicit(anyOf(
52                                           EmptyStringCtorExpr,
53                                           EmptyStringCtorExprWithTemporaries)))
54                                      .bind("expr"))),
55           unless(parmVarDecl()))
56           .bind("decl"),
57       this);
58 }
59 
60 void RedundantStringInitCheck::check(const MatchFinder::MatchResult &Result) {
61   const auto *CtorExpr = Result.Nodes.getNodeAs<Expr>("expr");
62   const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl");
63   diag(CtorExpr->getExprLoc(), "redundant string initialization")
64       << FixItHint::CreateReplacement(CtorExpr->getSourceRange(),
65                                       Decl->getName());
66 }
67 
68 } // namespace readability
69 } // namespace tidy
70 } // namespace clang
71