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