27 MatchFinder *Finder) {
28 const auto BasicStringType =
29 hasType(qualType(hasUnqualifiedDesugaredType(recordType(
30 hasDeclaration(cxxRecordDecl(hasName(
"::std::basic_string")))))));
32 const auto BasicStringPlusOperator = cxxOperatorCallExpr(
33 hasOverloadedOperatorName(
"+"),
34 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))));
36 const auto PlusOperator =
38 hasOverloadedOperatorName(
"+"),
39 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))),
40 hasDescendant(BasicStringPlusOperator))
41 .bind(
"plusOperator");
43 const auto AssignOperator = cxxOperatorCallExpr(
44 hasOverloadedOperatorName(
"="),
45 hasArgument(0, declRefExpr(BasicStringType,
46 hasDeclaration(decl().bind(
"lhsStrT")))
48 hasArgument(1, stmt(hasDescendant(declRefExpr(
49 hasDeclaration(decl(equalsBoundNode(
"lhsStrT"))))))),
50 hasDescendant(BasicStringPlusOperator));
53 Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)),
57 cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator),
58 hasAncestor(stmt(anyOf(cxxForRangeStmt(),
59 whileStmt(), forStmt())))),
65 const MatchFinder::MatchResult &Result) {
66 const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>(
"lhsStr");
67 const auto *PlusOperator =
68 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"plusOperator");
70 "string concatenation results in allocation of unnecessary temporary "
71 "strings; consider using 'operator+=' or 'string::append()' instead";
74 diag(LhsStr->getExprLoc(), DiagMsg);
75 else if (PlusOperator)
76 diag(PlusOperator->getExprLoc(), DiagMsg);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.