clang  14.0.0git
NoUncountedMembersChecker.cpp
Go to the documentation of this file.
1 //=======- NoUncountedMembersChecker.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 "ASTUtils.h"
10 #include "DiagOutputUtils.h"
11 #include "PtrTypesSemantics.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/AST/DeclCXX.h"
20 #include "llvm/ADT/DenseSet.h"
21 #include "llvm/Support/Casting.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 
28 class NoUncountedMemberChecker
29  : public Checker<check::ASTDecl<TranslationUnitDecl>> {
30 private:
31  BugType Bug;
32  mutable BugReporter *BR;
33 
34 public:
35  NoUncountedMemberChecker()
36  : Bug(this,
37  "Member variable is a raw-poiner/reference to reference-countable "
38  "type",
39  "WebKit coding guidelines") {}
40 
41  void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
42  BugReporter &BRArg) const {
43  BR = &BRArg;
44 
45  // The calls to checkAST* from AnalysisConsumer don't
46  // visit template instantiations or lambda classes. We
47  // want to visit those, so we make our own RecursiveASTVisitor.
48  struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
49  const NoUncountedMemberChecker *Checker;
50  explicit LocalVisitor(const NoUncountedMemberChecker *Checker)
51  : Checker(Checker) {
52  assert(Checker);
53  }
54 
55  bool shouldVisitTemplateInstantiations() const { return true; }
56  bool shouldVisitImplicitCode() const { return false; }
57 
58  bool VisitRecordDecl(const RecordDecl *RD) {
59  Checker->visitRecordDecl(RD);
60  return true;
61  }
62  };
63 
64  LocalVisitor visitor(this);
65  visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
66  }
67 
68  void visitRecordDecl(const RecordDecl *RD) const {
69  if (shouldSkipDecl(RD))
70  return;
71 
72  for (auto Member : RD->fields()) {
73  const Type *MemberType = Member->getType().getTypePtrOrNull();
74  if (!MemberType)
75  continue;
76 
77  if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) {
78  // If we don't see the definition we just don't know.
79  if (MemberCXXRD->hasDefinition()) {
80  llvm::Optional<bool> isRCAble = isRefCountable(MemberCXXRD);
81  if (isRCAble && *isRCAble)
82  reportBug(Member, MemberType, MemberCXXRD, RD);
83  }
84  }
85  }
86  }
87 
88  bool shouldSkipDecl(const RecordDecl *RD) const {
90  return true;
91 
92  if (RD->isImplicit())
93  return true;
94 
95  if (RD->isLambda())
96  return true;
97 
98  // If the construct doesn't have a source file, then it's not something
99  // we want to diagnose.
100  const auto RDLocation = RD->getLocation();
101  if (!RDLocation.isValid())
102  return true;
103 
104  const auto Kind = RD->getTagKind();
105  // FIMXE: Should we check union members too?
106  if (Kind != TTK_Struct && Kind != TTK_Class)
107  return true;
108 
109  // Ignore CXXRecords that come from system headers.
110  if (BR->getSourceManager().isInSystemHeader(RDLocation))
111  return true;
112 
113  // Ref-counted smartpointers actually have raw-pointer to uncounted type as
114  // a member but we trust them to handle it correctly.
115  auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
116  if (CXXRD)
117  return isRefCounted(CXXRD);
118 
119  return false;
120  }
121 
122  void reportBug(const FieldDecl *Member, const Type *MemberType,
123  const CXXRecordDecl *MemberCXXRD,
124  const RecordDecl *ClassCXXRD) const {
125  assert(Member);
126  assert(MemberType);
127  assert(MemberCXXRD);
128 
129  SmallString<100> Buf;
130  llvm::raw_svector_ostream Os(Buf);
131 
132  Os << "Member variable ";
133  printQuotedName(Os, Member);
134  Os << " in ";
135  printQuotedQualifiedName(Os, ClassCXXRD);
136  Os << " is a "
137  << (isa<PointerType>(MemberType) ? "raw pointer" : "reference")
138  << " to ref-countable type ";
139  printQuotedQualifiedName(Os, MemberCXXRD);
140  Os << "; member variables must be ref-counted.";
141 
142  PathDiagnosticLocation BSLoc(Member->getSourceRange().getBegin(),
143  BR->getSourceManager());
144  auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
145  Report->addRange(Member->getSourceRange());
146  BR->emitReport(std::move(Report));
147  }
148 };
149 } // namespace
150 
151 void ento::registerNoUncountedMemberChecker(CheckerManager &Mgr) {
152  Mgr.registerChecker<NoUncountedMemberChecker>();
153 }
154 
155 bool ento::shouldRegisterNoUncountedMemberChecker(
156  const CheckerManager &Mgr) {
157  return true;
158 }
clang::TTK_Struct
@ TTK_Struct
The "struct" keyword.
Definition: Type.h:5310
CXXInheritance.h
clang::printQuotedName
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
Definition: DiagOutputUtils.h:27
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2835
DeclCXX.h
llvm::Optional< bool >
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1490
Decl.h
clang::TranslationUnitDecl
The top declaration context.
Definition: Decl.h:82
BuiltinCheckerRegistration.h
clang::isRefCounted
bool isRefCounted(const CXXRecordDecl *R)
Definition: PtrTypesSemantics.cpp:168
DiagOutputUtils.h
BugReporter.h
clang::DeclaratorContext::Member
@ Member
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
clang::Type::getPointeeCXXRecordDecl
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition: Type.cpp:1745
llvm::SmallString
Definition: LLVM.h:37
clang::TTK_Class
@ TTK_Class
The "class" keyword.
Definition: Type.h:5319
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::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
PtrTypesSemantics.h
BugType.h
clang::printQuotedQualifiedName
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
Definition: DiagOutputUtils.h:18
clang::RecordDecl::fields
field_range fields() const
Definition: Decl.h:4083
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
Checker.h
ASTUtils.h
clang
Definition: CalledOnceCheck.h:17
RecursiveASTVisitor.h
clang::TagDecl::getTagKind
TagKind getTagKind() const
Definition: Decl.h:3507
clang::RecordDecl::isLambda
bool isLambda() const
Determine whether this record is a class describing a lambda function object.
Definition: Decl.cpp:4587
clang::Decl::getLocation
SourceLocation getLocation() const
Definition: DeclBase.h:430
clang::RecordDecl
Represents a struct/union/class.
Definition: Decl.h:3863