Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Line
Count
Source (jump to first uncovered line)
1
//=======- PtrTypesSemantics.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 "PtrTypesSemantics.h"
10
#include "ASTUtils.h"
11
#include "clang/AST/CXXInheritance.h"
12
#include "clang/AST/Decl.h"
13
#include "clang/AST/DeclCXX.h"
14
#include "clang/AST/ExprCXX.h"
15
#include <optional>
16
17
using namespace clang;
18
19
namespace {
20
21
78
bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
22
78
  assert(R);
23
78
  assert(R->hasDefinition());
24
25
78
  bool hasRef = false;
26
78
  bool hasDeref = false;
27
157
  for (const CXXMethodDecl *MD : R->methods()) {
28
157
    const auto MethodName = safeGetName(MD);
29
30
157
    if (MethodName == "ref" && 
MD->getAccess() == AS_public76
) {
31
73
      if (hasDeref)
32
0
        return true;
33
73
      hasRef = true;
34
84
    } else if (MethodName == "deref" && 
MD->getAccess() == AS_public76
) {
35
73
      if (hasRef)
36
73
        return true;
37
0
      hasDeref = true;
38
0
    }
39
157
  }
40
5
  return false;
41
78
}
42
43
} // namespace
44
45
namespace clang {
46
47
std::optional<const clang::CXXRecordDecl*>
48
isRefCountable(const CXXBaseSpecifier* Base)
49
13
{
50
13
  assert(Base);
51
52
13
  const Type *T = Base->getType().getTypePtrOrNull();
53
13
  if (!T)
54
0
    return std::nullopt;
55
56
13
  const CXXRecordDecl *R = T->getAsCXXRecordDecl();
57
13
  if (!R)
58
4
    return std::nullopt;
59
9
  if (!R->hasDefinition())
60
0
    return std::nullopt;
61
62
9
  return hasPublicRefAndDeref(R) ? 
R5
:
nullptr4
;
63
9
}
64
65
std::optional<bool> isRefCountable(const CXXRecordDecl* R)
66
69
{
67
69
  assert(R);
68
69
69
  R = R->getDefinition();
70
69
  if (!R)
71
0
    return std::nullopt;
72
73
69
  if (hasPublicRefAndDeref(R))
74
68
    return true;
75
76
1
  CXXBasePaths Paths;
77
1
  Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
78
79
1
  bool AnyInconclusiveBase = false;
80
1
  const auto isRefCountableBase =
81
1
      [&AnyInconclusiveBase](const CXXBaseSpecifier* Base, CXXBasePath&) {
82
0
          std::optional<const clang::CXXRecordDecl*> IsRefCountable = clang::isRefCountable(Base);
83
0
          if (!IsRefCountable) {
84
0
              AnyInconclusiveBase = true;
85
0
              return false;
86
0
          }
87
0
          return (*IsRefCountable) != nullptr;
88
0
      };
89
90
1
  bool BasesResult = R->lookupInBases(isRefCountableBase, Paths,
91
1
                                      /*LookupInDependent =*/true);
92
1
  if (AnyInconclusiveBase)
93
0
    return std::nullopt;
94
95
1
  return BasesResult;
96
1
}
97
98
113
bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
99
113
  assert(F);
100
113
  const auto &FunctionName = safeGetName(F);
101
102
113
  return FunctionName == "Ref" || FunctionName == "makeRef"
103
104
113
         || 
FunctionName == "RefPtr"112
||
FunctionName == "makeRefPtr"112
105
106
113
         || 
FunctionName == "UniqueRef"111
||
FunctionName == "makeUniqueRef"111
||
107
113
         
FunctionName == "makeUniqueRefWithoutFastMallocCheck"111
108
109
113
         || 
FunctionName == "String"111
||
FunctionName == "AtomString"111
||
110
113
         
FunctionName == "UniqueString"111
111
         // FIXME: Implement as attribute.
112
113
         || 
FunctionName == "Identifier"111
;
113
113
}
114
115
std::optional<bool> isUncounted(const CXXRecordDecl* Class)
116
66
{
117
  // Keep isRefCounted first as it's cheaper.
118
66
  if (isRefCounted(Class))
119
0
    return false;
120
121
66
  std::optional<bool> IsRefCountable = isRefCountable(Class);
122
66
  if (!IsRefCountable)
123
0
    return std::nullopt;
124
125
66
  return (*IsRefCountable);
126
66
}
127
128
std::optional<bool> isUncountedPtr(const Type* T)
129
77
{
130
77
  assert(T);
131
132
77
  if (T->isPointerType() || 
T->isReferenceType()29
) {
133
66
    if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
134
66
      return isUncounted(CXXRD);
135
66
    }
136
66
  }
137
11
  return false;
138
77
}
139
140
std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
141
16
{
142
16
  assert(M);
143
144
16
  if (isa<CXXMethodDecl>(M)) {
145
16
    const CXXRecordDecl *calleeMethodsClass = M->getParent();
146
16
    auto className = safeGetName(calleeMethodsClass);
147
16
    auto methodName = safeGetName(M);
148
149
16
    if (((className == "Ref" || 
className == "RefPtr"13
) &&
150
16
         
methodName == "get"10
) ||
151
16
        
(8
(8
className == "String"8
||
className == "AtomString"7
||
152
8
          
className == "AtomStringImpl"6
||
className == "UniqueString"6
||
153
8
          
className == "UniqueStringImpl"6
||
className == "Identifier"6
) &&
154
8
         
methodName == "impl"2
))
155
10
      return true;
156
157
    // Ref<T> -> T conversion
158
    // FIXME: Currently allowing any Ref<T> -> whatever cast.
159
6
    if (className == "Ref" || 
className == "RefPtr"4
) {
160
2
      if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
161
2
        if (auto *targetConversionType =
162
2
                maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
163
2
          return isUncountedPtr(targetConversionType);
164
2
        }
165
2
      }
166
2
    }
167
6
  }
168
4
  return false;
169
16
}
170
171
83
bool isRefCounted(const CXXRecordDecl *R) {
172
83
  assert(R);
173
83
  if (auto *TmplR = R->getTemplateInstantiationPattern()) {
174
    // FIXME: String/AtomString/UniqueString
175
10
    const auto &ClassName = safeGetName(TmplR);
176
10
    return ClassName == "RefPtr" || 
ClassName == "Ref"3
;
177
10
  }
178
73
  return false;
179
83
}
180
181
28
bool isPtrConversion(const FunctionDecl *F) {
182
28
  assert(F);
183
28
  if (isCtorOfRefCounted(F))
184
0
    return true;
185
186
  // FIXME: check # of params == 1
187
28
  const auto FunctionName = safeGetName(F);
188
28
  if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
189
28
      FunctionName == "makeWeakPtr"
190
191
28
      || FunctionName == "downcast" || 
FunctionName == "bitwise_cast"20
)
192
11
    return true;
193
194
17
  return false;
195
28
}
196
197
} // namespace clang