NoUncountedMembersChecker.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. #include "ASTUtils.h"
  9. #include "DiagOutputUtils.h"
  10. #include "PtrTypesSemantics.h"
  11. #include "clang/AST/CXXInheritance.h"
  12. #include "clang/AST/Decl.h"
  13. #include "clang/AST/DeclCXX.h"
  14. #include "clang/AST/RecursiveASTVisitor.h"
  15. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  16. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "llvm/ADT/DenseSet.h"
  20. #include "llvm/Support/Casting.h"
  21. using namespace clang;
  22. using namespace ento;
  23. namespace {
  24. class NoUncountedMemberChecker
  25. : public Checker<check::ASTDecl<TranslationUnitDecl>> {
  26. private:
  27. BugType Bug;
  28. mutable BugReporter *BR;
  29. public:
  30. NoUncountedMemberChecker()
  31. : Bug(this,
  32. "Member variable is a raw-poiner/reference to reference-countable "
  33. "type",
  34. "WebKit coding guidelines") {}
  35. void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
  36. BugReporter &BRArg) const {
  37. BR = &BRArg;
  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 NoUncountedMemberChecker *Checker;
  43. explicit LocalVisitor(const NoUncountedMemberChecker *Checker)
  44. : Checker(Checker) {
  45. assert(Checker);
  46. }
  47. bool shouldVisitTemplateInstantiations() const { return true; }
  48. bool shouldVisitImplicitCode() const { return false; }
  49. bool VisitRecordDecl(const RecordDecl *RD) {
  50. Checker->visitRecordDecl(RD);
  51. return true;
  52. }
  53. };
  54. LocalVisitor visitor(this);
  55. visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
  56. }
  57. void visitRecordDecl(const RecordDecl *RD) const {
  58. if (shouldSkipDecl(RD))
  59. return;
  60. for (auto Member : RD->fields()) {
  61. const Type *MemberType = Member->getType().getTypePtrOrNull();
  62. if (!MemberType)
  63. continue;
  64. if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) {
  65. // If we don't see the definition we just don't know.
  66. if (MemberCXXRD->hasDefinition()) {
  67. llvm::Optional<bool> isRCAble = isRefCountable(MemberCXXRD);
  68. if (isRCAble && *isRCAble)
  69. reportBug(Member, MemberType, MemberCXXRD, RD);
  70. }
  71. }
  72. }
  73. }
  74. bool shouldSkipDecl(const RecordDecl *RD) const {
  75. if (!RD->isThisDeclarationADefinition())
  76. return true;
  77. if (RD->isImplicit())
  78. return true;
  79. if (RD->isLambda())
  80. return true;
  81. // If the construct doesn't have a source file, then it's not something
  82. // we want to diagnose.
  83. const auto RDLocation = RD->getLocation();
  84. if (!RDLocation.isValid())
  85. return true;
  86. const auto Kind = RD->getTagKind();
  87. // FIMXE: Should we check union members too?
  88. if (Kind != TTK_Struct && Kind != TTK_Class)
  89. return true;
  90. // Ignore CXXRecords that come from system headers.
  91. if (BR->getSourceManager().isInSystemHeader(RDLocation))
  92. return true;
  93. // Ref-counted smartpointers actually have raw-pointer to uncounted type as
  94. // a member but we trust them to handle it correctly.
  95. auto CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
  96. if (CXXRD)
  97. return isRefCounted(CXXRD);
  98. return false;
  99. }
  100. void reportBug(const FieldDecl *Member, const Type *MemberType,
  101. const CXXRecordDecl *MemberCXXRD,
  102. const RecordDecl *ClassCXXRD) const {
  103. assert(Member);
  104. assert(MemberType);
  105. assert(MemberCXXRD);
  106. SmallString<100> Buf;
  107. llvm::raw_svector_ostream Os(Buf);
  108. Os << "Member variable ";
  109. printQuotedName(Os, Member);
  110. Os << " in ";
  111. printQuotedQualifiedName(Os, ClassCXXRD);
  112. Os << " is a "
  113. << (isa<PointerType>(MemberType) ? "raw pointer" : "reference")
  114. << " to ref-countable type ";
  115. printQuotedQualifiedName(Os, MemberCXXRD);
  116. Os << "; member variables must be ref-counted.";
  117. PathDiagnosticLocation BSLoc(Member->getSourceRange().getBegin(),
  118. BR->getSourceManager());
  119. auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
  120. Report->addRange(Member->getSourceRange());
  121. BR->emitReport(std::move(Report));
  122. }
  123. };
  124. } // namespace
  125. void ento::registerNoUncountedMemberChecker(CheckerManager &Mgr) {
  126. Mgr.registerChecker<NoUncountedMemberChecker>();
  127. }
  128. bool ento::shouldRegisterNoUncountedMemberChecker(
  129. const CheckerManager &Mgr) {
  130. return true;
  131. }