xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/RecordOps.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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(RecordStorageLocation &Src,
18                                  RecordStorageLocation &Dst, Environment &Env) {
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 *DstVal = &Env.create<RecordValue>(Dst);
70   Env.setValue(Dst, *DstVal);
71 }
72 
73 bool clang::dataflow::recordsEqual(const RecordStorageLocation &Loc1,
74                                    const Environment &Env1,
75                                    const RecordStorageLocation &Loc2,
76                                    const Environment &Env2) {
77   LLVM_DEBUG({
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";
82     }
83   });
84   assert(Loc2.getType().getCanonicalType().getUnqualifiedType() ==
85          Loc1.getType().getCanonicalType().getUnqualifiedType());
86 
87   for (auto [Field, FieldLoc1] : Loc1.children()) {
88     StorageLocation *FieldLoc2 = Loc2.getChild(*Field);
89 
90     assert(Field->getType()->isReferenceType() ||
91            (FieldLoc1 != nullptr && FieldLoc2 != nullptr));
92 
93     if (Field->getType()->isRecordType()) {
94       if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,
95                         cast<RecordStorageLocation>(*FieldLoc2), Env2))
96         return false;
97     } else if (Field->getType()->isReferenceType()) {
98       if (FieldLoc1 != FieldLoc2)
99         return false;
100     } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {
101       return false;
102     }
103   }
104 
105   for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {
106     if (SynthFieldLoc1->getType()->isRecordType()) {
107       if (!recordsEqual(
108               *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,
109               cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2))
110         return false;
111     } else if (Env1.getValue(*SynthFieldLoc1) !=
112                Env2.getValue(Loc2.getSyntheticField(Name))) {
113       return false;
114     }
115   }
116 
117   return true;
118 }
119