1 //===--- NoexceptMoveConstructorCheck.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 "NoexceptMoveConstructorCheck.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 NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { 21 // Only register the matchers for C++11; the functionality currently does not 22 // provide any benefit to other languages, despite being benign. 23 if (!getLangOpts().CPlusPlus11) 24 return; 25 26 Finder->addMatcher( 27 cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")), 28 unless(isImplicit()), unless(isDeleted())) 29 .bind("decl"), 30 this); 31 } 32 33 void NoexceptMoveConstructorCheck::check( 34 const MatchFinder::MatchResult &Result) { 35 if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) { 36 StringRef MethodType = "assignment operator"; 37 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) { 38 if (!Ctor->isMoveConstructor()) 39 return; 40 MethodType = "constructor"; 41 } else if (!Decl->isMoveAssignmentOperator()) { 42 return; 43 } 44 45 const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>(); 46 47 if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType())) 48 return; 49 50 switch (ProtoType->getNoexceptSpec(*Result.Context)) { 51 case FunctionProtoType::NR_NoNoexcept: 52 diag(Decl->getLocation(), "move %0s should be marked noexcept") 53 << MethodType; 54 // FIXME: Add a fixit. 55 break; 56 case FunctionProtoType::NR_Throw: 57 // Don't complain about nothrow(false), but complain on nothrow(expr) 58 // where expr evaluates to false. 59 if (const Expr *E = ProtoType->getNoexceptExpr()) { 60 if (isa<CXXBoolLiteralExpr>(E)) 61 break; 62 diag(E->getExprLoc(), 63 "noexcept specifier on the move %0 evaluates to 'false'") 64 << MethodType; 65 } 66 break; 67 case FunctionProtoType::NR_Nothrow: 68 case FunctionProtoType::NR_Dependent: 69 case FunctionProtoType::NR_BadNoexcept: 70 break; 71 } 72 } 73 } 74 75 } // namespace performance 76 } // namespace tidy 77 } // namespace clang 78