106c3fb27SDimitry Andric //===-- RecordOps.cpp -------------------------------------------*- C++ -*-===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // Operations on records (structs, classes, and unions). 1006c3fb27SDimitry Andric // 1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/RecordOps.h" 1406c3fb27SDimitry Andric 1506c3fb27SDimitry Andric #define DEBUG_TYPE "dataflow" 1606c3fb27SDimitry Andric 17*0fca6ea1SDimitry Andric namespace clang::dataflow { 18*0fca6ea1SDimitry Andric 19*0fca6ea1SDimitry Andric static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc, 20*0fca6ea1SDimitry Andric StorageLocation *DstFieldLoc, RecordStorageLocation &Dst, 21*0fca6ea1SDimitry Andric Environment &Env) { 22*0fca6ea1SDimitry Andric assert(Field.getType()->isReferenceType() || 23*0fca6ea1SDimitry Andric (SrcFieldLoc != nullptr && DstFieldLoc != nullptr)); 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric if (Field.getType()->isRecordType()) { 26*0fca6ea1SDimitry Andric copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc), 27*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(*DstFieldLoc), Env); 28*0fca6ea1SDimitry Andric } else if (Field.getType()->isReferenceType()) { 29*0fca6ea1SDimitry Andric Dst.setChild(Field, SrcFieldLoc); 30*0fca6ea1SDimitry Andric } else { 31*0fca6ea1SDimitry Andric if (Value *Val = Env.getValue(*SrcFieldLoc)) 32*0fca6ea1SDimitry Andric Env.setValue(*DstFieldLoc, *Val); 33*0fca6ea1SDimitry Andric else 34*0fca6ea1SDimitry Andric Env.clearValue(*DstFieldLoc); 35*0fca6ea1SDimitry Andric } 36*0fca6ea1SDimitry Andric } 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc, 39*0fca6ea1SDimitry Andric StorageLocation &DstFieldLoc, Environment &Env) { 40*0fca6ea1SDimitry Andric if (FieldType->isRecordType()) { 41*0fca6ea1SDimitry Andric copyRecord(cast<RecordStorageLocation>(SrcFieldLoc), 42*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(DstFieldLoc), Env); 43*0fca6ea1SDimitry Andric } else { 44*0fca6ea1SDimitry Andric if (Value *Val = Env.getValue(SrcFieldLoc)) 45*0fca6ea1SDimitry Andric Env.setValue(DstFieldLoc, *Val); 46*0fca6ea1SDimitry Andric else 47*0fca6ea1SDimitry Andric Env.clearValue(DstFieldLoc); 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric } 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, 52*0fca6ea1SDimitry Andric Environment &Env) { 535f757f3fSDimitry Andric auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType(); 545f757f3fSDimitry Andric auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType(); 555f757f3fSDimitry Andric 565f757f3fSDimitry Andric auto SrcDecl = SrcType->getAsCXXRecordDecl(); 575f757f3fSDimitry Andric auto DstDecl = DstType->getAsCXXRecordDecl(); 585f757f3fSDimitry Andric 59*0fca6ea1SDimitry Andric [[maybe_unused]] bool compatibleTypes = 605f757f3fSDimitry Andric SrcType == DstType || 61*0fca6ea1SDimitry Andric (SrcDecl != nullptr && DstDecl != nullptr && 62*0fca6ea1SDimitry Andric (SrcDecl->isDerivedFrom(DstDecl) || DstDecl->isDerivedFrom(SrcDecl))); 635f757f3fSDimitry Andric 6406c3fb27SDimitry Andric LLVM_DEBUG({ 655f757f3fSDimitry Andric if (!compatibleTypes) { 6606c3fb27SDimitry Andric llvm::dbgs() << "Source type " << Src.getType() << "\n"; 6706c3fb27SDimitry Andric llvm::dbgs() << "Destination type " << Dst.getType() << "\n"; 6806c3fb27SDimitry Andric } 6906c3fb27SDimitry Andric }); 705f757f3fSDimitry Andric assert(compatibleTypes); 7106c3fb27SDimitry Andric 72*0fca6ea1SDimitry Andric if (SrcType == DstType || (SrcDecl != nullptr && DstDecl != nullptr && 73*0fca6ea1SDimitry Andric SrcDecl->isDerivedFrom(DstDecl))) { 74*0fca6ea1SDimitry Andric for (auto [Field, DstFieldLoc] : Dst.children()) 75*0fca6ea1SDimitry Andric copyField(*Field, Src.getChild(*Field), DstFieldLoc, Dst, Env); 76*0fca6ea1SDimitry Andric for (const auto &[Name, DstFieldLoc] : Dst.synthetic_fields()) 77*0fca6ea1SDimitry Andric copySyntheticField(DstFieldLoc->getType(), Src.getSyntheticField(Name), 78*0fca6ea1SDimitry Andric *DstFieldLoc, Env); 7906c3fb27SDimitry Andric } else { 80*0fca6ea1SDimitry Andric for (auto [Field, SrcFieldLoc] : Src.children()) 81*0fca6ea1SDimitry Andric copyField(*Field, SrcFieldLoc, Dst.getChild(*Field), Dst, Env); 82*0fca6ea1SDimitry Andric for (const auto &[Name, SrcFieldLoc] : Src.synthetic_fields()) 83*0fca6ea1SDimitry Andric copySyntheticField(SrcFieldLoc->getType(), *SrcFieldLoc, 84*0fca6ea1SDimitry Andric Dst.getSyntheticField(Name), Env); 8506c3fb27SDimitry Andric } 8606c3fb27SDimitry Andric } 8706c3fb27SDimitry Andric 88*0fca6ea1SDimitry Andric bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1, 89*0fca6ea1SDimitry Andric const RecordStorageLocation &Loc2, const Environment &Env2) { 9006c3fb27SDimitry Andric LLVM_DEBUG({ 9106c3fb27SDimitry Andric if (Loc2.getType().getCanonicalType().getUnqualifiedType() != 9206c3fb27SDimitry Andric Loc1.getType().getCanonicalType().getUnqualifiedType()) { 9306c3fb27SDimitry Andric llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n"; 9406c3fb27SDimitry Andric llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n"; 9506c3fb27SDimitry Andric } 9606c3fb27SDimitry Andric }); 9706c3fb27SDimitry Andric assert(Loc2.getType().getCanonicalType().getUnqualifiedType() == 9806c3fb27SDimitry Andric Loc1.getType().getCanonicalType().getUnqualifiedType()); 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric for (auto [Field, FieldLoc1] : Loc1.children()) { 10106c3fb27SDimitry Andric StorageLocation *FieldLoc2 = Loc2.getChild(*Field); 10206c3fb27SDimitry Andric 10306c3fb27SDimitry Andric assert(Field->getType()->isReferenceType() || 10406c3fb27SDimitry Andric (FieldLoc1 != nullptr && FieldLoc2 != nullptr)); 10506c3fb27SDimitry Andric 10606c3fb27SDimitry Andric if (Field->getType()->isRecordType()) { 1075f757f3fSDimitry Andric if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1, 1085f757f3fSDimitry Andric cast<RecordStorageLocation>(*FieldLoc2), Env2)) 10906c3fb27SDimitry Andric return false; 11006c3fb27SDimitry Andric } else if (Field->getType()->isReferenceType()) { 11106c3fb27SDimitry Andric if (FieldLoc1 != FieldLoc2) 11206c3fb27SDimitry Andric return false; 11306c3fb27SDimitry Andric } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) { 11406c3fb27SDimitry Andric return false; 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric } 11706c3fb27SDimitry Andric 1185f757f3fSDimitry Andric for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) { 1195f757f3fSDimitry Andric if (SynthFieldLoc1->getType()->isRecordType()) { 1205f757f3fSDimitry Andric if (!recordsEqual( 1215f757f3fSDimitry Andric *cast<RecordStorageLocation>(SynthFieldLoc1), Env1, 1225f757f3fSDimitry Andric cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2)) 1235f757f3fSDimitry Andric return false; 1245f757f3fSDimitry Andric } else if (Env1.getValue(*SynthFieldLoc1) != 1255f757f3fSDimitry Andric Env2.getValue(Loc2.getSyntheticField(Name))) { 1265f757f3fSDimitry Andric return false; 1275f757f3fSDimitry Andric } 1285f757f3fSDimitry Andric } 1295f757f3fSDimitry Andric 13006c3fb27SDimitry Andric return true; 13106c3fb27SDimitry Andric } 132*0fca6ea1SDimitry Andric 133*0fca6ea1SDimitry Andric } // namespace clang::dataflow 134