1 //===-- ASTOps.cc -------------------------------*- 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 // Operations on AST nodes that are used in flow-sensitive analysis. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Analysis/FlowSensitive/ASTOps.h" 14 #include "clang/AST/ComputeDependence.h" 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/DeclBase.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/Stmt.h" 21 #include "clang/AST/Type.h" 22 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 23 #include "clang/Basic/LLVM.h" 24 #include "llvm/ADT/DenseSet.h" 25 #include "llvm/ADT/STLExtras.h" 26 #include <cassert> 27 #include <iterator> 28 #include <vector> 29 30 #define DEBUG_TYPE "dataflow" 31 32 namespace clang::dataflow { 33 34 const Expr &ignoreCFGOmittedNodes(const Expr &E) { 35 const Expr *Current = &E; 36 const Expr *Last = nullptr; 37 while (Current != Last) { 38 Last = Current; 39 if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) { 40 Current = EWC->getSubExpr(); 41 assert(Current != nullptr); 42 } 43 if (auto *CE = dyn_cast<ConstantExpr>(Current)) { 44 Current = CE->getSubExpr(); 45 assert(Current != nullptr); 46 } 47 Current = Current->IgnoreParens(); 48 assert(Current != nullptr); 49 } 50 return *Current; 51 } 52 53 const Stmt &ignoreCFGOmittedNodes(const Stmt &S) { 54 if (auto *E = dyn_cast<Expr>(&S)) 55 return ignoreCFGOmittedNodes(*E); 56 return S; 57 } 58 59 // FIXME: Does not precisely handle non-virtual diamond inheritance. A single 60 // field decl will be modeled for all instances of the inherited field. 61 static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields) { 62 if (Type->isIncompleteType() || Type->isDependentType() || 63 !Type->isRecordType()) 64 return; 65 66 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) 67 Fields.insert(Field); 68 if (auto *CXXRecord = Type->getAsCXXRecordDecl()) 69 for (const CXXBaseSpecifier &Base : CXXRecord->bases()) 70 getFieldsFromClassHierarchy(Base.getType(), Fields); 71 } 72 73 /// Gets the set of all fields in the type. 74 FieldSet getObjectFields(QualType Type) { 75 FieldSet Fields; 76 getFieldsFromClassHierarchy(Type, Fields); 77 return Fields; 78 } 79 80 bool containsSameFields(const FieldSet &Fields, 81 const RecordStorageLocation::FieldToLoc &FieldLocs) { 82 if (Fields.size() != FieldLocs.size()) 83 return false; 84 for ([[maybe_unused]] auto [Field, Loc] : FieldLocs) 85 if (!Fields.contains(cast_or_null<FieldDecl>(Field))) 86 return false; 87 return true; 88 } 89 90 /// Returns the fields of a `RecordDecl` that are initialized by an 91 /// `InitListExpr` or `CXXParenListInitExpr`, in the order in which they appear 92 /// in `InitListExpr::inits()` / `CXXParenListInitExpr::getInitExprs()`. 93 /// `InitList->getType()` must be a record type. 94 template <class InitListT> 95 static std::vector<const FieldDecl *> 96 getFieldsForInitListExpr(const InitListT *InitList) { 97 const RecordDecl *RD = InitList->getType()->getAsRecordDecl(); 98 assert(RD != nullptr); 99 100 std::vector<const FieldDecl *> Fields; 101 102 if (InitList->getType()->isUnionType()) { 103 if (const FieldDecl *Field = InitList->getInitializedFieldInUnion()) 104 Fields.push_back(Field); 105 return Fields; 106 } 107 108 // Unnamed bitfields are only used for padding and do not appear in 109 // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s 110 // field list, and we thus need to remove them before mapping inits to 111 // fields to avoid mapping inits to the wrongs fields. 112 llvm::copy_if( 113 RD->fields(), std::back_inserter(Fields), 114 [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); }); 115 return Fields; 116 } 117 118 RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) 119 : RecordInitListHelper(InitList->getType(), 120 getFieldsForInitListExpr(InitList), 121 InitList->inits()) {} 122 123 RecordInitListHelper::RecordInitListHelper( 124 const CXXParenListInitExpr *ParenInitList) 125 : RecordInitListHelper(ParenInitList->getType(), 126 getFieldsForInitListExpr(ParenInitList), 127 ParenInitList->getInitExprs()) {} 128 129 RecordInitListHelper::RecordInitListHelper( 130 QualType Ty, std::vector<const FieldDecl *> Fields, 131 ArrayRef<Expr *> Inits) { 132 auto *RD = Ty->getAsCXXRecordDecl(); 133 assert(RD != nullptr); 134 135 // Unions initialized with an empty initializer list need special treatment. 136 // For structs/classes initialized with an empty initializer list, Clang 137 // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, 138 // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. 139 SmallVector<Expr *> InitsForUnion; 140 if (Ty->isUnionType() && Inits.empty()) { 141 assert(Fields.size() <= 1); 142 if (!Fields.empty()) { 143 ImplicitValueInitForUnion.emplace(Fields.front()->getType()); 144 InitsForUnion.push_back(&*ImplicitValueInitForUnion); 145 } 146 Inits = InitsForUnion; 147 } 148 149 size_t InitIdx = 0; 150 151 assert(Fields.size() + RD->getNumBases() == Inits.size()); 152 for (const CXXBaseSpecifier &Base : RD->bases()) { 153 assert(InitIdx < Inits.size()); 154 Expr *Init = Inits[InitIdx++]; 155 BaseInits.emplace_back(&Base, Init); 156 } 157 158 assert(Fields.size() == Inits.size() - InitIdx); 159 for (const FieldDecl *Field : Fields) { 160 assert(InitIdx < Inits.size()); 161 Expr *Init = Inits[InitIdx++]; 162 FieldInits.emplace_back(Field, Init); 163 } 164 } 165 166 static void insertIfGlobal(const Decl &D, 167 llvm::DenseSet<const VarDecl *> &Globals) { 168 if (auto *V = dyn_cast<VarDecl>(&D)) 169 if (V->hasGlobalStorage()) 170 Globals.insert(V); 171 } 172 173 static void insertIfLocal(const Decl &D, 174 llvm::DenseSet<const VarDecl *> &Locals) { 175 if (auto *V = dyn_cast<VarDecl>(&D)) 176 if (V->hasLocalStorage() && !isa<ParmVarDecl>(V)) 177 Locals.insert(V); 178 } 179 180 static void insertIfFunction(const Decl &D, 181 llvm::DenseSet<const FunctionDecl *> &Funcs) { 182 if (auto *FD = dyn_cast<FunctionDecl>(&D)) 183 Funcs.insert(FD); 184 } 185 186 static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) { 187 // Use getCalleeDecl instead of getMethodDecl in order to handle 188 // pointer-to-member calls. 189 const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl()); 190 if (!MethodDecl) 191 return nullptr; 192 auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody()); 193 if (!Body || Body->size() != 1) 194 return nullptr; 195 if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin())) 196 if (auto *Return = RS->getRetValue()) 197 return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts()); 198 return nullptr; 199 } 200 201 class ReferencedDeclsVisitor 202 : public AnalysisASTVisitor<ReferencedDeclsVisitor> { 203 public: 204 ReferencedDeclsVisitor(ReferencedDecls &Referenced) 205 : Referenced(Referenced) {} 206 207 void TraverseConstructorInits(const CXXConstructorDecl *Ctor) { 208 for (const CXXCtorInitializer *Init : Ctor->inits()) { 209 if (Init->isMemberInitializer()) { 210 Referenced.Fields.insert(Init->getMember()); 211 } else if (Init->isIndirectMemberInitializer()) { 212 for (const auto *I : Init->getIndirectMember()->chain()) 213 Referenced.Fields.insert(cast<FieldDecl>(I)); 214 } 215 216 Expr *InitExpr = Init->getInit(); 217 218 // Also collect declarations referenced in `InitExpr`. 219 TraverseStmt(InitExpr); 220 221 // If this is a `CXXDefaultInitExpr`, also collect declarations referenced 222 // within the default expression. 223 if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr)) 224 TraverseStmt(DefaultInit->getExpr()); 225 } 226 } 227 228 bool VisitDecl(Decl *D) { 229 insertIfGlobal(*D, Referenced.Globals); 230 insertIfLocal(*D, Referenced.Locals); 231 insertIfFunction(*D, Referenced.Functions); 232 return true; 233 } 234 235 bool VisitDeclRefExpr(DeclRefExpr *E) { 236 insertIfGlobal(*E->getDecl(), Referenced.Globals); 237 insertIfLocal(*E->getDecl(), Referenced.Locals); 238 insertIfFunction(*E->getDecl(), Referenced.Functions); 239 return true; 240 } 241 242 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) { 243 // If this is a method that returns a member variable but does nothing else, 244 // model the field of the return value. 245 if (MemberExpr *E = getMemberForAccessor(*C)) 246 if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) 247 Referenced.Fields.insert(FD); 248 return true; 249 } 250 251 bool VisitMemberExpr(MemberExpr *E) { 252 // FIXME: should we be using `E->getFoundDecl()`? 253 const ValueDecl *VD = E->getMemberDecl(); 254 insertIfGlobal(*VD, Referenced.Globals); 255 insertIfFunction(*VD, Referenced.Functions); 256 if (const auto *FD = dyn_cast<FieldDecl>(VD)) 257 Referenced.Fields.insert(FD); 258 return true; 259 } 260 261 bool VisitInitListExpr(InitListExpr *InitList) { 262 if (InitList->getType()->isRecordType()) 263 for (const auto *FD : getFieldsForInitListExpr(InitList)) 264 Referenced.Fields.insert(FD); 265 return true; 266 } 267 268 bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) { 269 if (ParenInitList->getType()->isRecordType()) 270 for (const auto *FD : getFieldsForInitListExpr(ParenInitList)) 271 Referenced.Fields.insert(FD); 272 return true; 273 } 274 275 private: 276 ReferencedDecls &Referenced; 277 }; 278 279 ReferencedDecls getReferencedDecls(const FunctionDecl &FD) { 280 ReferencedDecls Result; 281 ReferencedDeclsVisitor Visitor(Result); 282 Visitor.TraverseStmt(FD.getBody()); 283 if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD)) 284 Visitor.TraverseConstructorInits(CtorDecl); 285 286 return Result; 287 } 288 289 ReferencedDecls getReferencedDecls(const Stmt &S) { 290 ReferencedDecls Result; 291 ReferencedDeclsVisitor Visitor(Result); 292 Visitor.TraverseStmt(const_cast<Stmt *>(&S)); 293 return Result; 294 } 295 296 } // namespace clang::dataflow 297