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