|  | //===--- InefficientStringConcatenationCheck.cpp - clang-tidy--------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "InefficientStringConcatenationCheck.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  |  | 
|  | using namespace clang::ast_matchers; | 
|  |  | 
|  | namespace clang { | 
|  | namespace tidy { | 
|  | namespace performance { | 
|  |  | 
|  | void InefficientStringConcatenationCheck::storeOptions( | 
|  | ClangTidyOptions::OptionMap &Opts) { | 
|  | Options.store(Opts, "StrictMode", StrictMode); | 
|  | } | 
|  |  | 
|  | InefficientStringConcatenationCheck::InefficientStringConcatenationCheck( | 
|  | StringRef Name, ClangTidyContext *Context) | 
|  | : ClangTidyCheck(Name, Context), | 
|  | StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {} | 
|  |  | 
|  | void InefficientStringConcatenationCheck::registerMatchers( | 
|  | MatchFinder *Finder) { | 
|  | if (!getLangOpts().CPlusPlus) | 
|  | return; | 
|  |  | 
|  | const auto BasicStringType = | 
|  | hasType(qualType(hasUnqualifiedDesugaredType(recordType( | 
|  | hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))))); | 
|  |  | 
|  | const auto BasicStringPlusOperator = cxxOperatorCallExpr( | 
|  | hasOverloadedOperatorName("+"), | 
|  | hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType)))); | 
|  |  | 
|  | const auto PlusOperator = | 
|  | cxxOperatorCallExpr( | 
|  | hasOverloadedOperatorName("+"), | 
|  | hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))), | 
|  | hasDescendant(BasicStringPlusOperator)) | 
|  | .bind("plusOperator"); | 
|  |  | 
|  | const auto AssignOperator = cxxOperatorCallExpr( | 
|  | hasOverloadedOperatorName("="), | 
|  | hasArgument(0, declRefExpr(BasicStringType, | 
|  | hasDeclaration(decl().bind("lhsStrT"))) | 
|  | .bind("lhsStr")), | 
|  | hasArgument(1, stmt(hasDescendant(declRefExpr( | 
|  | hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))), | 
|  | hasDescendant(BasicStringPlusOperator)); | 
|  |  | 
|  | if (StrictMode) { | 
|  | Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)), | 
|  | this); | 
|  | } else { | 
|  | Finder->addMatcher( | 
|  | cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator), | 
|  | hasAncestor(stmt(anyOf(cxxForRangeStmt(), | 
|  | whileStmt(), forStmt())))), | 
|  | this); | 
|  | } | 
|  | } | 
|  |  | 
|  | void InefficientStringConcatenationCheck::check( | 
|  | const MatchFinder::MatchResult &Result) { | 
|  | const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>("lhsStr"); | 
|  | const auto *PlusOperator = | 
|  | Result.Nodes.getNodeAs<CXXOperatorCallExpr>("plusOperator"); | 
|  | const auto DiagMsg = | 
|  | "string concatenation results in allocation of unnecessary temporary " | 
|  | "strings; consider using 'operator+=' or 'string::append()' instead"; | 
|  |  | 
|  | if (LhsStr) | 
|  | diag(LhsStr->getExprLoc(), DiagMsg); | 
|  | else if (PlusOperator) | 
|  | diag(PlusOperator->getExprLoc(), DiagMsg); | 
|  | } | 
|  |  | 
|  | } // namespace performance | 
|  | } // namespace tidy | 
|  | } // namespace clang |