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