brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · 03d6ed8 Raw
180 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9//  Operations on records (structs, classes, and unions).10//11//===----------------------------------------------------------------------===//12 13#include "clang/Analysis/FlowSensitive/RecordOps.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/Type.h"17#include "clang/Analysis/FlowSensitive/ASTOps.h"18#include "clang/Basic/LLVM.h"19#include "llvm/ADT/StringMap.h"20 21#define DEBUG_TYPE "dataflow"22 23namespace clang::dataflow {24 25static void copyField(const ValueDecl &Field, StorageLocation *SrcFieldLoc,26                      StorageLocation *DstFieldLoc, RecordStorageLocation &Dst,27                      Environment &Env) {28  assert(Field.getType()->isReferenceType() ||29         (SrcFieldLoc != nullptr && DstFieldLoc != nullptr));30 31  if (Field.getType()->isRecordType()) {32    copyRecord(cast<RecordStorageLocation>(*SrcFieldLoc),33               cast<RecordStorageLocation>(*DstFieldLoc), Env);34  } else if (Field.getType()->isReferenceType()) {35    Dst.setChild(Field, SrcFieldLoc);36  } else {37    if (Value *Val = Env.getValue(*SrcFieldLoc))38      Env.setValue(*DstFieldLoc, *Val);39    else40      Env.clearValue(*DstFieldLoc);41  }42}43 44static void copySyntheticField(QualType FieldType, StorageLocation &SrcFieldLoc,45                               StorageLocation &DstFieldLoc, Environment &Env) {46  if (FieldType->isRecordType()) {47    copyRecord(cast<RecordStorageLocation>(SrcFieldLoc),48               cast<RecordStorageLocation>(DstFieldLoc), Env);49  } else {50    if (Value *Val = Env.getValue(SrcFieldLoc))51      Env.setValue(DstFieldLoc, *Val);52    else53      Env.clearValue(DstFieldLoc);54  }55}56 57void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,58                Environment &Env, const QualType TypeToCopy) {59  auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType();60  auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType();61 62  auto SrcDecl = SrcType->getAsCXXRecordDecl();63  auto DstDecl = DstType->getAsCXXRecordDecl();64 65  const CXXRecordDecl *DeclToCopy =66      TypeToCopy.isNull() ? nullptr : TypeToCopy->getAsCXXRecordDecl();67 68  [[maybe_unused]] bool CompatibleTypes =69      SrcType == DstType ||70      (SrcDecl != nullptr && DstDecl != nullptr &&71       (SrcDecl->isDerivedFrom(DstDecl) || DstDecl->isDerivedFrom(SrcDecl) ||72        (DeclToCopy != nullptr && SrcDecl->isDerivedFrom(DeclToCopy) &&73         DstDecl->isDerivedFrom(DeclToCopy))));74 75  LLVM_DEBUG({76    if (!CompatibleTypes) {77      llvm::dbgs() << "Source type " << Src.getType() << "\n";78      llvm::dbgs() << "Destination type " << Dst.getType() << "\n";79    }80  });81  assert(CompatibleTypes);82 83  if (SrcType == DstType || (SrcDecl != nullptr && DstDecl != nullptr &&84                             SrcDecl->isDerivedFrom(DstDecl))) {85    // Dst may have children modeled from other derived types than SrcType, e.g.86    // after casts of Dst to other types derived from DstType. Only copy the87    // children and synthetic fields present in both Dst and SrcType.88    const FieldSet FieldsInSrcType =89        Env.getDataflowAnalysisContext().getModeledFields(SrcType);90    for (auto [Field, DstFieldLoc] : Dst.children())91      if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field);92          FieldAsFieldDecl && FieldsInSrcType.contains(FieldAsFieldDecl))93        copyField(*Field, Src.getChild(*Field), DstFieldLoc, Dst, Env);94    const llvm::StringMap<QualType> SyntheticFieldsForSrcType =95        Env.getDataflowAnalysisContext().getSyntheticFields(SrcType);96    for (const auto &[Name, DstFieldLoc] : Dst.synthetic_fields())97      if (SyntheticFieldsForSrcType.contains(Name))98        copySyntheticField(DstFieldLoc->getType(), Src.getSyntheticField(Name),99                           *DstFieldLoc, Env);100  } else if (SrcDecl != nullptr && DstDecl != nullptr &&101             DstDecl->isDerivedFrom(SrcDecl)) {102    // Src may have children modeled from other derived types than DstType, e.g.103    // after other casts of Src to those types (likely in different branches,104    // but without flow-condition-dependent field modeling). Only copy the105    // children and synthetic fields of Src that are present in DstType.106    const FieldSet FieldsInDstType =107        Env.getDataflowAnalysisContext().getModeledFields(DstType);108    for (auto [Field, SrcFieldLoc] : Src.children()) {109      if (const auto *FieldAsFieldDecl = dyn_cast<FieldDecl>(Field);110          FieldAsFieldDecl && FieldsInDstType.contains(FieldAsFieldDecl))111        copyField(*Field, SrcFieldLoc, Dst.getChild(*Field), Dst, Env);112    }113    const llvm::StringMap<QualType> SyntheticFieldsForDstType =114        Env.getDataflowAnalysisContext().getSyntheticFields(DstType);115    for (const auto &[Name, SrcFieldLoc] : Src.synthetic_fields()) {116      if (SyntheticFieldsForDstType.contains(Name))117        copySyntheticField(SrcFieldLoc->getType(), *SrcFieldLoc,118                           Dst.getSyntheticField(Name), Env);119    }120  } else {121    for (const FieldDecl *Field :122         Env.getDataflowAnalysisContext().getModeledFields(TypeToCopy)) {123      copyField(*Field, Src.getChild(*Field), Dst.getChild(*Field), Dst, Env);124    }125    for (const auto &[SyntheticFieldName, SyntheticFieldType] :126         Env.getDataflowAnalysisContext().getSyntheticFields(TypeToCopy)) {127      copySyntheticField(SyntheticFieldType,128                         Src.getSyntheticField(SyntheticFieldName),129                         Dst.getSyntheticField(SyntheticFieldName), Env);130    }131  }132}133 134bool recordsEqual(const RecordStorageLocation &Loc1, const Environment &Env1,135                  const RecordStorageLocation &Loc2, const Environment &Env2) {136  LLVM_DEBUG({137    if (Loc2.getType().getCanonicalType().getUnqualifiedType() !=138        Loc1.getType().getCanonicalType().getUnqualifiedType()) {139      llvm::dbgs() << "Loc1 type " << Loc1.getType() << "\n";140      llvm::dbgs() << "Loc2 type " << Loc2.getType() << "\n";141    }142  });143  assert(Loc2.getType().getCanonicalType().getUnqualifiedType() ==144         Loc1.getType().getCanonicalType().getUnqualifiedType());145 146  for (auto [Field, FieldLoc1] : Loc1.children()) {147    StorageLocation *FieldLoc2 = Loc2.getChild(*Field);148 149    assert(Field->getType()->isReferenceType() ||150           (FieldLoc1 != nullptr && FieldLoc2 != nullptr));151 152    if (Field->getType()->isRecordType()) {153      if (!recordsEqual(cast<RecordStorageLocation>(*FieldLoc1), Env1,154                        cast<RecordStorageLocation>(*FieldLoc2), Env2))155        return false;156    } else if (Field->getType()->isReferenceType()) {157      if (FieldLoc1 != FieldLoc2)158        return false;159    } else if (Env1.getValue(*FieldLoc1) != Env2.getValue(*FieldLoc2)) {160      return false;161    }162  }163 164  for (const auto &[Name, SynthFieldLoc1] : Loc1.synthetic_fields()) {165    if (SynthFieldLoc1->getType()->isRecordType()) {166      if (!recordsEqual(167              *cast<RecordStorageLocation>(SynthFieldLoc1), Env1,168              cast<RecordStorageLocation>(Loc2.getSyntheticField(Name)), Env2))169        return false;170    } else if (Env1.getValue(*SynthFieldLoc1) !=171               Env2.getValue(Loc2.getSyntheticField(Name))) {172      return false;173    }174  }175 176  return true;177}178 179} // namespace clang::dataflow180