xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/RecordOps.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- RecordOps.cpp -------------------------------------------*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric //  Operations on records (structs, classes, and unions).
1006c3fb27SDimitry Andric //
1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/RecordOps.h"
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric #define DEBUG_TYPE "dataflow"
1606c3fb27SDimitry Andric 
17*0fca6ea1SDimitry Andric namespace clang::dataflow {
18*0fca6ea1SDimitry Andric 
19*0fca6ea1SDimitry Andric static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc,
20*0fca6ea1SDimitry Andric                       StorageLocation *DstFieldLoc, RecordStorageLocation &Dst,
21*0fca6ea1SDimitry Andric                       Environment &Env) {
22*0fca6ea1SDimitry Andric   assert(Field.getType()->isReferenceType() ||
23*0fca6ea1SDimitry Andric          (SrcFieldLoc != nullptr && DstFieldLoc != nullptr));
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric   if (Field.getType()->isRecordType()) {
26*0fca6ea1SDimitry Andric     copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc),
27*0fca6ea1SDimitry Andric                cast<RecordStorageLocation>(*DstFieldLoc), Env);
28*0fca6ea1SDimitry Andric   } else if (Field.getType()->isReferenceType()) {
29*0fca6ea1SDimitry Andric     Dst.setChild(Field, SrcFieldLoc);
30*0fca6ea1SDimitry Andric   } else {
31*0fca6ea1SDimitry Andric     if (Value *Val = Env.getValue(*SrcFieldLoc))
32*0fca6ea1SDimitry Andric       Env.setValue(*DstFieldLoc, *Val);
33*0fca6ea1SDimitry Andric     else
34*0fca6ea1SDimitry Andric       Env.clearValue(*DstFieldLoc);
35*0fca6ea1SDimitry Andric   }
36*0fca6ea1SDimitry Andric }
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc,
39*0fca6ea1SDimitry Andric                                StorageLocation &DstFieldLoc, Environment &Env) {
40*0fca6ea1SDimitry Andric   if (FieldType->isRecordType()) {
41*0fca6ea1SDimitry Andric     copyRecord(cast<RecordStorageLocation>(SrcFieldLoc),
42*0fca6ea1SDimitry Andric                cast<RecordStorageLocation>(DstFieldLoc), Env);
43*0fca6ea1SDimitry Andric   } else {
44*0fca6ea1SDimitry Andric     if (Value *Val = Env.getValue(SrcFieldLoc))
45*0fca6ea1SDimitry Andric       Env.setValue(DstFieldLoc, *Val);
46*0fca6ea1SDimitry Andric     else
47*0fca6ea1SDimitry Andric       Env.clearValue(DstFieldLoc);
48*0fca6ea1SDimitry Andric   }
49*0fca6ea1SDimitry Andric }
50*0fca6ea1SDimitry Andric 
51*0fca6ea1SDimitry Andric void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,
52*0fca6ea1SDimitry Andric                 Environment &Env) {
535f757f3fSDimitry Andric   auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType();
545f757f3fSDimitry Andric   auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType();
555f757f3fSDimitry Andric 
565f757f3fSDimitry Andric   auto SrcDecl = SrcType->getAsCXXRecordDecl();
575f757f3fSDimitry Andric   auto DstDecl = DstType->getAsCXXRecordDecl();
585f757f3fSDimitry Andric 
59*0fca6ea1SDimitry Andric   [[maybe_unused]] bool compatibleTypes =
605f757f3fSDimitry Andric       SrcType == DstType ||
61*0fca6ea1SDimitry Andric       (SrcDecl != nullptr && DstDecl != nullptr &&
62*0fca6ea1SDimitry Andric        (SrcDecl->isDerivedFrom(DstDecl) || DstDecl->isDerivedFrom(SrcDecl)));
635f757f3fSDimitry Andric 
6406c3fb27SDimitry Andric   LLVM_DEBUG({
655f757f3fSDimitry Andric     if (!compatibleTypes) {
6606c3fb27SDimitry Andric       llvm::dbgs() << "Source type " << Src.getType() << "\n";
6706c3fb27SDimitry Andric       llvm::dbgs() << "Destination type " << Dst.getType() << "\n";
6806c3fb27SDimitry Andric     }
6906c3fb27SDimitry Andric   });
705f757f3fSDimitry Andric   assert(compatibleTypes);
7106c3fb27SDimitry Andric 
72*0fca6ea1SDimitry Andric   if (SrcType == DstType || (SrcDecl != nullptr && DstDecl != nullptr &&
73*0fca6ea1SDimitry Andric                              SrcDecl->isDerivedFrom(DstDecl))) {
74*0fca6ea1SDimitry Andric     for (auto [Field, DstFieldLoc] : Dst.children())
75*0fca6ea1SDimitry Andric       copyField(*Field, Src.getChild(*Field), DstFieldLoc, Dst, Env);
76*0fca6ea1SDimitry Andric     for (const auto &[Name, DstFieldLoc] : Dst.synthetic_fields())
77*0fca6ea1SDimitry Andric       copySyntheticField(DstFieldLoc->getType(), Src.getSyntheticField(Name),
78*0fca6ea1SDimitry Andric                          *DstFieldLoc, Env);
7906c3fb27SDimitry Andric   } else {
80*0fca6ea1SDimitry Andric     for (auto [Field, SrcFieldLoc] : Src.children())
81*0fca6ea1SDimitry Andric       copyField(*Field, SrcFieldLoc, Dst.getChild(*Field), Dst, Env);
82*0fca6ea1SDimitry Andric     for (const auto &[Name, SrcFieldLoc] : Src.synthetic_fields())
83*0fca6ea1SDimitry Andric       copySyntheticField(SrcFieldLoc->getType(), *SrcFieldLoc,
84*0fca6ea1SDimitry Andric                          Dst.getSyntheticField(Name), Env);
8506c3fb27SDimitry Andric   }
8606c3fb27SDimitry Andric }
8706c3fb27SDimitry Andric 
88*0fca6ea1SDimitry Andric bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1,
89*0fca6ea1SDimitry Andric                   const RecordStorageLocation &Loc2, const Environment &Env2) {
9006c3fb27SDimitry Andric   LLVM_DEBUG({
9106c3fb27SDimitry Andric     if (Loc2.getType().getCanonicalType().getUnqualifiedType() !=
9206c3fb27SDimitry Andric         Loc1.getType().getCanonicalType().getUnqualifiedType()) {
9306c3fb27SDimitry Andric       llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n";
9406c3fb27SDimitry Andric       llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n";
9506c3fb27SDimitry Andric     }
9606c3fb27SDimitry Andric   });
9706c3fb27SDimitry Andric   assert(Loc2.getType().getCanonicalType().getUnqualifiedType() ==
9806c3fb27SDimitry Andric          Loc1.getType().getCanonicalType().getUnqualifiedType());
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric   for (auto [Field, FieldLoc1] : Loc1.children()) {
10106c3fb27SDimitry Andric     StorageLocation *FieldLoc2 = Loc2.getChild(*Field);
10206c3fb27SDimitry Andric 
10306c3fb27SDimitry Andric     assert(Field->getType()->isReferenceType() ||
10406c3fb27SDimitry Andric            (FieldLoc1 != nullptr && FieldLoc2 != nullptr));
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric     if (Field->getType()->isRecordType()) {
1075f757f3fSDimitry Andric       if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,
1085f757f3fSDimitry Andric                         cast<RecordStorageLocation>(*FieldLoc2), Env2))
10906c3fb27SDimitry Andric         return false;
11006c3fb27SDimitry Andric     } else if (Field->getType()->isReferenceType()) {
11106c3fb27SDimitry Andric       if (FieldLoc1 != FieldLoc2)
11206c3fb27SDimitry Andric         return false;
11306c3fb27SDimitry Andric     } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {
11406c3fb27SDimitry Andric       return false;
11506c3fb27SDimitry Andric     }
11606c3fb27SDimitry Andric   }
11706c3fb27SDimitry Andric 
1185f757f3fSDimitry Andric   for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {
1195f757f3fSDimitry Andric     if (SynthFieldLoc1->getType()->isRecordType()) {
1205f757f3fSDimitry Andric       if (!recordsEqual(
1215f757f3fSDimitry Andric               *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,
1225f757f3fSDimitry Andric               cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2))
1235f757f3fSDimitry Andric         return false;
1245f757f3fSDimitry Andric     } else if (Env1.getValue(*SynthFieldLoc1) !=
1255f757f3fSDimitry Andric                Env2.getValue(Loc2.getSyntheticField(Name))) {
1265f757f3fSDimitry Andric       return false;
1275f757f3fSDimitry Andric     }
1285f757f3fSDimitry Andric   }
1295f757f3fSDimitry Andric 
13006c3fb27SDimitry Andric   return true;
13106c3fb27SDimitry Andric }
132*0fca6ea1SDimitry Andric 
133*0fca6ea1SDimitry Andric } // namespace clang::dataflow
134