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 #include "clang/Lex/Lexer.h" 13 #include "clang/Tooling/FixIt.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace performance { 20 21 void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { 22 Finder->addMatcher( 23 cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")), 24 unless(isImplicit()), unless(isDeleted())) 25 .bind("decl"), 26 this); 27 } 28 29 void NoexceptMoveConstructorCheck::check( 30 const MatchFinder::MatchResult &Result) { 31 if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) { 32 bool IsConstructor = false; 33 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) { 34 if (!Ctor->isMoveConstructor()) 35 return; 36 IsConstructor = true; 37 } else if (!Decl->isMoveAssignmentOperator()) { 38 return; 39 } 40 41 const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>(); 42 43 if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType())) 44 return; 45 46 if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) { 47 auto Diag = diag(Decl->getLocation(), 48 "move %select{assignment operator|constructor}0s should " 49 "be marked noexcept") 50 << IsConstructor; 51 // Add FixIt hints. 52 SourceManager &SM = *Result.SourceManager; 53 assert(Decl->getNumParams() > 0); 54 SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1) 55 ->getSourceRange() 56 .getEnd(); 57 if (NoexceptLoc.isValid()) 58 NoexceptLoc = Lexer::findLocationAfterToken( 59 NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true); 60 if (NoexceptLoc.isValid()) 61 Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); 62 return; 63 } 64 65 // Don't complain about nothrow(false), but complain on nothrow(expr) 66 // where expr evaluates to false. 67 if (ProtoType->canThrow() == CT_Can) { 68 Expr *E = ProtoType->getNoexceptExpr(); 69 E = E->IgnoreImplicit(); 70 if (!isa<CXXBoolLiteralExpr>(E)) { 71 diag(E->getExprLoc(), 72 "noexcept specifier on the move %select{assignment " 73 "operator|constructor}0 evaluates to 'false'") 74 << IsConstructor; 75 } 76 } 77 } 78 } 79 80 } // namespace performance 81 } // namespace tidy 82 } // namespace clang 83