10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
17 namespace performance {
19 void InefficientStringConcatenationCheck::storeOptions(
21 Options.store(Opts,
"StrictMode", StrictMode);
24 InefficientStringConcatenationCheck::InefficientStringConcatenationCheck(
27 StrictMode(Options.getLocalOrGlobal(
"StrictMode", false)) {}
30 MatchFinder *Finder) {
31 const auto BasicStringType =
32 hasType(qualType(hasUnqualifiedDesugaredType(recordType(
33 hasDeclaration(cxxRecordDecl(hasName(
"::std::basic_string")))))));
35 const auto BasicStringPlusOperator = cxxOperatorCallExpr(
36 hasOverloadedOperatorName(
"+"),
37 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))));
39 const auto PlusOperator =
41 hasOverloadedOperatorName(
"+"),
42 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))),
43 hasDescendant(BasicStringPlusOperator))
44 .bind(
"plusOperator");
46 const auto AssignOperator = cxxOperatorCallExpr(
47 hasOverloadedOperatorName(
"="),
48 hasArgument(0, declRefExpr(BasicStringType,
49 hasDeclaration(decl().bind(
"lhsStrT")))
51 hasArgument(1, stmt(hasDescendant(declRefExpr(
52 hasDeclaration(decl(equalsBoundNode(
"lhsStrT"))))))),
53 hasDescendant(BasicStringPlusOperator));
56 Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)),
60 cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator),
61 hasAncestor(stmt(anyOf(cxxForRangeStmt(),
62 whileStmt(), forStmt())))),
68 const MatchFinder::MatchResult &Result) {
69 const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>(
"lhsStr");
70 const auto *PlusOperator =
71 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"plusOperator");
73 "string concatenation results in allocation of unnecessary temporary "
74 "strings; consider using 'operator+=' or 'string::append()' instead";
77 diag(LhsStr->getExprLoc(), DiagMsg);
78 else if (PlusOperator)
79 diag(PlusOperator->getExprLoc(), DiagMsg);