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 
16 using llvm::Optional;
17 using namespace clang;
18 
19 namespace {
20 
21 bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
22   assert(R);
23 
24   bool hasRef = false;
25   bool hasDeref = false;
26   for (const CXXMethodDecl *MD : R->methods()) {
27     const auto MethodName = safeGetName(MD);
28 
29     if (MethodName == "ref" && MD->getAccess() == AS_public) {
30       if (hasDeref)
31         return true;
32       hasRef = true;
33     } else if (MethodName == "deref" && MD->getAccess() == AS_public) {
34       if (hasRef)
35         return true;
36       hasDeref = true;
37     }
38   }
39   return false;
40 }
41 
42 } // namespace
43 
44 namespace clang {
45 
46 const CXXRecordDecl *isRefCountable(const CXXBaseSpecifier *Base) {
47   assert(Base);
48 
49   const Type *T = Base->getType().getTypePtrOrNull();
50   if (!T)
51     return nullptr;
52 
53   const CXXRecordDecl *R = T->getAsCXXRecordDecl();
54   if (!R)
55     return nullptr;
56 
57   return hasPublicRefAndDeref(R) ? R : nullptr;
58 }
59 
60 bool isRefCountable(const CXXRecordDecl *R) {
61   assert(R);
62 
63   R = R->getDefinition();
64   assert(R);
65 
66   if (hasPublicRefAndDeref(R))
67     return true;
68 
69   CXXBasePaths Paths;
70   Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
71 
72   const auto isRefCountableBase = [](const CXXBaseSpecifier *Base,
73                                      CXXBasePath &) {
74     return clang::isRefCountable(Base);
75   };
76 
77   return R->lookupInBases(isRefCountableBase, Paths,
78                           /*LookupInDependent =*/true);
79 }
80 
81 bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
82   assert(F);
83   const auto &FunctionName = safeGetName(F);
84 
85   return FunctionName == "Ref" || FunctionName == "makeRef"
86 
87          || FunctionName == "RefPtr" || FunctionName == "makeRefPtr"
88 
89          || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
90          FunctionName == "makeUniqueRefWithoutFastMallocCheck"
91 
92          || FunctionName == "String" || FunctionName == "AtomString" ||
93          FunctionName == "UniqueString"
94          // FIXME: Implement as attribute.
95          || FunctionName == "Identifier";
96 }
97 
98 bool isUncounted(const CXXRecordDecl *Class) {
99   // Keep isRefCounted first as it's cheaper.
100   return !isRefCounted(Class) && isRefCountable(Class);
101 }
102 
103 bool isUncountedPtr(const Type *T) {
104   assert(T);
105 
106   if (T->isPointerType() || T->isReferenceType()) {
107     if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
108       return isUncounted(CXXRD);
109     }
110   }
111   return false;
112 }
113 
114 bool isGetterOfRefCounted(const CXXMethodDecl *M) {
115   assert(M);
116 
117   if (isa<CXXMethodDecl>(M)) {
118     const CXXRecordDecl *calleeMethodsClass = M->getParent();
119     auto className = safeGetName(calleeMethodsClass);
120     auto methodName = safeGetName(M);
121 
122     if (((className == "Ref" || className == "RefPtr") &&
123          methodName == "get") ||
124         ((className == "String" || className == "AtomString" ||
125           className == "AtomStringImpl" || className == "UniqueString" ||
126           className == "UniqueStringImpl" || className == "Identifier") &&
127          methodName == "impl"))
128       return true;
129 
130     // Ref<T> -> T conversion
131     // FIXME: Currently allowing any Ref<T> -> whatever cast.
132     if (className == "Ref" || className == "RefPtr") {
133       if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
134         if (auto *targetConversionType =
135                 maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
136           if (isUncountedPtr(targetConversionType)) {
137             return true;
138           }
139         }
140       }
141     }
142   }
143   return false;
144 }
145 
146 bool isRefCounted(const CXXRecordDecl *R) {
147   assert(R);
148   if (auto *TmplR = R->getTemplateInstantiationPattern()) {
149     // FIXME: String/AtomString/UniqueString
150     const auto &ClassName = safeGetName(TmplR);
151     return ClassName == "RefPtr" || ClassName == "Ref";
152   }
153   return false;
154 }
155 
156 bool isPtrConversion(const FunctionDecl *F) {
157   assert(F);
158   if (isCtorOfRefCounted(F))
159     return true;
160 
161   // FIXME: check # of params == 1
162   const auto FunctionName = safeGetName(F);
163   if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
164       FunctionName == "makeWeakPtr"
165 
166       || FunctionName == "downcast" || FunctionName == "bitwise_cast")
167     return true;
168 
169   return false;
170 }
171 
172 } // namespace clang
173