clang 18.0.0git
RecordOps.cpp
Go to the documentation of this file.
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
14
15#define DEBUG_TYPE "dataflow"
16
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 *SrcVal = cast_or_null<RecordValue>(Env.getValue(Src));
70 RecordValue *DstVal = cast_or_null<RecordValue>(Env.getValue(Dst));
71
72 DstVal = &Env.create<RecordValue>(Dst);
73 Env.setValue(Dst, *DstVal);
74
75 if (SrcVal == nullptr)
76 return;
77
78 for (const auto &[Name, Value] : SrcVal->properties()) {
79 if (Value != nullptr)
80 DstVal->setProperty(Name, *Value);
81 }
82}
83
85 const Environment &Env1,
86 const RecordStorageLocation &Loc2,
87 const Environment &Env2) {
88 LLVM_DEBUG({
91 llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n";
92 llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n";
93 }
94 });
97
98 for (auto [Field, FieldLoc1] : Loc1.children()) {
99 StorageLocation *FieldLoc2 = Loc2.getChild(*Field);
100
101 assert(Field->getType()->isReferenceType() ||
102 (FieldLoc1 != nullptr && FieldLoc2 != nullptr));
103
104 if (Field->getType()->isRecordType()) {
105 if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,
106 cast<RecordStorageLocation>(*FieldLoc2), Env2))
107 return false;
108 } else if (Field->getType()->isReferenceType()) {
109 if (FieldLoc1 != FieldLoc2)
110 return false;
111 } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {
112 return false;
113 }
114 }
115
116 for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {
117 if (SynthFieldLoc1->getType()->isRecordType()) {
118 if (!recordsEqual(
119 *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,
120 cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2))
121 return false;
122 } else if (Env1.getValue(*SynthFieldLoc1) !=
123 Env2.getValue(Loc2.getSyntheticField(Name))) {
124 return false;
125 }
126 }
127
128 llvm::StringMap<Value *> Props1, Props2;
129
130 if (RecordValue *Val1 = cast_or_null<RecordValue>(Env1.getValue(Loc1)))
131 for (const auto &[Name, Value] : Val1->properties())
132 Props1[Name] = Value;
133 if (RecordValue *Val2 = cast_or_null<RecordValue>(Env2.getValue(Loc2)))
134 for (const auto &[Name, Value] : Val2->properties())
135 Props2[Name] = Value;
136
137 if (Props1.size() != Props2.size())
138 return false;
139
140 for (const auto &[Name, Value] : Props1) {
141 auto It = Props2.find(Name);
142 if (It == Props2.end())
143 return false;
144 if (Value != It->second)
145 return false;
146 }
147
148 return true;
149}
const Environment & Env
Definition: HTMLLogger.cpp:148
QualType getCanonicalType() const
Definition: Type.h:6833
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:6874
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1819
Holds the state of the program (store and heap) at a given program point.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
A storage location for a record (struct, class, or union).
llvm::iterator_range< SyntheticFieldMap::const_iterator > synthetic_fields() const
StorageLocation * getChild(const ValueDecl &D) const
Returns the child storage location for D.
void setChild(const ValueDecl &D, StorageLocation *Loc)
Changes the child storage location for a field D of reference type.
StorageLocation & getSyntheticField(llvm::StringRef Name) const
Returns the storage location for the synthetic field Name.
llvm::iterator_range< FieldToLoc::const_iterator > children() const
Models a value of struct or class type.
Definition: Value.h:216
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition: Value.h:33
void setProperty(llvm::StringRef Name, Value &Val)
Assigns Val as the value of the synthetic property with the given Name.
Definition: Value.h:66
llvm::iterator_range< llvm::StringMap< Value * >::const_iterator > properties() const
Definition: Value.h:71
bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1, const RecordStorageLocation &Loc2, const Environment &Env2)
Returns whether the records Loc1 and Loc2 are equal.
Definition: RecordOps.cpp:84
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env)
Copies a record (struct, class, or union) from Src to Dst.
Definition: RecordOps.cpp:17