Index: clang-tidy/performance/NoexceptMoveConstructorCheck.cpp =================================================================== --- clang-tidy/performance/NoexceptMoveConstructorCheck.cpp +++ clang-tidy/performance/NoexceptMoveConstructorCheck.cpp @@ -9,6 +9,7 @@ #include "NoexceptMoveConstructorCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -33,7 +34,7 @@ const MatchFinder::MatchResult &Result) { if (const auto *Decl = Result.Nodes.getNodeAs("decl")) { StringRef MethodType = "assignment operator"; - if (const auto *Ctor = dyn_cast(Decl)) { + if (const CXXConstructorDecl *Ctor = dyn_cast(Decl)) { if (!Ctor->isMoveConstructor()) return; MethodType = "constructor"; @@ -47,9 +48,20 @@ return; if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) { - diag(Decl->getLocation(), "move %0s should be marked noexcept") + auto Diag = + diag(Decl->getLocation(), "move %0s should be marked noexcept") << MethodType; - // FIXME: Add a fixit. + // Add FixIt hints. + SourceManager &SM = *Result.SourceManager; + assert(Decl->getNumParams() > 0); + SourceLocation NoexceptLoc = Decl->getParamDecl(Decl->getNumParams() - 1) + ->getSourceRange() + .getEnd(); + if (NoexceptLoc.isValid()) + NoexceptLoc = Lexer::findLocationAfterToken( + NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true); + if (NoexceptLoc.isValid()) + Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); return; } Index: test/clang-tidy/performance-noexcept-move-constructor-fix.cpp =================================================================== --- test/clang-tidy/performance-noexcept-move-constructor-fix.cpp +++ test/clang-tidy/performance-noexcept-move-constructor-fix.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t + +struct C_1 { + ~C_1() {} + C_1(int a) {} + C_1(C_1&& a) :C_1(5) {} + // CHECK-FIXES:{{.*}}noexcept{{.*}} + C_1& operator=(C_1&&) { return *this; } + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +struct C_2 { + ~C_2() {} + C_2(C_2&& a); + // CHECK-FIXES:{{.*}}noexcept{{.*}} + C_2& operator=(C_2&&); + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +C_2::C_2(C_2&& a) {} +// CHECK-FIXES:{{.*}}noexcept{{.*}} +C_2& C_2::operator=(C_2&&) { return *this; } +// CHECK-FIXES:{{.*}}noexcept{{.*}} + +struct C_4 { + ~C_4() {} + C_4(C_4&& a); + // CHECK-FIXES:{{.*}}noexcept{{.*}} + C_4& operator=(C_4&& a); + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +C_4::C_4(C_4&& a) = default; +// CHECK-FIXES:{{.*}}noexcept{{.*}} +C_4& C_4::operator=(C_4&& a) = default; +// CHECK-FIXES:{{.*}}noexcept{{.*}} + +template +struct C_5 { + C_5(C_5&&) {} + // CHECK-FIXES:{{.*}}noexcept{{.*}} + ~C_5() {} + C_5& operator=(C_5&& a) = default; + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +template +struct C_6 { + C_6(C_6&&) {} + // CHECK-FIXES:{{.*}}noexcept{{.*}} + ~C_6() {} + auto operator=(C_6&& a)->C_6 = default; + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +template +struct C_7 { + C_7(C_7&&) {} + // CHECK-FIXES:{{.*}}noexcept{{.*}} + ~C_7() {} + auto operator=(C_7&& a)->C_7; + // CHECK-FIXES:{{.*}}noexcept{{.*}} +}; + +template +auto C_7::operator=(C_7&& a) -> C_7 {} +// CHECK-FIXES:{{.*}}noexcept{{.*}}