brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.8 KiB · d1d81d5 Raw
162 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 "MissingStdForwardCheck.h"10#include "../utils/Matchers.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13#include "clang/Basic/IdentifierTable.h"14 15using namespace clang::ast_matchers;16 17namespace clang::tidy::cppcoreguidelines {18 19namespace {20 21using matchers::hasUnevaluatedContext;22 23AST_MATCHER_P(QualType, possiblyPackExpansionOf,24              ast_matchers::internal::Matcher<QualType>, InnerMatcher) {25  return InnerMatcher.matches(Node.getNonPackExpansionType(), Finder, Builder);26}27 28AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {29  const ast_matchers::internal::Matcher<QualType> Inner =30      possiblyPackExpansionOf(31          qualType(rValueReferenceType(),32                   references(templateTypeParmType(33                       hasDeclaration(templateTypeParmDecl()))),34                   unless(references(qualType(isConstQualified())))));35  if (!Inner.matches(Node.getType(), Finder, Builder))36    return false;37 38  const auto *Function = dyn_cast<FunctionDecl>(Node.getDeclContext());39  if (!Function)40    return false;41 42  const FunctionTemplateDecl *FuncTemplate =43      Function->getDescribedFunctionTemplate();44  if (!FuncTemplate)45    return false;46 47  const QualType ParamType =48      Node.getType().getNonPackExpansionType()->getPointeeType();49  const auto *TemplateType = ParamType->getAsCanonical<TemplateTypeParmType>();50  if (!TemplateType)51    return false;52 53  return TemplateType->getDepth() ==54         FuncTemplate->getTemplateParameters()->getDepth();55}56 57AST_MATCHER_P(NamedDecl, hasSameNameAsBoundNode, std::string, BindingID) {58  const IdentifierInfo *II = Node.getIdentifier();59  if (nullptr == II)60    return false;61  const StringRef Name = II->getName();62 63  return Builder->removeBindings(64      [this, Name](const ast_matchers::internal::BoundNodesMap &Nodes) {65        const DynTypedNode &BN = Nodes.getNode(this->BindingID);66        if (const auto *ND = BN.get<NamedDecl>()) {67          if (!isa<FieldDecl, CXXMethodDecl, VarDecl>(ND))68            return true;69          return ND->getName() != Name;70        }71        return true;72      });73}74 75AST_MATCHER_P(LambdaCapture, hasCaptureKind, LambdaCaptureKind, Kind) {76  return Node.getCaptureKind() == Kind;77}78 79AST_MATCHER_P(LambdaExpr, hasCaptureDefaultKind, LambdaCaptureDefault, Kind) {80  return Node.getCaptureDefault() == Kind;81}82 83AST_MATCHER(VarDecl, hasIdentifier) {84  const IdentifierInfo *ID = Node.getIdentifier();85  return ID != nullptr && !ID->isPlaceholder();86}87 88} // namespace89 90void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {91  auto RefToParmImplicit = allOf(92      equalsBoundNode("var"), hasInitializer(ignoringParenImpCasts(93                                  declRefExpr(to(equalsBoundNode("param"))))));94  auto RefToParm = capturesVar(95      varDecl(anyOf(hasSameNameAsBoundNode("param"), RefToParmImplicit)));96 97  auto CaptureInRef =98      allOf(hasCaptureDefaultKind(LambdaCaptureDefault::LCD_ByRef),99            unless(hasAnyCapture(100                capturesVar(varDecl(hasSameNameAsBoundNode("param"))))));101  auto CaptureByRefExplicit = hasAnyCapture(102      allOf(hasCaptureKind(LambdaCaptureKind::LCK_ByRef), RefToParm));103 104  auto CapturedInBody = lambdaExpr(anyOf(CaptureInRef, CaptureByRefExplicit));105  auto CapturedInCaptureList = hasAnyCapture(capturesVar(106      varDecl(hasInitializer(ignoringParenImpCasts(equalsBoundNode("call"))))));107 108  auto CapturedInLambda = hasDeclContext(cxxRecordDecl(109      isLambda(),110      hasParent(lambdaExpr(forCallable(equalsBoundNode("func")),111                           anyOf(CapturedInCaptureList, CapturedInBody)))));112 113  auto ToParam = hasAnyParameter(parmVarDecl(equalsBoundNode("param")));114 115  auto ForwardCallMatcher = callExpr(116      callExpr().bind("call"), argumentCountIs(1),117      hasArgument(0, declRefExpr(to(varDecl().bind("var")))),118      forCallable(119          anyOf(allOf(equalsBoundNode("func"),120                      functionDecl(hasAnyParameter(parmVarDecl(allOf(121                          equalsBoundNode("param"), equalsBoundNode("var")))))),122                CapturedInLambda)),123      callee(unresolvedLookupExpr(hasAnyDeclaration(124          namedDecl(hasUnderlyingDecl(hasName(ForwardFunction)))))),125 126      unless(anyOf(hasAncestor(typeLoc()),127                   hasAncestor(expr(hasUnevaluatedContext())))));128 129  Finder->addMatcher(130      parmVarDecl(131          parmVarDecl().bind("param"), hasIdentifier(),132          unless(hasAttr(attr::Kind::Unused)), isTemplateTypeParameter(),133          hasAncestor(functionDecl().bind("func")),134          hasAncestor(functionDecl(135              isDefinition(), equalsBoundNode("func"), ToParam,136              unless(anyOf(isDeleted(), hasDescendant(ForwardCallMatcher)))))),137      this);138}139 140void MissingStdForwardCheck::check(const MatchFinder::MatchResult &Result) {141  const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");142 143  if (!Param)144    return;145 146  diag(Param->getLocation(),147       "forwarding reference parameter %0 is never forwarded "148       "inside the function body")149      << Param;150}151 152MissingStdForwardCheck::MissingStdForwardCheck(StringRef Name,153                                               ClangTidyContext *Context)154    : ClangTidyCheck(Name, Context),155      ForwardFunction(Options.get("ForwardFunction", "::std::forward")) {}156 157void MissingStdForwardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {158  Options.store(Opts, "ForwardFunction", ForwardFunction);159}160 161} // namespace clang::tidy::cppcoreguidelines162