1 //===--- NoAutomaticMoveCheck.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 "NoAutomaticMoveCheck.h" 10 #include "../utils/Matchers.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace performance { 20 21 NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name, 22 ClangTidyContext *Context) 23 : ClangTidyCheck(Name, Context), 24 AllowedTypes( 25 utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} 26 27 void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) { 28 const auto ConstLocalVariable = 29 varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())), 30 hasType(qualType( 31 isConstQualified(), 32 hasCanonicalType(matchers::isExpensiveToCopy()), 33 unless(hasDeclaration(namedDecl( 34 matchers::matchesAnyListedName(AllowedTypes))))))) 35 .bind("vardecl"); 36 37 // A matcher for a `DstT::DstT(const Src&)` where DstT also has a 38 // `DstT::DstT(Src&&)`. 39 const auto LValueRefCtor = cxxConstructorDecl( 40 hasParameter(0, 41 hasType(lValueReferenceType(pointee(type().bind("SrcT"))))), 42 ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl( 43 hasParameter(0, hasType(rValueReferenceType( 44 pointee(type(equalsBoundNode("SrcT"))))))))))); 45 46 Finder->addMatcher( 47 traverse(TK_AsIs, 48 returnStmt(hasReturnValue( 49 ignoringElidableConstructorCall(ignoringParenImpCasts( 50 cxxConstructExpr( 51 hasDeclaration(LValueRefCtor), 52 hasArgument(0, ignoringParenImpCasts(declRefExpr( 53 to(ConstLocalVariable))))) 54 .bind("ctor_call")))))), 55 this); 56 } 57 58 void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) { 59 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("vardecl"); 60 const auto *CtorCall = Result.Nodes.getNodeAs<Expr>("ctor_call"); 61 diag(CtorCall->getExprLoc(), "constness of '%0' prevents automatic move") 62 << Var->getName(); 63 } 64 65 void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 66 Options.store(Opts, "AllowedTypes", 67 utils::options::serializeStringList(AllowedTypes)); 68 } 69 70 } // namespace performance 71 } // namespace tidy 72 } // namespace clang 73