brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.1 KiB · d8cdc0d Raw
85 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 "MoveConstructorInitCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::performance {16 17MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name,18                                                   ClangTidyContext *Context)19    : ClangTidyCheck(Name, Context) {}20 21void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) {22  Finder->addMatcher(23      traverse(TK_AsIs,24               cxxConstructorDecl(25                   unless(isImplicit()), isMoveConstructor(),26                   hasAnyConstructorInitializer(27                       cxxCtorInitializer(28                           withInitializer(cxxConstructExpr(hasDeclaration(29                               cxxConstructorDecl(isCopyConstructor())30                                   .bind("ctor")))))31                           .bind("move-init")))),32      this);33}34 35void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {36  const auto *CopyCtor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");37  const auto *Initializer =38      Result.Nodes.getNodeAs<CXXCtorInitializer>("move-init");39 40  // Do not diagnose if the expression used to perform the initialization is a41  // trivially-copyable type.42  const QualType QT = Initializer->getInit()->getType();43  if (QT.isTriviallyCopyableType(*Result.Context))44    return;45 46  if (QT.isConstQualified())47    return;48 49  const auto *RD = QT->getAsCXXRecordDecl();50  if (RD && RD->isTriviallyCopyable())51    return;52 53  // Diagnose when the class type has a move constructor available, but the54  // ctor-initializer uses the copy constructor instead.55  const CXXConstructorDecl *Candidate = nullptr;56  for (const auto *Ctor : CopyCtor->getParent()->ctors()) {57    if (Ctor->isMoveConstructor() && Ctor->getAccess() <= AS_protected &&58        !Ctor->isDeleted()) {59      // The type has a move constructor that is at least accessible to the60      // initializer.61      //62      // FIXME: Determine whether the move constructor is a viable candidate63      // for the ctor-initializer, perhaps provide a fix-it that suggests64      // using std::move().65      Candidate = Ctor;66      break;67    }68  }69 70  if (Candidate) {71    // There's a move constructor candidate that the caller probably intended72    // to call instead.73    diag(Initializer->getSourceLocation(),74         "move constructor initializes %select{class member|base class}0 by "75         "calling a copy constructor")76        << Initializer->isBaseInitializer();77    diag(CopyCtor->getLocation(), "copy constructor being called",78         DiagnosticIDs::Note);79    diag(Candidate->getLocation(), "candidate move constructor here",80         DiagnosticIDs::Note);81  }82}83 84} // namespace clang::tidy::performance85