//===--- NoAutomaticMoveCheck.cpp - clang-tidy ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "NoAutomaticMoveCheck.h" #include "../utils/Matchers.h" #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace performance { NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), AllowedTypes( utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) { const auto ConstLocalVariable = varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())), hasType(qualType( isConstQualified(), hasCanonicalType(matchers::isExpensiveToCopy()), unless(hasDeclaration(namedDecl( matchers::matchesAnyListedName(AllowedTypes))))))) .bind("vardecl"); // A matcher for a `DstT::DstT(const Src&)` where DstT also has a // `DstT::DstT(Src&&)`. const auto LValueRefCtor = cxxConstructorDecl( hasParameter(0, hasType(lValueReferenceType(pointee(type().bind("SrcT"))))), ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl( hasParameter(0, hasType(rValueReferenceType( pointee(type(equalsBoundNode("SrcT"))))))))))); Finder->addMatcher( traverse(ast_type_traits::TK_AsIs, returnStmt(hasReturnValue( ignoringElidableConstructorCall(ignoringParenImpCasts( cxxConstructExpr( hasDeclaration(LValueRefCtor), hasArgument(0, ignoringParenImpCasts(declRefExpr( to(ConstLocalVariable))))) .bind("ctor_call")))))), this); } void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) { const auto *Var = Result.Nodes.getNodeAs("vardecl"); const auto *CtorCall = Result.Nodes.getNodeAs("ctor_call"); diag(CtorCall->getExprLoc(), "constness of '%0' prevents automatic move") << Var->getName(); } void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AllowedTypes", utils::options::serializeStringList(AllowedTypes)); } } // namespace performance } // namespace tidy } // namespace clang