Coverage Report

Created: 2022-01-15 10:30

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