1 //===--- InefficientStringConcatenationCheck.cpp - clang-tidy--------------===// 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 "InefficientStringConcatenationCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace performance { 19 20 void InefficientStringConcatenationCheck::storeOptions( 21 ClangTidyOptions::OptionMap &Opts) { 22 Options.store(Opts, "StrictMode", StrictMode); 23 } 24 25 InefficientStringConcatenationCheck::InefficientStringConcatenationCheck( 26 StringRef Name, ClangTidyContext *Context) 27 : ClangTidyCheck(Name, Context), 28 StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {} 29 30 void InefficientStringConcatenationCheck::registerMatchers( 31 MatchFinder *Finder) { 32 if (!getLangOpts().CPlusPlus) 33 return; 34 35 const auto BasicStringType = 36 hasType(qualType(hasUnqualifiedDesugaredType(recordType( 37 hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))))); 38 39 const auto BasicStringPlusOperator = cxxOperatorCallExpr( 40 hasOverloadedOperatorName("+"), 41 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType)))); 42 43 const auto PlusOperator = 44 cxxOperatorCallExpr( 45 hasOverloadedOperatorName("+"), 46 hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))), 47 hasDescendant(BasicStringPlusOperator)) 48 .bind("plusOperator"); 49 50 const auto AssignOperator = cxxOperatorCallExpr( 51 hasOverloadedOperatorName("="), 52 hasArgument(0, declRefExpr(BasicStringType, 53 hasDeclaration(decl().bind("lhsStrT"))) 54 .bind("lhsStr")), 55 hasArgument(1, stmt(hasDescendant(declRefExpr( 56 hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))), 57 hasDescendant(BasicStringPlusOperator)); 58 59 if (StrictMode) { 60 Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)), 61 this); 62 } else { 63 Finder->addMatcher( 64 cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator), 65 hasAncestor(stmt(anyOf(cxxForRangeStmt(), 66 whileStmt(), forStmt())))), 67 this); 68 } 69 } 70 71 void InefficientStringConcatenationCheck::check( 72 const MatchFinder::MatchResult &Result) { 73 const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>("lhsStr"); 74 const auto *PlusOperator = 75 Result.Nodes.getNodeAs<CXXOperatorCallExpr>("plusOperator"); 76 const auto DiagMsg = 77 "string concatenation results in allocation of unnecessary temporary " 78 "strings; consider using 'operator+=' or 'string::append()' instead"; 79 80 if (LhsStr) 81 diag(LhsStr->getExprLoc(), DiagMsg); 82 else if (PlusOperator) 83 diag(PlusOperator->getExprLoc(), DiagMsg); 84 } 85 86 } // namespace performance 87 } // namespace tidy 88 } // namespace clang 89