clang  19.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/Support/Casting.h"
21 #include <optional>
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-pointer/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  std::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?
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 }
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:599
SourceLocation getLocation() const
Definition: DeclBase.h:445
Represents a member of a struct/union/class.
Definition: Decl.h:3060
Represents a struct/union/class.
Definition: Decl.h:4171
bool isLambda() const
Determine whether this record is a class describing a lambda function object.
Definition: Decl.cpp:5044
field_range fields() const
Definition: Decl.h:4377
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isThisDeclarationADefinition() const
Return true if this declaration is a completion definition of the type.
Definition: Decl.h:3685
TagKind getTagKind() const
Definition: Decl.h:3782
The top declaration context.
Definition: Decl.h:84
The base class of the type hierarchy.
Definition: Type.h:1813
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:1866
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:585
const SourceManager & getSourceManager()
Definition: BugReporter.h:623
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
The JSON file list parser is used to communicate input to InstallAPI.
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< bool > isRefCountable(const CXXRecordDecl *R)
@ Struct
The "struct" keyword.
@ Class
The "class" keyword.
bool isRefCounted(const CXXRecordDecl *R)