1 //===-- RecordOps.cpp -------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Operations on records (structs, classes, and unions).
11 //===----------------------------------------------------------------------===//
13 #include "clang/Analysis/FlowSensitive/RecordOps.h"
15 #define DEBUG_TYPE "dataflow"
17 namespace clang::dataflow
{
19 static void copyField(const ValueDecl
&Field
, StorageLocation
*SrcFieldLoc
,
20 StorageLocation
*DstFieldLoc
, RecordStorageLocation
&Dst
,
22 assert(Field
.getType()->isReferenceType() ||
23 (SrcFieldLoc
!= nullptr && DstFieldLoc
!= nullptr));
25 if (Field
.getType()->isRecordType()) {
26 copyRecord(cast
<RecordStorageLocation
>(*SrcFieldLoc
),
27 cast
<RecordStorageLocation
>(*DstFieldLoc
), Env
);
28 } else if (Field
.getType()->isReferenceType()) {
29 Dst
.setChild(Field
, SrcFieldLoc
);
31 if (Value
*Val
= Env
.getValue(*SrcFieldLoc
))
32 Env
.setValue(*DstFieldLoc
, *Val
);
34 Env
.clearValue(*DstFieldLoc
);
38 static void copySyntheticField(QualType FieldType
, StorageLocation
&SrcFieldLoc
,
39 StorageLocation
&DstFieldLoc
, Environment
&Env
) {
40 if (FieldType
->isRecordType()) {
41 copyRecord(cast
<RecordStorageLocation
>(SrcFieldLoc
),
42 cast
<RecordStorageLocation
>(DstFieldLoc
), Env
);
44 if (Value
*Val
= Env
.getValue(SrcFieldLoc
))
45 Env
.setValue(DstFieldLoc
, *Val
);
47 Env
.clearValue(DstFieldLoc
);
51 void copyRecord(RecordStorageLocation
&Src
, RecordStorageLocation
&Dst
,
53 auto SrcType
= Src
.getType().getCanonicalType().getUnqualifiedType();
54 auto DstType
= Dst
.getType().getCanonicalType().getUnqualifiedType();
56 auto SrcDecl
= SrcType
->getAsCXXRecordDecl();
57 auto DstDecl
= DstType
->getAsCXXRecordDecl();
59 [[maybe_unused
]] bool compatibleTypes
=
61 (SrcDecl
!= nullptr && DstDecl
!= nullptr &&
62 (SrcDecl
->isDerivedFrom(DstDecl
) || DstDecl
->isDerivedFrom(SrcDecl
)));
65 if (!compatibleTypes
) {
66 llvm::dbgs() << "Source type " << Src
.getType() << "\n";
67 llvm::dbgs() << "Destination type " << Dst
.getType() << "\n";
70 assert(compatibleTypes
);
72 if (SrcType
== DstType
|| (SrcDecl
!= nullptr && DstDecl
!= nullptr &&
73 SrcDecl
->isDerivedFrom(DstDecl
))) {
74 for (auto [Field
, DstFieldLoc
] : Dst
.children())
75 copyField(*Field
, Src
.getChild(*Field
), DstFieldLoc
, Dst
, Env
);
76 for (const auto &[Name
, DstFieldLoc
] : Dst
.synthetic_fields())
77 copySyntheticField(DstFieldLoc
->getType(), Src
.getSyntheticField(Name
),
80 for (auto [Field
, SrcFieldLoc
] : Src
.children())
81 copyField(*Field
, SrcFieldLoc
, Dst
.getChild(*Field
), Dst
, Env
);
82 for (const auto &[Name
, SrcFieldLoc
] : Src
.synthetic_fields())
83 copySyntheticField(SrcFieldLoc
->getType(), *SrcFieldLoc
,
84 Dst
.getSyntheticField(Name
), Env
);
88 bool recordsEqual(const RecordStorageLocation
&Loc1
, const Environment
&Env1
,
89 const RecordStorageLocation
&Loc2
, const Environment
&Env2
) {
91 if (Loc2
.getType().getCanonicalType().getUnqualifiedType() !=
92 Loc1
.getType().getCanonicalType().getUnqualifiedType()) {
93 llvm::dbgs() << "Loc1 type " << Loc1
.getType() << "\n";
94 llvm::dbgs() << "Loc2 type " << Loc2
.getType() << "\n";
97 assert(Loc2
.getType().getCanonicalType().getUnqualifiedType() ==
98 Loc1
.getType().getCanonicalType().getUnqualifiedType());
100 for (auto [Field
, FieldLoc1
] : Loc1
.children()) {
101 StorageLocation
*FieldLoc2
= Loc2
.getChild(*Field
);
103 assert(Field
->getType()->isReferenceType() ||
104 (FieldLoc1
!= nullptr && FieldLoc2
!= nullptr));
106 if (Field
->getType()->isRecordType()) {
107 if (!recordsEqual(cast
<RecordStorageLocation
>(*FieldLoc1
), Env1
,
108 cast
<RecordStorageLocation
>(*FieldLoc2
), Env2
))
110 } else if (Field
->getType()->isReferenceType()) {
111 if (FieldLoc1
!= FieldLoc2
)
113 } else if (Env1
.getValue(*FieldLoc1
) != Env2
.getValue(*FieldLoc2
)) {
118 for (const auto &[Name
, SynthFieldLoc1
] : Loc1
.synthetic_fields()) {
119 if (SynthFieldLoc1
->getType()->isRecordType()) {
121 *cast
<RecordStorageLocation
>(SynthFieldLoc1
), Env1
,
122 cast
<RecordStorageLocation
>(Loc2
.getSyntheticField(Name
)), Env2
))
124 } else if (Env1
.getValue(*SynthFieldLoc1
) !=
125 Env2
.getValue(Loc2
.getSyntheticField(Name
))) {
133 } // namespace clang::dataflow