Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
Line
Count
Source (jump to first uncovered line)
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"
11
#include "clang/AST/CXXInheritance.h"
12
#include "clang/AST/RecursiveASTVisitor.h"
13
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
15
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16
#include "clang/StaticAnalyzer/Core/Checker.h"
17
#include <optional>
18
19
using namespace clang;
20
using namespace ento;
21
22
namespace {
23
class RefCntblBaseVirtualDtorChecker
24
    : public Checker<check::ASTDecl<TranslationUnitDecl>> {
25
private:
26
  BugType Bug;
27
  mutable BugReporter *BR;
28
29
public:
30
  RefCntblBaseVirtualDtorChecker()
31
2
      : Bug(this,
32
2
            "Reference-countable base class doesn't have virtual destructor",
33
2
            "WebKit coding guidelines") {}
34
35
  void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
36
2
                    BugReporter &BRArg) const {
37
2
    BR = &BRArg;
38
39
    // The calls to checkAST* from AnalysisConsumer don't
40
    // visit template instantiations or lambda classes. We
41
    // want to visit those, so we make our own RecursiveASTVisitor.
42
2
    struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
43
2
      const RefCntblBaseVirtualDtorChecker *Checker;
44
2
      explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker)
45
2
          : Checker(Checker) {
46
2
        assert(Checker);
47
2
      }
48
49
9
      bool shouldVisitTemplateInstantiations() const { return true; }
50
124
      bool shouldVisitImplicitCode() const { return false; }
51
52
22
      bool VisitCXXRecordDecl(const CXXRecordDecl *RD) {
53
22
        Checker->visitCXXRecordDecl(RD);
54
22
        return true;
55
22
      }
56
2
    };
57
58
2
    LocalVisitor visitor(this);
59
2
    visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
60
2
  }
61
62
22
  void visitCXXRecordDecl(const CXXRecordDecl *RD) const {
63
22
    if (shouldSkipDecl(RD))
64
1
      return;
65
66
21
    CXXBasePaths Paths;
67
21
    Paths.setOrigin(RD);
68
69
21
    const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr;
70
21
    const CXXRecordDecl *ProblematicBaseClass = nullptr;
71
72
21
    const auto IsPublicBaseRefCntblWOVirtualDtor =
73
21
        [RD, &ProblematicBaseSpecifier,
74
21
         &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) {
75
15
          const auto AccSpec = Base->getAccessSpecifier();
76
15
          if (AccSpec == AS_protected || AccSpec == AS_private ||
77
15
              
(13
AccSpec == AS_none13
&&
RD->isClass()0
))
78
2
            return false;
79
80
13
          std::optional<const CXXRecordDecl*> RefCntblBaseRD = isRefCountable(Base);
81
13
          if (!RefCntblBaseRD || 
!(*RefCntblBaseRD)9
)
82
8
            return false;
83
84
5
          const auto *Dtor = (*RefCntblBaseRD)->getDestructor();
85
5
          if (!Dtor || !Dtor->isVirtual()) {
86
5
            ProblematicBaseSpecifier = Base;
87
5
            ProblematicBaseClass = *RefCntblBaseRD;
88
5
            return true;
89
5
          }
90
91
0
          return false;
92
5
        };
93
94
21
    if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths,
95
21
                          /*LookupInDependent =*/true)) {
96
5
      reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass);
97
5
    }
98
21
  }
99
100
22
  bool shouldSkipDecl(const CXXRecordDecl *RD) const {
101
22
    if (!RD->isThisDeclarationADefinition())
102
1
      return true;
103
104
21
    if (RD->isImplicit())
105
0
      return true;
106
107
21
    if (RD->isLambda())
108
0
      return true;
109
110
    // If the construct doesn't have a source file, then it's not something
111
    // we want to diagnose.
112
21
    const auto RDLocation = RD->getLocation();
113
21
    if (!RDLocation.isValid())
114
0
      return true;
115
116
21
    const auto Kind = RD->getTagKind();
117
21
    if (Kind != TTK_Struct && 
Kind != TTK_Class2
)
118
0
      return true;
119
120
    // Ignore CXXRecords that come from system headers.
121
21
    if (BR->getSourceManager().getFileCharacteristic(RDLocation) !=
122
21
        SrcMgr::C_User)
123
0
      return true;
124
125
21
    return false;
126
21
  }
127
128
  void reportBug(const CXXRecordDecl *DerivedClass,
129
                 const CXXBaseSpecifier *BaseSpec,
130
5
                 const CXXRecordDecl *ProblematicBaseClass) const {
131
5
    assert(DerivedClass);
132
5
    assert(BaseSpec);
133
5
    assert(ProblematicBaseClass);
134
135
5
    SmallString<100> Buf;
136
5
    llvm::raw_svector_ostream Os(Buf);
137
138
5
    Os << (ProblematicBaseClass->isClass() ? 
"Class"0
: "Struct") << " ";
139
5
    printQuotedQualifiedName(Os, ProblematicBaseClass);
140
141
5
    Os << " is used as a base of "
142
5
       << (DerivedClass->isClass() ? 
"class"0
: "struct") << " ";
143
5
    printQuotedQualifiedName(Os, DerivedClass);
144
145
5
    Os << " but doesn't have virtual destructor";
146
147
5
    PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(),
148
5
                                 BR->getSourceManager());
149
5
    auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
150
5
    Report->addRange(BaseSpec->getSourceRange());
151
5
    BR->emitReport(std::move(Report));
152
5
  }
153
};
154
} // namespace
155
156
2
void ento::registerRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) {
157
2
  Mgr.registerChecker<RefCntblBaseVirtualDtorChecker>();
158
2
}
159
160
bool ento::shouldRegisterRefCntblBaseVirtualDtorChecker(
161
4
    const CheckerManager &mgr) {
162
4
  return true;
163
4
}