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
NoAutomaticMoveCheck(StringRef Name,ClangTidyContext * Context)21 NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name,
22 ClangTidyContext *Context)
23 : ClangTidyCheck(Name, Context),
24 AllowedTypes(
25 utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
26
registerMatchers(MatchFinder * Finder)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(ast_type_traits::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
check(const MatchFinder::MatchResult & Result)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
storeOptions(ClangTidyOptions::OptionMap & Opts)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