84 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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 15using namespace clang::ast_matchers;16 17namespace clang::tidy::performance {18 19namespace {20 21AST_MATCHER(VarDecl, isNRVOVariable) { return Node.isNRVOVariable(); }22 23} // namespace24 25NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name,26 ClangTidyContext *Context)27 : ClangTidyCheck(Name, Context),28 AllowedTypes(29 utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}30 31void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {32 const auto NonNrvoConstLocalVariable =33 varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())),34 unless(isNRVOVariable()),35 hasType(qualType(36 isConstQualified(),37 hasCanonicalType(matchers::isExpensiveToCopy()),38 unless(hasDeclaration(namedDecl(39 matchers::matchesAnyListedName(AllowedTypes)))))))40 .bind("vardecl");41 42 // A matcher for a `DstT::DstT(const Src&)` where DstT also has a43 // `DstT::DstT(Src&&)`.44 const auto LValueRefCtor = cxxConstructorDecl(45 hasParameter(0, hasType(hasCanonicalType(46 lValueReferenceType(pointee(type().bind("SrcT")))))),47 ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(48 hasParameter(0, hasType(hasCanonicalType(rValueReferenceType(49 pointee(type(equalsBoundNode("SrcT"))))))))))));50 51 // A matcher for `DstT::DstT(const Src&&)`, which typically comes from an52 // instantiation of `template <typename U> DstT::DstT(U&&)`.53 const auto ConstRefRefCtor = cxxConstructorDecl(54 parameterCountIs(1),55 hasParameter(0,56 hasType(rValueReferenceType(pointee(isConstQualified())))));57 58 Finder->addMatcher(59 traverse(60 TK_AsIs,61 returnStmt(hasReturnValue(62 ignoringElidableConstructorCall(ignoringParenImpCasts(63 cxxConstructExpr(64 hasDeclaration(anyOf(LValueRefCtor, ConstRefRefCtor)),65 hasArgument(0, ignoringParenImpCasts(declRefExpr(66 to(NonNrvoConstLocalVariable)))))67 .bind("ctor_call")))))),68 this);69}70 71void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) {72 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("vardecl");73 const auto *CtorCall = Result.Nodes.getNodeAs<Expr>("ctor_call");74 diag(CtorCall->getExprLoc(), "constness of '%0' prevents automatic move")75 << Var->getName();76}77 78void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {79 Options.store(Opts, "AllowedTypes",80 utils::options::serializeStringList(AllowedTypes));81}82 83} // namespace clang::tidy::performance84