clang  14.0.0git
RefCntblBaseVirtualDtorChecker.cpp
Go to the documentation of this file.
1 //=======- RefCntblBaseVirtualDtor.cpp ---------------------------*- C++ -*-==//
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 
9 #include "DiagOutputUtils.h"
10 #include "PtrTypesSemantics.h"
17 
18 using namespace clang;
19 using namespace ento;
20 
21 namespace {
22 class RefCntblBaseVirtualDtorChecker
23  : public Checker<check::ASTDecl<TranslationUnitDecl>> {
24 private:
25  BugType Bug;
26  mutable BugReporter *BR;
27 
28 public:
29  RefCntblBaseVirtualDtorChecker()
30  : Bug(this,
31  "Reference-countable base class doesn't have virtual destructor",
32  "WebKit coding guidelines") {}
33 
34  void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
35  BugReporter &BRArg) const {
36  BR = &BRArg;
37 
38  // The calls to checkAST* from AnalysisConsumer don't
39  // visit template instantiations or lambda classes. We
40  // want to visit those, so we make our own RecursiveASTVisitor.
41  struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
42  const RefCntblBaseVirtualDtorChecker *Checker;
43  explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker)
44  : Checker(Checker) {
45  assert(Checker);
46  }
47 
48  bool shouldVisitTemplateInstantiations() const { return true; }
49  bool shouldVisitImplicitCode() const { return false; }
50 
51  bool VisitCXXRecordDecl(const CXXRecordDecl *RD) {
52  Checker->visitCXXRecordDecl(RD);
53  return true;
54  }
55  };
56 
57  LocalVisitor visitor(this);
58  visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
59  }
60 
61  void visitCXXRecordDecl(const CXXRecordDecl *RD) const {
62  if (shouldSkipDecl(RD))
63  return;
64 
65  CXXBasePaths Paths;
66  Paths.setOrigin(RD);
67 
68  const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr;
69  const CXXRecordDecl *ProblematicBaseClass = nullptr;
70 
71  const auto IsPublicBaseRefCntblWOVirtualDtor =
72  [RD, &ProblematicBaseSpecifier,
73  &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) {
74  const auto AccSpec = Base->getAccessSpecifier();
75  if (AccSpec == AS_protected || AccSpec == AS_private ||
76  (AccSpec == AS_none && RD->isClass()))
77  return false;
78 
81  if (!RefCntblBaseRD || !(*RefCntblBaseRD))
82  return false;
83 
84  const auto *Dtor = (*RefCntblBaseRD)->getDestructor();
85  if (!Dtor || !Dtor->isVirtual()) {
86  ProblematicBaseSpecifier = Base;
87  ProblematicBaseClass = *RefCntblBaseRD;
88  return true;
89  }
90 
91  return false;
92  };
93 
94  if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths,
95  /*LookupInDependent =*/true)) {
96  reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass);
97  }
98  }
99 
100  bool shouldSkipDecl(const CXXRecordDecl *RD) const {
101  if (!RD->isThisDeclarationADefinition())
102  return true;
103 
104  if (RD->isImplicit())
105  return true;
106 
107  if (RD->isLambda())
108  return true;
109 
110  // If the construct doesn't have a source file, then it's not something
111  // we want to diagnose.
112  const auto RDLocation = RD->getLocation();
113  if (!RDLocation.isValid())
114  return true;
115 
116  const auto Kind = RD->getTagKind();
117  if (Kind != TTK_Struct && Kind != TTK_Class)
118  return true;
119 
120  // Ignore CXXRecords that come from system headers.
121  if (BR->getSourceManager().getFileCharacteristic(RDLocation) !=
123  return true;
124 
125  return false;
126  }
127 
128  void reportBug(const CXXRecordDecl *DerivedClass,
129  const CXXBaseSpecifier *BaseSpec,
130  const CXXRecordDecl *ProblematicBaseClass) const {
131  assert(DerivedClass);
132  assert(BaseSpec);
133  assert(ProblematicBaseClass);
134 
135  SmallString<100> Buf;
136  llvm::raw_svector_ostream Os(Buf);
137 
138  Os << (ProblematicBaseClass->isClass() ? "Class" : "Struct") << " ";
139  printQuotedQualifiedName(Os, ProblematicBaseClass);
140 
141  Os << " is used as a base of "
142  << (DerivedClass->isClass() ? "class" : "struct") << " ";
143  printQuotedQualifiedName(Os, DerivedClass);
144 
145  Os << " but doesn't have virtual destructor";
146 
147  PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(),
148  BR->getSourceManager());
149  auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
150  Report->addRange(BaseSpec->getSourceRange());
151  BR->emitReport(std::move(Report));
152  }
153 };
154 } // namespace
155 
156 void ento::registerRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) {
157  Mgr.registerChecker<RefCntblBaseVirtualDtorChecker>();
158 }
159 
160 bool ento::shouldRegisterRefCntblBaseVirtualDtorChecker(
161  const CheckerManager &mgr) {
162  return true;
163 }
clang::TTK_Struct
@ TTK_Struct
The "struct" keyword.
Definition: Type.h:5310
clang::SourceRange::getBegin
SourceLocation getBegin() const
Definition: SourceLocation.h:221
clang::AS_private
@ AS_private
Definition: Specifiers.h:111
CXXInheritance.h
llvm::Optional
Definition: LLVM.h:40
clang::CXXRecordDecl::lookupInBases
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const
Look for entities within the base classes of this C++ class, transitively searching all base class su...
Definition: CXXInheritance.cpp:307
clang::AS_none
@ AS_none
Definition: Specifiers.h:112
clang::TranslationUnitDecl
The top declaration context.
Definition: Decl.h:82
BuiltinCheckerRegistration.h
DiagOutputUtils.h
BugReporter.h
clang::RecursiveASTVisitor
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Definition: RecursiveASTVisitor.h:164
clang::TagDecl::isThisDeclarationADefinition
bool isThisDeclarationADefinition() const
Return true if this declaration is a completion definition of the type.
Definition: Decl.h:3428
llvm::SmallString
Definition: LLVM.h:37
clang::CXXBaseSpecifier::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
Retrieves the source range that contains the entire base specifier.
Definition: DeclCXX.h:190
clang::TTK_Class
@ TTK_Class
The "class" keyword.
Definition: Type.h:5319
clang::SrcMgr::C_User
@ C_User
Definition: SourceManager.h:79
Base
clang::isRefCountable
llvm::Optional< const clang::CXXRecordDecl * > isRefCountable(const CXXBaseSpecifier *Base)
Definition: PtrTypesSemantics.cpp:49
clang::Decl::isImplicit
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:563
clang::TagDecl::isClass
bool isClass() const
Definition: Decl.h:3515
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
PtrTypesSemantics.h
BugType.h
clang::AS_protected
@ AS_protected
Definition: Specifiers.h:110
clang::printQuotedQualifiedName
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
Definition: DiagOutputUtils.h:18
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
Checker.h
clang::CXXBasePath
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
Definition: CXXInheritance.h:70
clang
Definition: CalledOnceCheck.h:17
RecursiveASTVisitor.h
clang::CXXBaseSpecifier
Represents a base class of a C++ class.
Definition: DeclCXX.h:147
clang::TagDecl::getTagKind
TagKind getTagKind() const
Definition: Decl.h:3507
clang::CXXBasePaths
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
Definition: CXXInheritance.h:117
clang::CXXRecordDecl::isLambda
bool isLambda() const
Determine whether this class describes a lambda function object.
Definition: DeclCXX.h:992
clang::Decl::getLocation
SourceLocation getLocation() const
Definition: DeclBase.h:430