blob: d49c55e8f1f1cbc04faeed2f19f4c0c55e1f7924 [file] [log] [blame]
Alexander Kornienko1612fa02016-02-25 23:57:23 +00001//===- 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
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace readability {
18
19namespace {
20
21AST_MATCHER(StringLiteral, lengthIsZero) { return Node.getLength() == 0; }
22
Etienne Bergeron1329b982016-03-22 17:39:36 +000023AST_MATCHER_P(Expr, ignoringImplicit,
24 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
25 return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder);
26}
27
Alexander Kornienko1612fa02016-02-25 23:57:23 +000028} // namespace
29
30void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
31 if (!getLangOpts().CPlusPlus)
32 return;
33
Etienne Bergeron1329b982016-03-22 17:39:36 +000034 // 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()))));
Alexander Kornienko1612fa02016-02-25 23:57:23 +000043
Etienne Bergeron1329b982016-03-22 17:39:36 +000044 // 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("");
Alexander Kornienko1612fa02016-02-25 23:57:23 +000059 Finder->addMatcher(
60 namedDecl(varDecl(hasType(cxxRecordDecl(hasName("basic_string"))),
61 hasInitializer(
Etienne Bergeron1329b982016-03-22 17:39:36 +000062 expr(anyOf(EmptyStringCtorExpr,
63 EmptyStringCtorExprWithTemporaries))
64 .bind("expr"))))
Alexander Kornienko1612fa02016-02-25 23:57:23 +000065 .bind("decl"),
66 this);
67}
68
69void 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