1 //===-- RecordOps.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 // Operations on records (structs, classes, and unions). 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Analysis/FlowSensitive/RecordOps.h" 14 15 #define DEBUG_TYPE "dataflow" 16 17 namespace clang::dataflow { 18 19 static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc, 20 StorageLocation *DstFieldLoc, RecordStorageLocation &Dst, 21 Environment &Env) { 22 assert(Field.getType()->isReferenceType() || 23 (SrcFieldLoc != nullptr && DstFieldLoc != nullptr)); 24 25 if (Field.getType()->isRecordType()) { 26 copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc), 27 cast<RecordStorageLocation>(*DstFieldLoc), Env); 28 } else if (Field.getType()->isReferenceType()) { 29 Dst.setChild(Field, SrcFieldLoc); 30 } else { 31 if (Value *Val = Env.getValue(*SrcFieldLoc)) 32 Env.setValue(*DstFieldLoc, *Val); 33 else 34 Env.clearValue(*DstFieldLoc); 35 } 36 } 37 38 static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc, 39 StorageLocation &DstFieldLoc, Environment &Env) { 40 if (FieldType->isRecordType()) { 41 copyRecord(cast<RecordStorageLocation>(SrcFieldLoc), 42 cast<RecordStorageLocation>(DstFieldLoc), Env); 43 } else { 44 if (Value *Val = Env.getValue(SrcFieldLoc)) 45 Env.setValue(DstFieldLoc, *Val); 46 else 47 Env.clearValue(DstFieldLoc); 48 } 49 } 50 51 void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, 52 Environment &Env) { 53 auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType(); 54 auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType(); 55 56 auto SrcDecl = SrcType->getAsCXXRecordDecl(); 57 auto DstDecl = DstType->getAsCXXRecordDecl(); 58 59 [[maybe_unused]] bool compatibleTypes = 60 SrcType == DstType || 61 (SrcDecl != nullptr && DstDecl != nullptr && 62 (SrcDecl->isDerivedFrom(DstDecl) || DstDecl->isDerivedFrom(SrcDecl))); 63 64 LLVM_DEBUG({ 65 if (!compatibleTypes) { 66 llvm::dbgs() << "Source type " << Src.getType() << "\n"; 67 llvm::dbgs() << "Destination type " << Dst.getType() << "\n"; 68 } 69 }); 70 assert(compatibleTypes); 71 72 if (SrcType == DstType || (SrcDecl != nullptr && DstDecl != nullptr && 73 SrcDecl->isDerivedFrom(DstDecl))) { 74 for (auto [Field, DstFieldLoc] : Dst.children()) 75 copyField(*Field, Src.getChild(*Field), DstFieldLoc, Dst, Env); 76 for (const auto &[Name, DstFieldLoc] : Dst.synthetic_fields()) 77 copySyntheticField(DstFieldLoc->getType(), Src.getSyntheticField(Name), 78 *DstFieldLoc, Env); 79 } else { 80 for (auto [Field, SrcFieldLoc] : Src.children()) 81 copyField(*Field, SrcFieldLoc, Dst.getChild(*Field), Dst, Env); 82 for (const auto &[Name, SrcFieldLoc] : Src.synthetic_fields()) 83 copySyntheticField(SrcFieldLoc->getType(), *SrcFieldLoc, 84 Dst.getSyntheticField(Name), Env); 85 } 86 } 87 88 bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1, 89 const RecordStorageLocation &Loc2, const Environment &Env2) { 90 LLVM_DEBUG({ 91 if (Loc2.getType().getCanonicalType().getUnqualifiedType() != 92 Loc1.getType().getCanonicalType().getUnqualifiedType()) { 93 llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n"; 94 llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n"; 95 } 96 }); 97 assert(Loc2.getType().getCanonicalType().getUnqualifiedType() == 98 Loc1.getType().getCanonicalType().getUnqualifiedType()); 99 100 for (auto [Field, FieldLoc1] : Loc1.children()) { 101 StorageLocation *FieldLoc2 = Loc2.getChild(*Field); 102 103 assert(Field->getType()->isReferenceType() || 104 (FieldLoc1 != nullptr && FieldLoc2 != nullptr)); 105 106 if (Field->getType()->isRecordType()) { 107 if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1, 108 cast<RecordStorageLocation>(*FieldLoc2), Env2)) 109 return false; 110 } else if (Field->getType()->isReferenceType()) { 111 if (FieldLoc1 != FieldLoc2) 112 return false; 113 } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) { 114 return false; 115 } 116 } 117 118 for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) { 119 if (SynthFieldLoc1->getType()->isRecordType()) { 120 if (!recordsEqual( 121 *cast<RecordStorageLocation>(SynthFieldLoc1), Env1, 122 cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2)) 123 return false; 124 } else if (Env1.getValue(*SynthFieldLoc1) != 125 Env2.getValue(Loc2.getSyntheticField(Name))) { 126 return false; 127 } 128 } 129 130 return true; 131 } 132 133 } // namespace clang::dataflow 134