1 //===--- ExplicitMakePairCheck.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 "ExplicitMakePairCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace { 19 AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) { 20 return Node.hasExplicitTemplateArgs(); 21 } 22 } // namespace 23 24 namespace tidy { 25 namespace google { 26 namespace build { 27 28 void ExplicitMakePairCheck::registerMatchers( 29 ast_matchers::MatchFinder *Finder) { 30 // Only register the matchers for C++; the functionality currently does not 31 // provide any benefit to other languages, despite being benign. 32 if (!getLangOpts().CPlusPlus) 33 return; 34 35 // Look for std::make_pair with explicit template args. Ignore calls in 36 // templates. 37 Finder->addMatcher( 38 callExpr(unless(isInTemplateInstantiation()), 39 callee(expr(ignoringParenImpCasts( 40 declRefExpr(hasExplicitTemplateArgs(), 41 to(functionDecl(hasName("::std::make_pair")))) 42 .bind("declref"))))) 43 .bind("call"), 44 this); 45 } 46 47 void ExplicitMakePairCheck::check(const MatchFinder::MatchResult &Result) { 48 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); 49 const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref"); 50 51 // Sanity check: The use might have overriden ::std::make_pair. 52 if (Call->getNumArgs() != 2) 53 return; 54 55 const Expr *Arg0 = Call->getArg(0)->IgnoreParenImpCasts(); 56 const Expr *Arg1 = Call->getArg(1)->IgnoreParenImpCasts(); 57 58 // If types don't match, we suggest replacing with std::pair and explicit 59 // template arguments. Otherwise just remove the template arguments from 60 // make_pair. 61 if (Arg0->getType() != Call->getArg(0)->getType() || 62 Arg1->getType() != Call->getArg(1)->getType()) { 63 diag(Call->getLocStart(), "for C++11-compatibility, use pair directly") 64 << FixItHint::CreateReplacement( 65 SourceRange(DeclRef->getLocStart(), DeclRef->getLAngleLoc()), 66 "std::pair<"); 67 } else { 68 diag(Call->getLocStart(), 69 "for C++11-compatibility, omit template arguments from make_pair") 70 << FixItHint::CreateRemoval( 71 SourceRange(DeclRef->getLAngleLoc(), DeclRef->getRAngleLoc())); 72 } 73 } 74 75 } // namespace build 76 } // namespace google 77 } // namespace tidy 78 } // namespace clang 79