clang-tools  8.0.0
CopyConstructorInitCheck.cpp
Go to the documentation of this file.
1 //===--- CopyConstructorInitCheck.cpp - clang-tidy-------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 namespace bugprone {
20 
21 void CopyConstructorInitCheck::registerMatchers(MatchFinder *Finder) {
22  if (!getLangOpts().CPlusPlus)
23  return;
24 
25  // In the future this might be extended to move constructors?
26  Finder->addMatcher(
27  cxxConstructorDecl(
28  isCopyConstructor(),
29  hasAnyConstructorInitializer(cxxCtorInitializer(
30  isBaseInitializer(),
31  withInitializer(cxxConstructExpr(hasDeclaration(
32  cxxConstructorDecl(isDefaultConstructor())))))),
33  unless(isInstantiated()))
34  .bind("ctor"),
35  this);
36 }
37 
38 void CopyConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
39  const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
40  std::string ParamName = Ctor->getParamDecl(0)->getNameAsString();
41 
42  // We want only one warning (and FixIt) for each ctor.
43  std::string FixItInitList;
44  bool HasRelevantBaseInit = false;
45  bool ShouldNotDoFixit = false;
46  bool HasWrittenInitializer = false;
47  SmallVector<FixItHint, 2> SafeFixIts;
48  for (const auto *Init : Ctor->inits()) {
49  bool CtorInitIsWritten = Init->isWritten();
50  HasWrittenInitializer = HasWrittenInitializer || CtorInitIsWritten;
51  if (!Init->isBaseInitializer())
52  continue;
53  const Type *BaseType = Init->getBaseClass();
54  // Do not do fixits if there is a type alias involved or one of the bases
55  // are explicitly initialized. In the latter case we not do fixits to avoid
56  // -Wreorder warnings.
57  if (const auto *TempSpecTy = dyn_cast<TemplateSpecializationType>(BaseType))
58  ShouldNotDoFixit = ShouldNotDoFixit || TempSpecTy->isTypeAlias();
59  ShouldNotDoFixit = ShouldNotDoFixit || isa<TypedefType>(BaseType);
60  ShouldNotDoFixit = ShouldNotDoFixit || CtorInitIsWritten;
61  const CXXRecordDecl *BaseClass =
62  BaseType->getAsCXXRecordDecl()->getDefinition();
63  if (BaseClass->field_empty() &&
64  BaseClass->forallBases(
65  [](const CXXRecordDecl *Class) { return Class->field_empty(); }))
66  continue;
67  bool NonCopyableBase = false;
68  for (const auto *Ctor : BaseClass->ctors()) {
69  if (Ctor->isCopyConstructor() &&
70  (Ctor->getAccess() == AS_private || Ctor->isDeleted())) {
71  NonCopyableBase = true;
72  break;
73  }
74  }
75  if (NonCopyableBase)
76  continue;
77  const auto *CExpr = dyn_cast<CXXConstructExpr>(Init->getInit());
78  if (!CExpr || !CExpr->getConstructor()->isDefaultConstructor())
79  continue;
80  HasRelevantBaseInit = true;
81  if (CtorInitIsWritten) {
82  if (!ParamName.empty())
83  SafeFixIts.push_back(
84  FixItHint::CreateInsertion(CExpr->getEndLoc(), ParamName));
85  } else {
86  if (Init->getSourceLocation().isMacroID() ||
87  Ctor->getLocation().isMacroID() || ShouldNotDoFixit)
88  break;
89  FixItInitList += BaseClass->getNameAsString();
90  FixItInitList += "(" + ParamName + "), ";
91  }
92  }
93  if (!HasRelevantBaseInit)
94  return;
95 
96  auto Diag = diag(Ctor->getLocation(),
97  "calling a base constructor other than the copy constructor")
98  << SafeFixIts;
99 
100  if (FixItInitList.empty() || ParamName.empty() || ShouldNotDoFixit)
101  return;
102 
103  std::string FixItMsg{FixItInitList.substr(0, FixItInitList.size() - 2)};
104  SourceLocation FixItLoc;
105  // There is no initialization list in this constructor.
106  if (!HasWrittenInitializer) {
107  FixItLoc = Ctor->getBody()->getBeginLoc();
108  FixItMsg = " : " + FixItMsg;
109  } else {
110  // We apply the missing ctors at the beginning of the initialization list.
111  FixItLoc = (*Ctor->init_begin())->getSourceLocation();
112  FixItMsg += ',';
113  }
114  FixItMsg += ' ';
115 
116  Diag << FixItHint::CreateInsertion(FixItLoc, FixItMsg);
117 } // namespace misc
118 
119 } // namespace misc
120 } // namespace tidy
121 } // namespace clang
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//