1 //===--- NoexceptMoveConstructorCheck.cpp - clang-tidy---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NoexceptMoveConstructorCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace performance { 18 19 void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { 20 // Only register the matchers for C++11; the functionality currently does not 21 // provide any benefit to other languages, despite being benign. 22 if (!getLangOpts().CPlusPlus11) 23 return; 24 25 Finder->addMatcher( 26 cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")), 27 unless(isImplicit()), unless(isDeleted())) 28 .bind("decl"), 29 this); 30 } 31 32 void NoexceptMoveConstructorCheck::check( 33 const MatchFinder::MatchResult &Result) { 34 if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) { 35 StringRef MethodType = "assignment operator"; 36 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) { 37 if (!Ctor->isMoveConstructor()) 38 return; 39 MethodType = "constructor"; 40 } else if (!Decl->isMoveAssignmentOperator()) { 41 return; 42 } 43 44 const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>(); 45 46 if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType())) 47 return; 48 49 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) { 50 diag(Decl->getLocation(), "move %0s should be marked noexcept") 51 << MethodType; 52 // FIXME: Add a fixit. 53 return; 54 } 55 56 // Don't complain about nothrow(false), but complain on nothrow(expr) 57 // where expr evaluates to false. 58 if (ProtoType->canThrow() == CT_Can) { 59 Expr *E = ProtoType->getNoexceptExpr(); 60 E = E->IgnoreImplicit(); 61 if (!isa<CXXBoolLiteralExpr>(E)) { 62 diag(E->getExprLoc(), 63 "noexcept specifier on the move %0 evaluates to 'false'") 64 << MethodType; 65 } 66 } 67 } 68 } 69 70 } // namespace performance 71 } // namespace tidy 72 } // namespace clang 73