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