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 void clang::dataflow::copyRecord(RecordStorageLocation &Src, 18 RecordStorageLocation &Dst, Environment &Env) { 19 auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType(); 20 auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType(); 21 22 auto SrcDecl = SrcType->getAsCXXRecordDecl(); 23 auto DstDecl = DstType->getAsCXXRecordDecl(); 24 25 bool compatibleTypes = 26 SrcType == DstType || 27 (SrcDecl && DstDecl && SrcDecl->isDerivedFrom(DstDecl)); 28 (void)compatibleTypes; 29 30 LLVM_DEBUG({ 31 if (!compatibleTypes) { 32 llvm::dbgs() << "Source type " << Src.getType() << "\n"; 33 llvm::dbgs() << "Destination type " << Dst.getType() << "\n"; 34 } 35 }); 36 assert(compatibleTypes); 37 38 for (auto [Field, DstFieldLoc] : Dst.children()) { 39 StorageLocation *SrcFieldLoc = Src.getChild(*Field); 40 41 assert(Field->getType()->isReferenceType() || 42 (SrcFieldLoc != nullptr && DstFieldLoc != nullptr)); 43 44 if (Field->getType()->isRecordType()) { 45 copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc), 46 cast<RecordStorageLocation>(*DstFieldLoc), Env); 47 } else if (Field->getType()->isReferenceType()) { 48 Dst.setChild(*Field, SrcFieldLoc); 49 } else { 50 if (Value *Val = Env.getValue(*SrcFieldLoc)) 51 Env.setValue(*DstFieldLoc, *Val); 52 else 53 Env.clearValue(*DstFieldLoc); 54 } 55 } 56 57 for (const auto &[Name, SynthFieldLoc] : Src.synthetic_fields()) { 58 if (SynthFieldLoc->getType()->isRecordType()) { 59 copyRecord(*cast<RecordStorageLocation>(SynthFieldLoc), 60 cast<RecordStorageLocation>(Dst.getSyntheticField(Name)), Env); 61 } else { 62 if (Value *Val = Env.getValue(*SynthFieldLoc)) 63 Env.setValue(Dst.getSyntheticField(Name), *Val); 64 else 65 Env.clearValue(Dst.getSyntheticField(Name)); 66 } 67 } 68 69 RecordValue *DstVal = &Env.create<RecordValue>(Dst); 70 Env.setValue(Dst, *DstVal); 71 } 72 73 bool clang::dataflow::recordsEqual(const RecordStorageLocation &Loc1, 74 const Environment &Env1, 75 const RecordStorageLocation &Loc2, 76 const Environment &Env2) { 77 LLVM_DEBUG({ 78 if (Loc2.getType().getCanonicalType().getUnqualifiedType() != 79 Loc1.getType().getCanonicalType().getUnqualifiedType()) { 80 llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n"; 81 llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n"; 82 } 83 }); 84 assert(Loc2.getType().getCanonicalType().getUnqualifiedType() == 85 Loc1.getType().getCanonicalType().getUnqualifiedType()); 86 87 for (auto [Field, FieldLoc1] : Loc1.children()) { 88 StorageLocation *FieldLoc2 = Loc2.getChild(*Field); 89 90 assert(Field->getType()->isReferenceType() || 91 (FieldLoc1 != nullptr && FieldLoc2 != nullptr)); 92 93 if (Field->getType()->isRecordType()) { 94 if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1, 95 cast<RecordStorageLocation>(*FieldLoc2), Env2)) 96 return false; 97 } else if (Field->getType()->isReferenceType()) { 98 if (FieldLoc1 != FieldLoc2) 99 return false; 100 } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) { 101 return false; 102 } 103 } 104 105 for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) { 106 if (SynthFieldLoc1->getType()->isRecordType()) { 107 if (!recordsEqual( 108 *cast<RecordStorageLocation>(SynthFieldLoc1), Env1, 109 cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2)) 110 return false; 111 } else if (Env1.getValue(*SynthFieldLoc1) != 112 Env2.getValue(Loc2.getSyntheticField(Name))) { 113 return false; 114 } 115 } 116 117 return true; 118 } 119