brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.3 KiB · 607be0b Raw
565 lines · cpp
1//===-- DiffEngine.cpp - Structural file comparison -----------------------===//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// This file defines the implementation of the llvm-tapi difference10// engine, which structurally compares two tbd files.11//12//===----------------------------------------------------------------------===/13#include "DiffEngine.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/Support/Casting.h"16#include "llvm/Support/raw_ostream.h"17#include "llvm/TextAPI/InterfaceFile.h"18#include "llvm/TextAPI/Symbol.h"19#include "llvm/TextAPI/Target.h"20#include <iterator>21 22using namespace llvm;23using namespace MachO;24using namespace object;25 26StringRef setOrderIndicator(InterfaceInputOrder Order) {27  return ((Order == lhs) ? "< " : "> ");28}29 30// The following template specialization implementations31// need to be explicitly placed into the llvm namespace32// to work around a GCC 4.8 bug.33namespace llvm {34 35template <typename T, DiffAttrKind U>36inline void DiffScalarVal<T, U>::print(raw_ostream &OS, std::string Indent) {37  OS << Indent << "\t" << setOrderIndicator(Order) << Val << "\n";38}39 40template <>41inline void42DiffScalarVal<StringRef, AD_Diff_Scalar_Str>::print(raw_ostream &OS,43                                                    std::string Indent) {44  OS << Indent << "\t\t" << setOrderIndicator(Order) << Val << "\n";45}46 47template <>48inline void49DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>::print(raw_ostream &OS,50                                                       std::string Indent) {51  OS << Indent << "\t" << setOrderIndicator(Order) << std::to_string(Val)52     << "\n";53}54 55template <>56inline void57DiffScalarVal<bool, AD_Diff_Scalar_Bool>::print(raw_ostream &OS,58                                                std::string Indent) {59  OS << Indent << "\t" << setOrderIndicator(Order)60     << ((Val == true) ? "true" : "false") << "\n";61}62 63} // end namespace llvm64 65StringLiteral SymScalar::getSymbolNamePrefix(MachO::EncodeKind Kind) {66  switch (Kind) {67  case MachO::EncodeKind::GlobalSymbol:68    return StringLiteral("");69  case MachO::EncodeKind::ObjectiveCClass:70    return ObjC2MetaClassNamePrefix;71  case MachO::EncodeKind ::ObjectiveCClassEHType:72    return ObjC2EHTypePrefix;73  case MachO::EncodeKind ::ObjectiveCInstanceVariable:74    return ObjC2IVarPrefix;75  }76  llvm_unreachable("Unknown llvm::MachO::EncodeKind enum");77}78 79std::string SymScalar::getFlagString(const MachO::Symbol *Sym) {80  if (Sym->getFlags() == SymbolFlags::None)81    return {};82  SmallString<64> Flags(" - ");83  if (Sym->isThreadLocalValue())84    Flags.append("Thread-Local ");85  if (Sym->isWeakDefined())86    Flags.append("Weak-Defined ");87  if (Sym->isWeakReferenced())88    Flags.append("Weak-Referenced ");89  if (Sym->isUndefined())90    Flags.append("Undefined ");91  if (Sym->isReexported())92    Flags.append("Reexported ");93  if (Sym->isData())94    Flags.append("Data ");95  if (Sym->isText())96    Flags.append("Text ");97 98  return std::string(Flags);99}100 101void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) {102  if (Val->getKind() == MachO::EncodeKind::ObjectiveCClass) {103    if (Targ.Arch == MachO::AK_i386 && Targ.Platform == MachO::PLATFORM_MACOS) {104      OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")105         << ObjC1ClassNamePrefix << Val->getName() << getFlagString(Val)106         << "\n";107      return;108    }109    OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")110       << ObjC2ClassNamePrefix << Val->getName() << getFlagString(Val) << "\n";111  }112  OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")113     << getSymbolNamePrefix(Val->getKind()) << Val->getName()114     << getFlagString(Val) << "\n";115}116 117bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,118                         llvm::MachO::InterfaceFile::const_symbol_range RHS) {119  if (std::distance(LHS.begin(), LHS.end()) !=120      std::distance(RHS.begin(), RHS.end()))121    return false;122  return std::equal(LHS.begin(), LHS.end(), RHS.begin(),123                    [&](auto LHS, auto RHS) { return *LHS == *RHS; });124}125 126template <typename TargetVecT, typename ValTypeT, typename V>127void addDiffForTargSlice(V Val, Target Targ, DiffOutput &Diff,128                         InterfaceInputOrder Order) {129  auto TargetVector = llvm::find_if(130      Diff.Values, [&](const std::unique_ptr<AttributeDiff> &RawTVec) {131        if (TargetVecT *TVec = dyn_cast<TargetVecT>(RawTVec.get()))132          return TVec->Targ == Targ;133        return false;134      });135  if (TargetVector != Diff.Values.end()) {136    ValTypeT NewVal(Order, Val);137    cast<TargetVecT>(TargetVector->get())->TargValues.push_back(NewVal);138  } else {139    auto NewTargetVec = std::make_unique<TargetVecT>(Targ);140    ValTypeT NewVal(Order, Val);141    NewTargetVec->TargValues.push_back(NewVal);142    Diff.Values.push_back(std::move(NewTargetVec));143  }144}145 146DiffOutput getSingleAttrDiff(const std::vector<InterfaceFileRef> &IRefVec,147                             std::string Name, InterfaceInputOrder Order) {148  DiffOutput Diff(Name);149  Diff.Kind = AD_Str_Vec;150  for (const auto &IRef : IRefVec)151    for (auto Targ : IRef.targets())152      addDiffForTargSlice<DiffStrVec,153                          DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(154          IRef.getInstallName(), Targ, Diff, Order);155  return Diff;156}157 158DiffOutput159getSingleAttrDiff(const std::vector<std::pair<Target, std::string>> &PairVec,160                  std::string Name, InterfaceInputOrder Order) {161  DiffOutput Diff(Name);162  Diff.Kind = AD_Str_Vec;163  for (const auto &Pair : PairVec)164    addDiffForTargSlice<DiffStrVec,165                        DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(166        StringRef(Pair.second), Pair.first, Diff, Order);167  return Diff;168}169 170DiffOutput getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,171                             std::string Name, InterfaceInputOrder Order) {172  DiffOutput Diff(Name);173  Diff.Kind = AD_Sym_Vec;174  for (const auto *Sym : SymRange)175    for (auto Targ : Sym->targets())176      addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Diff, Order);177  return Diff;178}179 180template <typename T>181DiffOutput getSingleAttrDiff(T SingleAttr, std::string Attribute) {182  DiffOutput Diff(Attribute);183  Diff.Kind = SingleAttr.getKind();184  Diff.Values.push_back(std::make_unique<T>(SingleAttr));185  return Diff;186}187 188template <typename T, DiffAttrKind U>189void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,190                   DiffScalarVal<T, U> Attr) {191  Output.push_back(getSingleAttrDiff(Attr, Name));192}193 194template <typename T>195void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,196                   const T &Val, InterfaceInputOrder Order) {197  Output.push_back(getSingleAttrDiff(Val, Name, Order));198}199 200std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface,201                                    InterfaceInputOrder Order) {202  std::vector<DiffOutput> Output;203  diffAttribute("Install Name", Output,204                DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(205                    Order, Interface->getInstallName()));206  for (const auto &Doc : Interface->documents()) {207    DiffOutput Documents("Inlined Reexported Frameworks/Libraries");208    Documents.Kind = AD_Inline_Doc;209    Documents.Values.push_back(std::make_unique<InlineDoc>(210        InlineDoc(Doc->getInstallName(), getSingleIF(Doc.get(), Order))));211    Output.push_back(std::move(Documents));212  }213  return Output;214}215 216void findAndAddDiff(const std::vector<InterfaceFileRef> &CollectedIRefVec,217                    const std::vector<InterfaceFileRef> &LookupIRefVec,218                    DiffOutput &Result, InterfaceInputOrder Order) {219  Result.Kind = AD_Str_Vec;220  for (const auto &IRef : CollectedIRefVec)221    for (auto Targ : IRef.targets()) {222      auto FoundIRef = llvm::any_of(LookupIRefVec, [&](const auto LIRef) {223        return llvm::is_contained(LIRef.targets(), Targ) &&224               IRef.getInstallName() == LIRef.getInstallName();225      });226      if (!FoundIRef)227        addDiffForTargSlice<DiffStrVec,228                            DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(229            IRef.getInstallName(), Targ, Result, Order);230    }231}232 233void findAndAddDiff(234    const std::vector<std::pair<Target, std::string>> &CollectedPairs,235    const std::vector<std::pair<Target, std::string>> &LookupPairs,236    DiffOutput &Result, InterfaceInputOrder Order) {237  Result.Kind = AD_Str_Vec;238  for (const auto &Pair : CollectedPairs) {239    auto FoundPair = llvm::find(LookupPairs, Pair);240    if (FoundPair == LookupPairs.end())241      addDiffForTargSlice<DiffStrVec,242                          DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(243          StringRef(Pair.second), Pair.first, Result, Order);244  }245}246 247void findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,248                    InterfaceFile::const_symbol_range LookupSyms,249                    DiffOutput &Result, InterfaceInputOrder Order) {250  Result.Kind = AD_Sym_Vec;251  for (const auto *Sym : CollectedSyms)252    for (const auto Targ : Sym->targets()) {253      auto FoundSym = llvm::any_of(LookupSyms, [&](const auto LSym) {254        return (Sym->getName() == LSym->getName() &&255                Sym->getKind() == LSym->getKind() &&256                Sym->getFlags() == LSym->getFlags() &&257                llvm::is_contained(LSym->targets(), Targ));258      });259      if (!FoundSym)260        addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order);261    }262}263 264template <typename T>265DiffOutput recordDifferences(T LHS, T RHS, std::string Attr) {266  DiffOutput Diff(Attr);267  if (LHS.getKind() == RHS.getKind()) {268    Diff.Kind = LHS.getKind();269    Diff.Values.push_back(std::make_unique<T>(LHS));270    Diff.Values.push_back(std::make_unique<T>(RHS));271  }272  return Diff;273}274 275template <typename T>276DiffOutput recordDifferences(const std::vector<T> &LHS,277                             const std::vector<T> &RHS, std::string Attr) {278  DiffOutput Diff(Attr);279  Diff.Kind = AD_Str_Vec;280  findAndAddDiff(LHS, RHS, Diff, lhs);281  findAndAddDiff(RHS, LHS, Diff, rhs);282  return Diff;283}284 285DiffOutput recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,286                             llvm::MachO::InterfaceFile::const_symbol_range RHS,287                             std::string Attr) {288  DiffOutput Diff(Attr);289  Diff.Kind = AD_Sym_Vec;290  findAndAddDiff(LHS, RHS, Diff, lhs);291  findAndAddDiff(RHS, LHS, Diff, rhs);292  return Diff;293}294 295std::vector<DiffOutput>296DiffEngine::findDifferences(const InterfaceFile *IFLHS,297                            const InterfaceFile *IFRHS) {298  std::vector<DiffOutput> Output;299  if (IFLHS->getInstallName() != IFRHS->getInstallName())300    Output.push_back(recordDifferences(301        DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(lhs,302                                                     IFLHS->getInstallName()),303        DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(rhs,304                                                     IFRHS->getInstallName()),305        "Install Name"));306 307  if (IFLHS->getCurrentVersion() != IFRHS->getCurrentVersion())308    Output.push_back(recordDifferences(309        DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(310            lhs, IFLHS->getCurrentVersion()),311        DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(312            rhs, IFRHS->getCurrentVersion()),313        "Current Version"));314  if (IFLHS->getCompatibilityVersion() != IFRHS->getCompatibilityVersion())315    Output.push_back(recordDifferences(316        DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(317            lhs, IFLHS->getCompatibilityVersion()),318        DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(319            rhs, IFRHS->getCompatibilityVersion()),320        "Compatibility Version"));321  if (IFLHS->getSwiftABIVersion() != IFRHS->getSwiftABIVersion())322    Output.push_back(323        recordDifferences(DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(324                              lhs, IFLHS->getSwiftABIVersion()),325                          DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(326                              rhs, IFRHS->getSwiftABIVersion()),327                          "Swift ABI Version"));328 329  if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace())330    Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(331                                           lhs, IFLHS->isTwoLevelNamespace()),332                                       DiffScalarVal<bool, AD_Diff_Scalar_Bool>(333                                           rhs, IFRHS->isTwoLevelNamespace()),334                                       "Two Level Namespace"));335 336  if (IFLHS->isApplicationExtensionSafe() !=337      IFRHS->isApplicationExtensionSafe())338    Output.push_back(339        recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(340                              lhs, IFLHS->isApplicationExtensionSafe()),341                          DiffScalarVal<bool, AD_Diff_Scalar_Bool>(342                              rhs, IFRHS->isApplicationExtensionSafe()),343                          "Application Extension Safe"));344 345  if (IFLHS->hasSimulatorSupport() != IFRHS->hasSimulatorSupport())346    Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(347                                           lhs, IFLHS->hasSimulatorSupport()),348                                       DiffScalarVal<bool, AD_Diff_Scalar_Bool>(349                                           rhs, IFRHS->hasSimulatorSupport()),350                                       "Simulator Support"));351 352  if (IFLHS->isOSLibNotForSharedCache() != IFRHS->isOSLibNotForSharedCache())353    Output.push_back(354        recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(355                              lhs, IFLHS->isOSLibNotForSharedCache()),356                          DiffScalarVal<bool, AD_Diff_Scalar_Bool>(357                              rhs, IFRHS->isOSLibNotForSharedCache()),358                          "Shared Cache Ineligible"));359 360  if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries())361    Output.push_back(recordDifferences(IFLHS->reexportedLibraries(),362                                       IFRHS->reexportedLibraries(),363                                       "Reexported Libraries"));364 365  if (IFLHS->rpaths() != IFRHS->rpaths())366    Output.push_back(recordDifferences(IFLHS->rpaths(), IFRHS->rpaths(),367                                       "Run Path Search Paths"));368 369  if (IFLHS->allowableClients() != IFRHS->allowableClients())370    Output.push_back(recordDifferences(IFLHS->allowableClients(),371                                       IFRHS->allowableClients(),372                                       "Allowable Clients"));373 374  if (IFLHS->umbrellas() != IFRHS->umbrellas())375    Output.push_back(recordDifferences(IFLHS->umbrellas(), IFRHS->umbrellas(),376                                       "Parent Umbrellas"));377 378  if (!checkSymbolEquality(IFLHS->symbols(), IFRHS->symbols()))379    Output.push_back(380        recordDifferences(IFLHS->symbols(), IFRHS->symbols(), "Symbols"));381 382  if (IFLHS->documents() != IFRHS->documents()) {383    DiffOutput Docs("Inlined Reexported Frameworks/Libraries");384    Docs.Kind = AD_Inline_Doc;385    std::vector<StringRef> DocsInserted;386    // Iterate through inline frameworks/libraries from interface file and find387    // match based on install name.388    for (auto DocLHS : IFLHS->documents()) {389      auto Pair = llvm::find_if(IFRHS->documents(), [&](const auto &DocRHS) {390        return (DocLHS->getInstallName() == DocRHS->getInstallName());391      });392      // If a match found, recursively get differences between the pair.393      if (Pair != IFRHS->documents().end()) {394        InlineDoc PairDiff =395            InlineDoc(DocLHS->getInstallName(),396                      findDifferences(DocLHS.get(), Pair->get()));397        if (!PairDiff.DocValues.empty())398          Docs.Values.push_back(399              std::make_unique<InlineDoc>(std::move(PairDiff)));400      }401      // No matching inlined library was found.402      else403        Docs.Values.push_back(std::make_unique<InlineDoc>(404            InlineDoc(DocLHS->getInstallName(), getSingleIF(DocLHS.get(), lhs),405                      /*IsMissingDoc=*/true)));406      DocsInserted.push_back(DocLHS->getInstallName());407    }408    for (auto DocRHS : IFRHS->documents()) {409      auto WasGathered =410          llvm::any_of(DocsInserted, [&](const auto &GatheredDoc) {411            return (GatheredDoc == DocRHS->getInstallName());412          });413      if (!WasGathered)414        Docs.Values.push_back(std::make_unique<InlineDoc>(415            InlineDoc(DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs),416                      /*IsMissingDoc=*/true)));417    }418    if (!Docs.Values.empty())419      Output.push_back(std::move(Docs));420  }421  return Output;422}423 424template <typename T>425void printSingleVal(std::string Indent, const DiffOutput &Attr,426                    raw_ostream &OS) {427  if (Attr.Values.empty())428    return;429  OS << Indent << Attr.Name << "\n";430  for (auto &RawItem : Attr.Values)431    if (T *Item = dyn_cast<T>(RawItem.get()))432      Item->print(OS, Indent);433}434 435template <typename T>436T *castValues(const std::unique_ptr<AttributeDiff> &RawAttr) {437  T *CastAttr = cast<T>(RawAttr.get());438  return CastAttr;439}440 441template <typename T> void sortTargetValues(std::vector<T> &TargValues) {442  llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {443    if (ValA.getOrder() == ValB.getOrder()) {444      return ValA.getVal() < ValB.getVal();445    }446    return ValA.getOrder() < ValB.getOrder();447  });448}449 450template <typename T>451void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) {452  if (Attr.Values.empty()) {453    OS << Indent << "'" << Attr.Name << "' differ by order\n";454    return;455  }456 457  OS << Indent << Attr.Name << "\n";458 459  std::vector<T *> SortedAttrs;460 461  llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), castValues<T>);462 463  llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {464    return ValA->Targ < ValB->Targ;465  });466 467  for (auto *Vec : SortedAttrs) {468    sortTargetValues<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(469        Vec->TargValues);470    OS << Indent << "\t" << getTargetTripleName(Vec->Targ) << "\n";471    for (auto &Item : Vec->TargValues)472      Item.print(OS, Indent);473  }474}475 476template <>477void printVecVal<DiffSymVec>(std::string Indent, const DiffOutput &Attr,478                             raw_ostream &OS) {479  if (Attr.Values.empty())480    return;481 482  OS << Indent << Attr.Name << "\n";483 484  std::vector<DiffSymVec *> SortedAttrs;485 486  llvm::transform(Attr.Values, std::back_inserter(SortedAttrs),487                  castValues<DiffSymVec>);488 489  llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {490    return ValA->Targ < ValB->Targ;491  });492  for (auto *SymVec : SortedAttrs) {493    sortTargetValues<SymScalar>(SymVec->TargValues);494    OS << Indent << "\t" << getTargetTripleName(SymVec->Targ) << "\n";495    for (auto &Item : SymVec->TargValues)496      Item.print(OS, Indent, SymVec->Targ);497  }498}499 500void DiffEngine::printDifferences(raw_ostream &OS,501                                  const std::vector<DiffOutput> &Diffs,502                                  int IndentCounter) {503  std::string Indent = std::string(IndentCounter, '\t');504  for (auto &Attr : Diffs) {505    switch (Attr.Kind) {506    case AD_Diff_Scalar_Str:507      if (IndentCounter == 0)508        printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(Indent,509                                                                     Attr, OS);510      break;511    case AD_Diff_Scalar_PackedVersion:512      printSingleVal<513          DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>>(Indent,514                                                                      Attr, OS);515      break;516    case AD_Diff_Scalar_Unsigned:517      printSingleVal<DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>>(Indent,518                                                                      Attr, OS);519      break;520    case AD_Diff_Scalar_Bool:521      printSingleVal<DiffScalarVal<bool, AD_Diff_Scalar_Bool>>(Indent, Attr,522                                                               OS);523      break;524    case AD_Str_Vec:525      printVecVal<DiffStrVec>(Indent, Attr, OS);526      break;527    case AD_Sym_Vec:528      printVecVal<DiffSymVec>(Indent, Attr, OS);529      break;530    case AD_Inline_Doc:531      if (!Attr.Values.empty()) {532        OS << Indent << Attr.Name << "\n";533        for (auto &Item : Attr.Values) {534          if (InlineDoc *Doc = dyn_cast<InlineDoc>(Item.get())) {535            if (Doc->DocValues.empty())536              continue;537            IndentCounter = 2;538            // When only one input file contains an inlined library, print out539            // the install name for it. Otherwise print out the different values540            // by the install name.541            if (Doc->IsMissingDoc) {542              printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(543                  std::string(IndentCounter, '\t'), Doc->DocValues.front(), OS);544            } else {545              OS << Indent << "\t" << Doc->InstallName << "\n";546              printDifferences(OS, std::move(Doc->DocValues), IndentCounter);547            }548          }549        }550      }551      break;552    }553  }554}555 556bool DiffEngine::compareFiles(raw_ostream &OS) {557  if (*FileLHS == *FileRHS)558    return false;559  OS << "< " << std::string(FileLHS->getPath().data()) << "\n> "560     << std::string(FileRHS->getPath().data()) << "\n\n";561  std::vector<DiffOutput> Diffs = findDifferences(FileLHS, FileRHS);562  printDifferences(OS, Diffs, 0);563  return true;564}565