1fe013be4SDimitry Andric //===-- RecordOps.cpp -------------------------------------------*- C++ -*-===//
2fe013be4SDimitry Andric //
3fe013be4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe013be4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe013be4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe013be4SDimitry Andric //
7fe013be4SDimitry Andric //===----------------------------------------------------------------------===//
8fe013be4SDimitry Andric //
9fe013be4SDimitry Andric // Operations on records (structs, classes, and unions).
10fe013be4SDimitry Andric //
11fe013be4SDimitry Andric //===----------------------------------------------------------------------===//
12fe013be4SDimitry Andric
13fe013be4SDimitry Andric #include "clang/Analysis/FlowSensitive/RecordOps.h"
14fe013be4SDimitry Andric
15fe013be4SDimitry Andric #define DEBUG_TYPE "dataflow"
16fe013be4SDimitry Andric
copyRecord(RecordStorageLocation & Src,RecordStorageLocation & Dst,Environment & Env)17c9157d92SDimitry Andric void clang::dataflow::copyRecord(RecordStorageLocation &Src,
18c9157d92SDimitry Andric RecordStorageLocation &Dst, Environment &Env) {
19c9157d92SDimitry Andric auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType();
20c9157d92SDimitry Andric auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType();
21c9157d92SDimitry Andric
22c9157d92SDimitry Andric auto SrcDecl = SrcType->getAsCXXRecordDecl();
23c9157d92SDimitry Andric auto DstDecl = DstType->getAsCXXRecordDecl();
24c9157d92SDimitry Andric
25c9157d92SDimitry Andric bool compatibleTypes =
26c9157d92SDimitry Andric SrcType == DstType ||
27c9157d92SDimitry Andric (SrcDecl && DstDecl && SrcDecl->isDerivedFrom(DstDecl));
28c9157d92SDimitry Andric (void)compatibleTypes;
29c9157d92SDimitry Andric
30fe013be4SDimitry Andric LLVM_DEBUG({
31c9157d92SDimitry Andric if (!compatibleTypes) {
32fe013be4SDimitry Andric llvm::dbgs() << "Source type " << Src.getType() << "\n";
33fe013be4SDimitry Andric llvm::dbgs() << "Destination type " << Dst.getType() << "\n";
34fe013be4SDimitry Andric }
35fe013be4SDimitry Andric });
36c9157d92SDimitry Andric assert(compatibleTypes);
37fe013be4SDimitry Andric
38c9157d92SDimitry Andric for (auto [Field, DstFieldLoc] : Dst.children()) {
39c9157d92SDimitry Andric StorageLocation *SrcFieldLoc = Src.getChild(*Field);
40fe013be4SDimitry Andric
41fe013be4SDimitry Andric assert(Field->getType()->isReferenceType() ||
42fe013be4SDimitry Andric (SrcFieldLoc != nullptr && DstFieldLoc != nullptr));
43fe013be4SDimitry Andric
44fe013be4SDimitry Andric if (Field->getType()->isRecordType()) {
45c9157d92SDimitry Andric copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc),
46c9157d92SDimitry Andric cast<RecordStorageLocation>(*DstFieldLoc), Env);
47fe013be4SDimitry Andric } else if (Field->getType()->isReferenceType()) {
48fe013be4SDimitry Andric Dst.setChild(*Field, SrcFieldLoc);
49fe013be4SDimitry Andric } else {
50fe013be4SDimitry Andric if (Value *Val = Env.getValue(*SrcFieldLoc))
51fe013be4SDimitry Andric Env.setValue(*DstFieldLoc, *Val);
52fe013be4SDimitry Andric else
53fe013be4SDimitry Andric Env.clearValue(*DstFieldLoc);
54fe013be4SDimitry Andric }
55fe013be4SDimitry Andric }
56fe013be4SDimitry Andric
57c9157d92SDimitry Andric for (const auto &[Name, SynthFieldLoc] : Src.synthetic_fields()) {
58c9157d92SDimitry Andric if (SynthFieldLoc->getType()->isRecordType()) {
59c9157d92SDimitry Andric copyRecord(*cast<RecordStorageLocation>(SynthFieldLoc),
60c9157d92SDimitry Andric cast<RecordStorageLocation>(Dst.getSyntheticField(Name)), Env);
61c9157d92SDimitry Andric } else {
62c9157d92SDimitry Andric if (Value *Val = Env.getValue(*SynthFieldLoc))
63c9157d92SDimitry Andric Env.setValue(Dst.getSyntheticField(Name), *Val);
64c9157d92SDimitry Andric else
65c9157d92SDimitry Andric Env.clearValue(Dst.getSyntheticField(Name));
66c9157d92SDimitry Andric }
67c9157d92SDimitry Andric }
68fe013be4SDimitry Andric
69*e710425bSDimitry Andric RecordValue *DstVal = &Env.create<RecordValue>(Dst);
70fe013be4SDimitry Andric Env.setValue(Dst, *DstVal);
71fe013be4SDimitry Andric }
72fe013be4SDimitry Andric
recordsEqual(const RecordStorageLocation & Loc1,const Environment & Env1,const RecordStorageLocation & Loc2,const Environment & Env2)73c9157d92SDimitry Andric bool clang::dataflow::recordsEqual(const RecordStorageLocation &Loc1,
74fe013be4SDimitry Andric const Environment &Env1,
75c9157d92SDimitry Andric const RecordStorageLocation &Loc2,
76fe013be4SDimitry Andric const Environment &Env2) {
77fe013be4SDimitry Andric LLVM_DEBUG({
78fe013be4SDimitry Andric if (Loc2.getType().getCanonicalType().getUnqualifiedType() !=
79fe013be4SDimitry Andric Loc1.getType().getCanonicalType().getUnqualifiedType()) {
80fe013be4SDimitry Andric llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n";
81fe013be4SDimitry Andric llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n";
82fe013be4SDimitry Andric }
83fe013be4SDimitry Andric });
84fe013be4SDimitry Andric assert(Loc2.getType().getCanonicalType().getUnqualifiedType() ==
85fe013be4SDimitry Andric Loc1.getType().getCanonicalType().getUnqualifiedType());
86fe013be4SDimitry Andric
87fe013be4SDimitry Andric for (auto [Field, FieldLoc1] : Loc1.children()) {
88fe013be4SDimitry Andric StorageLocation *FieldLoc2 = Loc2.getChild(*Field);
89fe013be4SDimitry Andric
90fe013be4SDimitry Andric assert(Field->getType()->isReferenceType() ||
91fe013be4SDimitry Andric (FieldLoc1 != nullptr && FieldLoc2 != nullptr));
92fe013be4SDimitry Andric
93fe013be4SDimitry Andric if (Field->getType()->isRecordType()) {
94c9157d92SDimitry Andric if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,
95c9157d92SDimitry Andric cast<RecordStorageLocation>(*FieldLoc2), Env2))
96fe013be4SDimitry Andric return false;
97fe013be4SDimitry Andric } else if (Field->getType()->isReferenceType()) {
98fe013be4SDimitry Andric if (FieldLoc1 != FieldLoc2)
99fe013be4SDimitry Andric return false;
100fe013be4SDimitry Andric } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {
101fe013be4SDimitry Andric return false;
102fe013be4SDimitry Andric }
103fe013be4SDimitry Andric }
104fe013be4SDimitry Andric
105c9157d92SDimitry Andric for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {
106c9157d92SDimitry Andric if (SynthFieldLoc1->getType()->isRecordType()) {
107c9157d92SDimitry Andric if (!recordsEqual(
108c9157d92SDimitry Andric *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,
109c9157d92SDimitry Andric cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2))
110c9157d92SDimitry Andric return false;
111c9157d92SDimitry Andric } else if (Env1.getValue(*SynthFieldLoc1) !=
112c9157d92SDimitry Andric Env2.getValue(Loc2.getSyntheticField(Name))) {
113c9157d92SDimitry Andric return false;
114c9157d92SDimitry Andric }
115c9157d92SDimitry Andric }
116c9157d92SDimitry Andric
117fe013be4SDimitry Andric return true;
118fe013be4SDimitry Andric }
119