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 void clang::dataflow::copyRecord(RecordStorageLocation
&Src
,
18 RecordStorageLocation
&Dst
, Environment
&Env
) {
19 auto SrcType
= Src
.getType().getCanonicalType().getUnqualifiedType();
20 auto DstType
= Dst
.getType().getCanonicalType().getUnqualifiedType();
22 auto SrcDecl
= SrcType
->getAsCXXRecordDecl();
23 auto DstDecl
= DstType
->getAsCXXRecordDecl();
25 bool compatibleTypes
=
27 (SrcDecl
&& DstDecl
&& SrcDecl
->isDerivedFrom(DstDecl
));
28 (void)compatibleTypes
;
31 if (!compatibleTypes
) {
32 llvm::dbgs() << "Source type " << Src
.getType() << "\n";
33 llvm::dbgs() << "Destination type " << Dst
.getType() << "\n";
36 assert(compatibleTypes
);
38 for (auto [Field
, DstFieldLoc
] : Dst
.children()) {
39 StorageLocation
*SrcFieldLoc
= Src
.getChild(*Field
);
41 assert(Field
->getType()->isReferenceType() ||
42 (SrcFieldLoc
!= nullptr && DstFieldLoc
!= nullptr));
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
);
50 if (Value
*Val
= Env
.getValue(*SrcFieldLoc
))
51 Env
.setValue(*DstFieldLoc
, *Val
);
53 Env
.clearValue(*DstFieldLoc
);
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
);
62 if (Value
*Val
= Env
.getValue(*SynthFieldLoc
))
63 Env
.setValue(Dst
.getSyntheticField(Name
), *Val
);
65 Env
.clearValue(Dst
.getSyntheticField(Name
));
69 RecordValue
*DstVal
= &Env
.create
<RecordValue
>(Dst
);
70 Env
.setValue(Dst
, *DstVal
);
73 bool clang::dataflow::recordsEqual(const RecordStorageLocation
&Loc1
,
74 const Environment
&Env1
,
75 const RecordStorageLocation
&Loc2
,
76 const Environment
&Env2
) {
78 if (Loc2
.getType().getCanonicalType().getUnqualifiedType() !=
79 Loc1
.getType().getCanonicalType().getUnqualifiedType()) {
80 llvm::dbgs() << "Loc1 type " << Loc1
.getType() << "\n";
81 llvm::dbgs() << "Loc2 type " << Loc2
.getType() << "\n";
84 assert(Loc2
.getType().getCanonicalType().getUnqualifiedType() ==
85 Loc1
.getType().getCanonicalType().getUnqualifiedType());
87 for (auto [Field
, FieldLoc1
] : Loc1
.children()) {
88 StorageLocation
*FieldLoc2
= Loc2
.getChild(*Field
);
90 assert(Field
->getType()->isReferenceType() ||
91 (FieldLoc1
!= nullptr && FieldLoc2
!= nullptr));
93 if (Field
->getType()->isRecordType()) {
94 if (!recordsEqual(cast
<RecordStorageLocation
>(*FieldLoc1
), Env1
,
95 cast
<RecordStorageLocation
>(*FieldLoc2
), Env2
))
97 } else if (Field
->getType()->isReferenceType()) {
98 if (FieldLoc1
!= FieldLoc2
)
100 } else if (Env1
.getValue(*FieldLoc1
) != Env2
.getValue(*FieldLoc2
)) {
105 for (const auto &[Name
, SynthFieldLoc1
] : Loc1
.synthetic_fields()) {
106 if (SynthFieldLoc1
->getType()->isRecordType()) {
108 *cast
<RecordStorageLocation
>(SynthFieldLoc1
), Env1
,
109 cast
<RecordStorageLocation
>(Loc2
.getSyntheticField(Name
)), Env2
))
111 } else if (Env1
.getValue(*SynthFieldLoc1
) !=
112 Env2
.getValue(Loc2
.getSyntheticField(Name
))) {