xref: /llvm-project/llvm/tools/llvm-readtapi/DiffEngine.cpp (revision d9a9872ec4760762fdc467ef283cea302a3742e5)
15656d797SCyndy Ishida //===-- DiffEngine.cpp - Structural file comparison -----------------------===//
25656d797SCyndy Ishida //
35656d797SCyndy Ishida // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45656d797SCyndy Ishida // See https://llvm.org/LICENSE.txt for license information.
55656d797SCyndy Ishida // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65656d797SCyndy Ishida //
75656d797SCyndy Ishida //===----------------------------------------------------------------------===//
85656d797SCyndy Ishida //
95656d797SCyndy Ishida // This file defines the implementation of the llvm-tapi difference
105656d797SCyndy Ishida // engine, which structurally compares two tbd files.
115656d797SCyndy Ishida //
125656d797SCyndy Ishida //===----------------------------------------------------------------------===/
135656d797SCyndy Ishida #include "DiffEngine.h"
145656d797SCyndy Ishida #include "llvm/ADT/SmallString.h"
155656d797SCyndy Ishida #include "llvm/Support/Casting.h"
165656d797SCyndy Ishida #include "llvm/Support/raw_ostream.h"
175656d797SCyndy Ishida #include "llvm/TextAPI/InterfaceFile.h"
185656d797SCyndy Ishida #include "llvm/TextAPI/Symbol.h"
195656d797SCyndy Ishida #include "llvm/TextAPI/Target.h"
205656d797SCyndy Ishida #include <iterator>
215656d797SCyndy Ishida 
225656d797SCyndy Ishida using namespace llvm;
235656d797SCyndy Ishida using namespace MachO;
245656d797SCyndy Ishida using namespace object;
255656d797SCyndy Ishida 
setOrderIndicator(InterfaceInputOrder Order)265656d797SCyndy Ishida StringRef setOrderIndicator(InterfaceInputOrder Order) {
275656d797SCyndy Ishida   return ((Order == lhs) ? "< " : "> ");
285656d797SCyndy Ishida }
295656d797SCyndy Ishida 
305656d797SCyndy Ishida // The following template specialization implementations
315656d797SCyndy Ishida // need to be explicitly placed into the llvm namespace
325656d797SCyndy Ishida // to work around a GCC 4.8 bug.
335656d797SCyndy Ishida namespace llvm {
345656d797SCyndy Ishida 
355656d797SCyndy Ishida template <typename T, DiffAttrKind U>
print(raw_ostream & OS,std::string Indent)365656d797SCyndy Ishida inline void DiffScalarVal<T, U>::print(raw_ostream &OS, std::string Indent) {
375656d797SCyndy Ishida   OS << Indent << "\t" << setOrderIndicator(Order) << Val << "\n";
385656d797SCyndy Ishida }
395656d797SCyndy Ishida 
405656d797SCyndy Ishida template <>
415656d797SCyndy Ishida inline void
print(raw_ostream & OS,std::string Indent)425656d797SCyndy Ishida DiffScalarVal<StringRef, AD_Diff_Scalar_Str>::print(raw_ostream &OS,
435656d797SCyndy Ishida                                                     std::string Indent) {
445656d797SCyndy Ishida   OS << Indent << "\t\t" << setOrderIndicator(Order) << Val << "\n";
455656d797SCyndy Ishida }
465656d797SCyndy Ishida 
475656d797SCyndy Ishida template <>
485656d797SCyndy Ishida inline void
print(raw_ostream & OS,std::string Indent)495656d797SCyndy Ishida DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>::print(raw_ostream &OS,
505656d797SCyndy Ishida                                                        std::string Indent) {
515656d797SCyndy Ishida   OS << Indent << "\t" << setOrderIndicator(Order) << std::to_string(Val)
525656d797SCyndy Ishida      << "\n";
535656d797SCyndy Ishida }
545656d797SCyndy Ishida 
555656d797SCyndy Ishida template <>
565656d797SCyndy Ishida inline void
print(raw_ostream & OS,std::string Indent)575656d797SCyndy Ishida DiffScalarVal<bool, AD_Diff_Scalar_Bool>::print(raw_ostream &OS,
585656d797SCyndy Ishida                                                 std::string Indent) {
595656d797SCyndy Ishida   OS << Indent << "\t" << setOrderIndicator(Order)
605656d797SCyndy Ishida      << ((Val == true) ? "true" : "false") << "\n";
615656d797SCyndy Ishida }
625656d797SCyndy Ishida 
635656d797SCyndy Ishida } // end namespace llvm
645656d797SCyndy Ishida 
getSymbolNamePrefix(MachO::EncodeKind Kind)65*d9a9872eSCyndy Ishida StringLiteral SymScalar::getSymbolNamePrefix(MachO::EncodeKind Kind) {
665656d797SCyndy Ishida   switch (Kind) {
67*d9a9872eSCyndy Ishida   case MachO::EncodeKind::GlobalSymbol:
685656d797SCyndy Ishida     return StringLiteral("");
69*d9a9872eSCyndy Ishida   case MachO::EncodeKind::ObjectiveCClass:
705656d797SCyndy Ishida     return ObjC2MetaClassNamePrefix;
71*d9a9872eSCyndy Ishida   case MachO::EncodeKind ::ObjectiveCClassEHType:
725656d797SCyndy Ishida     return ObjC2EHTypePrefix;
73*d9a9872eSCyndy Ishida   case MachO::EncodeKind ::ObjectiveCInstanceVariable:
745656d797SCyndy Ishida     return ObjC2IVarPrefix;
755656d797SCyndy Ishida   }
76*d9a9872eSCyndy Ishida   llvm_unreachable("Unknown llvm::MachO::EncodeKind enum");
775656d797SCyndy Ishida }
785656d797SCyndy Ishida 
getFlagString(const MachO::Symbol * Sym)795656d797SCyndy Ishida std::string SymScalar::getFlagString(const MachO::Symbol *Sym) {
805656d797SCyndy Ishida   if (Sym->getFlags() == SymbolFlags::None)
815656d797SCyndy Ishida     return {};
825656d797SCyndy Ishida   SmallString<64> Flags(" - ");
835656d797SCyndy Ishida   if (Sym->isThreadLocalValue())
845656d797SCyndy Ishida     Flags.append("Thread-Local ");
855656d797SCyndy Ishida   if (Sym->isWeakDefined())
865656d797SCyndy Ishida     Flags.append("Weak-Defined ");
875656d797SCyndy Ishida   if (Sym->isWeakReferenced())
885656d797SCyndy Ishida     Flags.append("Weak-Referenced ");
895656d797SCyndy Ishida   if (Sym->isUndefined())
905656d797SCyndy Ishida     Flags.append("Undefined ");
915656d797SCyndy Ishida   if (Sym->isReexported())
925656d797SCyndy Ishida     Flags.append("Reexported ");
935656d797SCyndy Ishida   if (Sym->isData())
945656d797SCyndy Ishida     Flags.append("Data ");
955656d797SCyndy Ishida   if (Sym->isText())
965656d797SCyndy Ishida     Flags.append("Text ");
975656d797SCyndy Ishida 
985656d797SCyndy Ishida   return std::string(Flags);
995656d797SCyndy Ishida }
1005656d797SCyndy Ishida 
print(raw_ostream & OS,std::string Indent,MachO::Target Targ)1015656d797SCyndy Ishida void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) {
102*d9a9872eSCyndy Ishida   if (Val->getKind() == MachO::EncodeKind::ObjectiveCClass) {
1035656d797SCyndy Ishida     if (Targ.Arch == MachO::AK_i386 && Targ.Platform == MachO::PLATFORM_MACOS) {
1045656d797SCyndy Ishida       OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
1055656d797SCyndy Ishida          << ObjC1ClassNamePrefix << Val->getName() << getFlagString(Val)
1065656d797SCyndy Ishida          << "\n";
1075656d797SCyndy Ishida       return;
1085656d797SCyndy Ishida     }
1095656d797SCyndy Ishida     OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
1105656d797SCyndy Ishida        << ObjC2ClassNamePrefix << Val->getName() << getFlagString(Val) << "\n";
1115656d797SCyndy Ishida   }
1125656d797SCyndy Ishida   OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
1135656d797SCyndy Ishida      << getSymbolNamePrefix(Val->getKind()) << Val->getName()
1145656d797SCyndy Ishida      << getFlagString(Val) << "\n";
1155656d797SCyndy Ishida }
1165656d797SCyndy Ishida 
checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,llvm::MachO::InterfaceFile::const_symbol_range RHS)1175656d797SCyndy Ishida bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,
1185656d797SCyndy Ishida                          llvm::MachO::InterfaceFile::const_symbol_range RHS) {
1195656d797SCyndy Ishida   if (std::distance(LHS.begin(), LHS.end()) !=
1205656d797SCyndy Ishida       std::distance(RHS.begin(), RHS.end()))
1215656d797SCyndy Ishida     return false;
1225656d797SCyndy Ishida   return std::equal(LHS.begin(), LHS.end(), RHS.begin(),
1235656d797SCyndy Ishida                     [&](auto LHS, auto RHS) { return *LHS == *RHS; });
1245656d797SCyndy Ishida }
1255656d797SCyndy Ishida 
1265656d797SCyndy Ishida template <typename TargetVecT, typename ValTypeT, typename V>
addDiffForTargSlice(V Val,Target Targ,DiffOutput & Diff,InterfaceInputOrder Order)1275656d797SCyndy Ishida void addDiffForTargSlice(V Val, Target Targ, DiffOutput &Diff,
1285656d797SCyndy Ishida                          InterfaceInputOrder Order) {
1295656d797SCyndy Ishida   auto TargetVector = llvm::find_if(
1305656d797SCyndy Ishida       Diff.Values, [&](const std::unique_ptr<AttributeDiff> &RawTVec) {
1315656d797SCyndy Ishida         if (TargetVecT *TVec = dyn_cast<TargetVecT>(RawTVec.get()))
1325656d797SCyndy Ishida           return TVec->Targ == Targ;
1335656d797SCyndy Ishida         return false;
1345656d797SCyndy Ishida       });
1355656d797SCyndy Ishida   if (TargetVector != Diff.Values.end()) {
1365656d797SCyndy Ishida     ValTypeT NewVal(Order, Val);
1375656d797SCyndy Ishida     cast<TargetVecT>(TargetVector->get())->TargValues.push_back(NewVal);
1385656d797SCyndy Ishida   } else {
1395656d797SCyndy Ishida     auto NewTargetVec = std::make_unique<TargetVecT>(Targ);
1405656d797SCyndy Ishida     ValTypeT NewVal(Order, Val);
1415656d797SCyndy Ishida     NewTargetVec->TargValues.push_back(NewVal);
1425656d797SCyndy Ishida     Diff.Values.push_back(std::move(NewTargetVec));
1435656d797SCyndy Ishida   }
1445656d797SCyndy Ishida }
1455656d797SCyndy Ishida 
getSingleAttrDiff(const std::vector<InterfaceFileRef> & IRefVec,std::string Name,InterfaceInputOrder Order)1465656d797SCyndy Ishida DiffOutput getSingleAttrDiff(const std::vector<InterfaceFileRef> &IRefVec,
1475656d797SCyndy Ishida                              std::string Name, InterfaceInputOrder Order) {
1485656d797SCyndy Ishida   DiffOutput Diff(Name);
1495656d797SCyndy Ishida   Diff.Kind = AD_Str_Vec;
1505656d797SCyndy Ishida   for (const auto &IRef : IRefVec)
1515656d797SCyndy Ishida     for (auto Targ : IRef.targets())
1525656d797SCyndy Ishida       addDiffForTargSlice<DiffStrVec,
1535656d797SCyndy Ishida                           DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
1545656d797SCyndy Ishida           IRef.getInstallName(), Targ, Diff, Order);
1555656d797SCyndy Ishida   return Diff;
1565656d797SCyndy Ishida }
1575656d797SCyndy Ishida 
1585656d797SCyndy Ishida DiffOutput
getSingleAttrDiff(const std::vector<std::pair<Target,std::string>> & PairVec,std::string Name,InterfaceInputOrder Order)1595656d797SCyndy Ishida getSingleAttrDiff(const std::vector<std::pair<Target, std::string>> &PairVec,
1605656d797SCyndy Ishida                   std::string Name, InterfaceInputOrder Order) {
1615656d797SCyndy Ishida   DiffOutput Diff(Name);
1625656d797SCyndy Ishida   Diff.Kind = AD_Str_Vec;
1635656d797SCyndy Ishida   for (const auto &Pair : PairVec)
1645656d797SCyndy Ishida     addDiffForTargSlice<DiffStrVec,
1655656d797SCyndy Ishida                         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
1665656d797SCyndy Ishida         StringRef(Pair.second), Pair.first, Diff, Order);
1675656d797SCyndy Ishida   return Diff;
1685656d797SCyndy Ishida }
1695656d797SCyndy Ishida 
getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,std::string Name,InterfaceInputOrder Order)1705656d797SCyndy Ishida DiffOutput getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,
1715656d797SCyndy Ishida                              std::string Name, InterfaceInputOrder Order) {
1725656d797SCyndy Ishida   DiffOutput Diff(Name);
1735656d797SCyndy Ishida   Diff.Kind = AD_Sym_Vec;
1745656d797SCyndy Ishida   for (const auto *Sym : SymRange)
1755656d797SCyndy Ishida     for (auto Targ : Sym->targets())
1765656d797SCyndy Ishida       addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Diff, Order);
1775656d797SCyndy Ishida   return Diff;
1785656d797SCyndy Ishida }
1795656d797SCyndy Ishida 
1805656d797SCyndy Ishida template <typename T>
getSingleAttrDiff(T SingleAttr,std::string Attribute)1815656d797SCyndy Ishida DiffOutput getSingleAttrDiff(T SingleAttr, std::string Attribute) {
1825656d797SCyndy Ishida   DiffOutput Diff(Attribute);
1835656d797SCyndy Ishida   Diff.Kind = SingleAttr.getKind();
1845656d797SCyndy Ishida   Diff.Values.push_back(std::make_unique<T>(SingleAttr));
1855656d797SCyndy Ishida   return Diff;
1865656d797SCyndy Ishida }
1875656d797SCyndy Ishida 
1885656d797SCyndy Ishida template <typename T, DiffAttrKind U>
diffAttribute(std::string Name,std::vector<DiffOutput> & Output,DiffScalarVal<T,U> Attr)1895656d797SCyndy Ishida void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
1905656d797SCyndy Ishida                    DiffScalarVal<T, U> Attr) {
1915656d797SCyndy Ishida   Output.push_back(getSingleAttrDiff(Attr, Name));
1925656d797SCyndy Ishida }
1935656d797SCyndy Ishida 
1945656d797SCyndy Ishida template <typename T>
diffAttribute(std::string Name,std::vector<DiffOutput> & Output,const T & Val,InterfaceInputOrder Order)1955656d797SCyndy Ishida void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
1965656d797SCyndy Ishida                    const T &Val, InterfaceInputOrder Order) {
1975656d797SCyndy Ishida   Output.push_back(getSingleAttrDiff(Val, Name, Order));
1985656d797SCyndy Ishida }
1995656d797SCyndy Ishida 
getSingleIF(InterfaceFile * Interface,InterfaceInputOrder Order)2005656d797SCyndy Ishida std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface,
2015656d797SCyndy Ishida                                     InterfaceInputOrder Order) {
2025656d797SCyndy Ishida   std::vector<DiffOutput> Output;
2035656d797SCyndy Ishida   diffAttribute("Install Name", Output,
2045656d797SCyndy Ishida                 DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(
2055656d797SCyndy Ishida                     Order, Interface->getInstallName()));
2065656d797SCyndy Ishida   diffAttribute("Current Version", Output,
2075656d797SCyndy Ishida                 DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
2085656d797SCyndy Ishida                     Order, Interface->getCurrentVersion()));
2095656d797SCyndy Ishida   diffAttribute("Compatibility Version", Output,
2105656d797SCyndy Ishida                 DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
2115656d797SCyndy Ishida                     Order, Interface->getCompatibilityVersion()));
2125656d797SCyndy Ishida   diffAttribute("Swift ABI Version", Output,
2135656d797SCyndy Ishida                 DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
2145656d797SCyndy Ishida                     Order, Interface->getSwiftABIVersion()));
2155656d797SCyndy Ishida   diffAttribute("Two Level Namespace", Output,
2165656d797SCyndy Ishida                 DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
2175656d797SCyndy Ishida                     Order, Interface->isTwoLevelNamespace()));
2185656d797SCyndy Ishida   diffAttribute("Application Extension Safe", Output,
2195656d797SCyndy Ishida                 DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
2205656d797SCyndy Ishida                     Order, Interface->isApplicationExtensionSafe()));
2215656d797SCyndy Ishida   diffAttribute("Reexported Libraries", Output,
2225656d797SCyndy Ishida                 Interface->reexportedLibraries(), Order);
2235656d797SCyndy Ishida   diffAttribute("Allowable Clients", Output, Interface->allowableClients(),
2245656d797SCyndy Ishida                 Order);
2255656d797SCyndy Ishida   diffAttribute("Parent Umbrellas", Output, Interface->umbrellas(), Order);
2265656d797SCyndy Ishida   diffAttribute("Symbols", Output, Interface->symbols(), Order);
22740dc8e68SGregory Alfonso   for (const auto &Doc : Interface->documents()) {
2285656d797SCyndy Ishida     DiffOutput Documents("Inlined Reexported Frameworks/Libraries");
2295656d797SCyndy Ishida     Documents.Kind = AD_Inline_Doc;
2305656d797SCyndy Ishida     Documents.Values.push_back(std::make_unique<InlineDoc>(
2315656d797SCyndy Ishida         InlineDoc(Doc->getInstallName(), getSingleIF(Doc.get(), Order))));
2325656d797SCyndy Ishida     Output.push_back(std::move(Documents));
2335656d797SCyndy Ishida   }
2345656d797SCyndy Ishida   return Output;
2355656d797SCyndy Ishida }
2365656d797SCyndy Ishida 
findAndAddDiff(const std::vector<InterfaceFileRef> & CollectedIRefVec,const std::vector<InterfaceFileRef> & LookupIRefVec,DiffOutput & Result,InterfaceInputOrder Order)2375656d797SCyndy Ishida void findAndAddDiff(const std::vector<InterfaceFileRef> &CollectedIRefVec,
2385656d797SCyndy Ishida                     const std::vector<InterfaceFileRef> &LookupIRefVec,
2395656d797SCyndy Ishida                     DiffOutput &Result, InterfaceInputOrder Order) {
2405656d797SCyndy Ishida   Result.Kind = AD_Str_Vec;
2415656d797SCyndy Ishida   for (const auto &IRef : CollectedIRefVec)
2425656d797SCyndy Ishida     for (auto Targ : IRef.targets()) {
2435656d797SCyndy Ishida       auto FoundIRef = llvm::any_of(LookupIRefVec, [&](const auto LIRef) {
2445656d797SCyndy Ishida         return llvm::is_contained(LIRef.targets(), Targ) &&
2455656d797SCyndy Ishida                IRef.getInstallName() == LIRef.getInstallName();
2465656d797SCyndy Ishida       });
2475656d797SCyndy Ishida       if (!FoundIRef)
2485656d797SCyndy Ishida         addDiffForTargSlice<DiffStrVec,
2495656d797SCyndy Ishida                             DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
2505656d797SCyndy Ishida             IRef.getInstallName(), Targ, Result, Order);
2515656d797SCyndy Ishida     }
2525656d797SCyndy Ishida }
2535656d797SCyndy Ishida 
findAndAddDiff(const std::vector<std::pair<Target,std::string>> & CollectedPairs,const std::vector<std::pair<Target,std::string>> & LookupPairs,DiffOutput & Result,InterfaceInputOrder Order)2545656d797SCyndy Ishida void findAndAddDiff(
2555656d797SCyndy Ishida     const std::vector<std::pair<Target, std::string>> &CollectedPairs,
2565656d797SCyndy Ishida     const std::vector<std::pair<Target, std::string>> &LookupPairs,
2575656d797SCyndy Ishida     DiffOutput &Result, InterfaceInputOrder Order) {
2585656d797SCyndy Ishida   Result.Kind = AD_Str_Vec;
2595656d797SCyndy Ishida   for (const auto &Pair : CollectedPairs) {
2605656d797SCyndy Ishida     auto FoundPair = llvm::find(LookupPairs, Pair);
2615656d797SCyndy Ishida     if (FoundPair == LookupPairs.end())
2625656d797SCyndy Ishida       addDiffForTargSlice<DiffStrVec,
2635656d797SCyndy Ishida                           DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
2645656d797SCyndy Ishida           StringRef(Pair.second), Pair.first, Result, Order);
2655656d797SCyndy Ishida   }
2665656d797SCyndy Ishida }
2675656d797SCyndy Ishida 
findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,InterfaceFile::const_symbol_range LookupSyms,DiffOutput & Result,InterfaceInputOrder Order)2685656d797SCyndy Ishida void findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,
2695656d797SCyndy Ishida                     InterfaceFile::const_symbol_range LookupSyms,
2705656d797SCyndy Ishida                     DiffOutput &Result, InterfaceInputOrder Order) {
2715656d797SCyndy Ishida   Result.Kind = AD_Sym_Vec;
2725656d797SCyndy Ishida   for (const auto *Sym : CollectedSyms)
2735656d797SCyndy Ishida     for (const auto Targ : Sym->targets()) {
2745656d797SCyndy Ishida       auto FoundSym = llvm::any_of(LookupSyms, [&](const auto LSym) {
2755656d797SCyndy Ishida         return (Sym->getName() == LSym->getName() &&
2765656d797SCyndy Ishida                 Sym->getKind() == LSym->getKind() &&
2775656d797SCyndy Ishida                 Sym->getFlags() == LSym->getFlags() &&
2785656d797SCyndy Ishida                 llvm::is_contained(LSym->targets(), Targ));
2795656d797SCyndy Ishida       });
2805656d797SCyndy Ishida       if (!FoundSym)
2815656d797SCyndy Ishida         addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order);
2825656d797SCyndy Ishida     }
2835656d797SCyndy Ishida }
2845656d797SCyndy Ishida 
2855656d797SCyndy Ishida template <typename T>
recordDifferences(T LHS,T RHS,std::string Attr)2865656d797SCyndy Ishida DiffOutput recordDifferences(T LHS, T RHS, std::string Attr) {
2875656d797SCyndy Ishida   DiffOutput Diff(Attr);
2885656d797SCyndy Ishida   if (LHS.getKind() == RHS.getKind()) {
2895656d797SCyndy Ishida     Diff.Kind = LHS.getKind();
2905656d797SCyndy Ishida     Diff.Values.push_back(std::make_unique<T>(LHS));
2915656d797SCyndy Ishida     Diff.Values.push_back(std::make_unique<T>(RHS));
2925656d797SCyndy Ishida   }
2935656d797SCyndy Ishida   return Diff;
2945656d797SCyndy Ishida }
2955656d797SCyndy Ishida 
2965656d797SCyndy Ishida template <typename T>
recordDifferences(const std::vector<T> & LHS,const std::vector<T> & RHS,std::string Attr)2975656d797SCyndy Ishida DiffOutput recordDifferences(const std::vector<T> &LHS,
2985656d797SCyndy Ishida                              const std::vector<T> &RHS, std::string Attr) {
2995656d797SCyndy Ishida   DiffOutput Diff(Attr);
3005656d797SCyndy Ishida   Diff.Kind = AD_Str_Vec;
3015656d797SCyndy Ishida   findAndAddDiff(LHS, RHS, Diff, lhs);
3025656d797SCyndy Ishida   findAndAddDiff(RHS, LHS, Diff, rhs);
3035656d797SCyndy Ishida   return Diff;
3045656d797SCyndy Ishida }
3055656d797SCyndy Ishida 
recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,llvm::MachO::InterfaceFile::const_symbol_range RHS,std::string Attr)3065656d797SCyndy Ishida DiffOutput recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,
3075656d797SCyndy Ishida                              llvm::MachO::InterfaceFile::const_symbol_range RHS,
3085656d797SCyndy Ishida                              std::string Attr) {
3095656d797SCyndy Ishida   DiffOutput Diff(Attr);
3105656d797SCyndy Ishida   Diff.Kind = AD_Sym_Vec;
3115656d797SCyndy Ishida   findAndAddDiff(LHS, RHS, Diff, lhs);
3125656d797SCyndy Ishida   findAndAddDiff(RHS, LHS, Diff, rhs);
3135656d797SCyndy Ishida   return Diff;
3145656d797SCyndy Ishida }
3155656d797SCyndy Ishida 
3165656d797SCyndy Ishida std::vector<DiffOutput>
findDifferences(const InterfaceFile * IFLHS,const InterfaceFile * IFRHS)3175656d797SCyndy Ishida DiffEngine::findDifferences(const InterfaceFile *IFLHS,
3185656d797SCyndy Ishida                             const InterfaceFile *IFRHS) {
3195656d797SCyndy Ishida   std::vector<DiffOutput> Output;
3205656d797SCyndy Ishida   if (IFLHS->getInstallName() != IFRHS->getInstallName())
3215656d797SCyndy Ishida     Output.push_back(recordDifferences(
3225656d797SCyndy Ishida         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(lhs,
3235656d797SCyndy Ishida                                                      IFLHS->getInstallName()),
3245656d797SCyndy Ishida         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(rhs,
3255656d797SCyndy Ishida                                                      IFRHS->getInstallName()),
3265656d797SCyndy Ishida         "Install Name"));
3275656d797SCyndy Ishida 
3285656d797SCyndy Ishida   if (IFLHS->getCurrentVersion() != IFRHS->getCurrentVersion())
3295656d797SCyndy Ishida     Output.push_back(recordDifferences(
3305656d797SCyndy Ishida         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3315656d797SCyndy Ishida             lhs, IFLHS->getCurrentVersion()),
3325656d797SCyndy Ishida         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3335656d797SCyndy Ishida             rhs, IFRHS->getCurrentVersion()),
3345656d797SCyndy Ishida         "Current Version"));
3355656d797SCyndy Ishida   if (IFLHS->getCompatibilityVersion() != IFRHS->getCompatibilityVersion())
3365656d797SCyndy Ishida     Output.push_back(recordDifferences(
3375656d797SCyndy Ishida         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3385656d797SCyndy Ishida             lhs, IFLHS->getCompatibilityVersion()),
3395656d797SCyndy Ishida         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3405656d797SCyndy Ishida             rhs, IFRHS->getCompatibilityVersion()),
3415656d797SCyndy Ishida         "Compatibility Version"));
3425656d797SCyndy Ishida   if (IFLHS->getSwiftABIVersion() != IFRHS->getSwiftABIVersion())
3435656d797SCyndy Ishida     Output.push_back(
3445656d797SCyndy Ishida         recordDifferences(DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
3455656d797SCyndy Ishida                               lhs, IFLHS->getSwiftABIVersion()),
3465656d797SCyndy Ishida                           DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
3475656d797SCyndy Ishida                               rhs, IFRHS->getSwiftABIVersion()),
3485656d797SCyndy Ishida                           "Swift ABI Version"));
3495656d797SCyndy Ishida 
3505656d797SCyndy Ishida   if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace())
3515656d797SCyndy Ishida     Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3525656d797SCyndy Ishida                                            lhs, IFLHS->isTwoLevelNamespace()),
3535656d797SCyndy Ishida                                        DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3545656d797SCyndy Ishida                                            rhs, IFRHS->isTwoLevelNamespace()),
3555656d797SCyndy Ishida                                        "Two Level Namespace"));
3565656d797SCyndy Ishida 
3575656d797SCyndy Ishida   if (IFLHS->isApplicationExtensionSafe() !=
3585656d797SCyndy Ishida       IFRHS->isApplicationExtensionSafe())
3595656d797SCyndy Ishida     Output.push_back(
3605656d797SCyndy Ishida         recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3615656d797SCyndy Ishida                               lhs, IFLHS->isApplicationExtensionSafe()),
3625656d797SCyndy Ishida                           DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3635656d797SCyndy Ishida                               rhs, IFRHS->isApplicationExtensionSafe()),
3645656d797SCyndy Ishida                           "Application Extension Safe"));
3655656d797SCyndy Ishida 
366913f21aeSCyndy Ishida   if (IFLHS->hasSimulatorSupport() != IFRHS->hasSimulatorSupport())
367913f21aeSCyndy Ishida     Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
368913f21aeSCyndy Ishida                                            lhs, IFLHS->hasSimulatorSupport()),
369913f21aeSCyndy Ishida                                        DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
370913f21aeSCyndy Ishida                                            rhs, IFRHS->hasSimulatorSupport()),
371913f21aeSCyndy Ishida                                        "Simulator Support"));
372913f21aeSCyndy Ishida 
373e17efa60SCyndy Ishida   if (IFLHS->isOSLibNotForSharedCache() != IFRHS->isOSLibNotForSharedCache())
374e17efa60SCyndy Ishida     Output.push_back(
375e17efa60SCyndy Ishida         recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
376e17efa60SCyndy Ishida                               lhs, IFLHS->isOSLibNotForSharedCache()),
377e17efa60SCyndy Ishida                           DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
378e17efa60SCyndy Ishida                               rhs, IFRHS->isOSLibNotForSharedCache()),
379e17efa60SCyndy Ishida                           "Shared Cache Ineligible"));
380e17efa60SCyndy Ishida 
3815656d797SCyndy Ishida   if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries())
3825656d797SCyndy Ishida     Output.push_back(recordDifferences(IFLHS->reexportedLibraries(),
3835656d797SCyndy Ishida                                        IFRHS->reexportedLibraries(),
3845656d797SCyndy Ishida                                        "Reexported Libraries"));
3855656d797SCyndy Ishida 
3861a0d6992SCyndy Ishida   if (IFLHS->rpaths() != IFRHS->rpaths())
3871a0d6992SCyndy Ishida     Output.push_back(recordDifferences(IFLHS->rpaths(), IFRHS->rpaths(),
3881a0d6992SCyndy Ishida                                        "Run Path Search Paths"));
3891a0d6992SCyndy Ishida 
3905656d797SCyndy Ishida   if (IFLHS->allowableClients() != IFRHS->allowableClients())
3915656d797SCyndy Ishida     Output.push_back(recordDifferences(IFLHS->allowableClients(),
3925656d797SCyndy Ishida                                        IFRHS->allowableClients(),
3935656d797SCyndy Ishida                                        "Allowable Clients"));
3945656d797SCyndy Ishida 
3955656d797SCyndy Ishida   if (IFLHS->umbrellas() != IFRHS->umbrellas())
3965656d797SCyndy Ishida     Output.push_back(recordDifferences(IFLHS->umbrellas(), IFRHS->umbrellas(),
3975656d797SCyndy Ishida                                        "Parent Umbrellas"));
3985656d797SCyndy Ishida 
3995656d797SCyndy Ishida   if (!checkSymbolEquality(IFLHS->symbols(), IFRHS->symbols()))
4005656d797SCyndy Ishida     Output.push_back(
4015656d797SCyndy Ishida         recordDifferences(IFLHS->symbols(), IFRHS->symbols(), "Symbols"));
4025656d797SCyndy Ishida 
4035656d797SCyndy Ishida   if (IFLHS->documents() != IFRHS->documents()) {
4045656d797SCyndy Ishida     DiffOutput Docs("Inlined Reexported Frameworks/Libraries");
4055656d797SCyndy Ishida     Docs.Kind = AD_Inline_Doc;
4065656d797SCyndy Ishida     std::vector<StringRef> DocsInserted;
4075656d797SCyndy Ishida     // Iterate through inline frameworks/libraries from interface file and find
4085656d797SCyndy Ishida     // match based on install name.
4095656d797SCyndy Ishida     for (auto DocLHS : IFLHS->documents()) {
4105656d797SCyndy Ishida       auto Pair = llvm::find_if(IFRHS->documents(), [&](const auto &DocRHS) {
4115656d797SCyndy Ishida         return (DocLHS->getInstallName() == DocRHS->getInstallName());
4125656d797SCyndy Ishida       });
4135656d797SCyndy Ishida       // If a match found, recursively get differences between the pair.
4145656d797SCyndy Ishida       if (Pair != IFRHS->documents().end()) {
4155656d797SCyndy Ishida         InlineDoc PairDiff =
4165656d797SCyndy Ishida             InlineDoc(DocLHS->getInstallName(),
4175656d797SCyndy Ishida                       findDifferences(DocLHS.get(), Pair->get()));
4185656d797SCyndy Ishida         if (!PairDiff.DocValues.empty())
4195656d797SCyndy Ishida           Docs.Values.push_back(
4205656d797SCyndy Ishida               std::make_unique<InlineDoc>(std::move(PairDiff)));
4215656d797SCyndy Ishida       }
4225656d797SCyndy Ishida       // If a match is not found, get attributes from single item.
4235656d797SCyndy Ishida       else
4245656d797SCyndy Ishida         Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
4255656d797SCyndy Ishida             DocLHS->getInstallName(), getSingleIF(DocLHS.get(), lhs))));
4265656d797SCyndy Ishida       DocsInserted.push_back(DocLHS->getInstallName());
4275656d797SCyndy Ishida     }
4285656d797SCyndy Ishida     for (auto DocRHS : IFRHS->documents()) {
4295656d797SCyndy Ishida       auto WasGathered =
4305656d797SCyndy Ishida           llvm::any_of(DocsInserted, [&](const auto &GatheredDoc) {
4315656d797SCyndy Ishida             return (GatheredDoc == DocRHS->getInstallName());
4325656d797SCyndy Ishida           });
4335656d797SCyndy Ishida       if (!WasGathered)
4345656d797SCyndy Ishida         Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
4355656d797SCyndy Ishida             DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs))));
4365656d797SCyndy Ishida     }
4375656d797SCyndy Ishida     if (!Docs.Values.empty())
4385656d797SCyndy Ishida       Output.push_back(std::move(Docs));
4395656d797SCyndy Ishida   }
4405656d797SCyndy Ishida   return Output;
4415656d797SCyndy Ishida }
4425656d797SCyndy Ishida 
4435656d797SCyndy Ishida template <typename T>
printSingleVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4445656d797SCyndy Ishida void printSingleVal(std::string Indent, const DiffOutput &Attr,
4455656d797SCyndy Ishida                     raw_ostream &OS) {
4465656d797SCyndy Ishida   if (Attr.Values.empty())
4475656d797SCyndy Ishida     return;
4485656d797SCyndy Ishida   OS << Indent << Attr.Name << "\n";
4495656d797SCyndy Ishida   for (auto &RawItem : Attr.Values)
4505656d797SCyndy Ishida     if (T *Item = dyn_cast<T>(RawItem.get()))
4515656d797SCyndy Ishida       Item->print(OS, Indent);
4525656d797SCyndy Ishida }
4535656d797SCyndy Ishida 
4545656d797SCyndy Ishida template <typename T>
castValues(const std::unique_ptr<AttributeDiff> & RawAttr)4555656d797SCyndy Ishida T *castValues(const std::unique_ptr<AttributeDiff> &RawAttr) {
4565656d797SCyndy Ishida   T *CastAttr = cast<T>(RawAttr.get());
4575656d797SCyndy Ishida   return CastAttr;
4585656d797SCyndy Ishida }
4595656d797SCyndy Ishida 
sortTargetValues(std::vector<T> & TargValues)4605656d797SCyndy Ishida template <typename T> void sortTargetValues(std::vector<T> &TargValues) {
4615656d797SCyndy Ishida   llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
4621094e2ebSDanila Kutenin     if (ValA.getOrder() == ValB.getOrder()) {
4631094e2ebSDanila Kutenin       return ValA.getVal() < ValB.getVal();
4641094e2ebSDanila Kutenin     }
4655656d797SCyndy Ishida     return ValA.getOrder() < ValB.getOrder();
4665656d797SCyndy Ishida   });
4675656d797SCyndy Ishida }
4685656d797SCyndy Ishida 
4695656d797SCyndy Ishida template <typename T>
printVecVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4705656d797SCyndy Ishida void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) {
4715656d797SCyndy Ishida   if (Attr.Values.empty())
4725656d797SCyndy Ishida     return;
4735656d797SCyndy Ishida 
4745656d797SCyndy Ishida   OS << Indent << Attr.Name << "\n";
4755656d797SCyndy Ishida 
4765656d797SCyndy Ishida   std::vector<T *> SortedAttrs;
4775656d797SCyndy Ishida 
4785656d797SCyndy Ishida   llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), castValues<T>);
4795656d797SCyndy Ishida 
4805656d797SCyndy Ishida   llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
4815656d797SCyndy Ishida     return ValA->Targ < ValB->Targ;
4825656d797SCyndy Ishida   });
4835656d797SCyndy Ishida 
4845656d797SCyndy Ishida   for (auto *Vec : SortedAttrs) {
4855656d797SCyndy Ishida     sortTargetValues<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
4865656d797SCyndy Ishida         Vec->TargValues);
4875656d797SCyndy Ishida     OS << Indent << "\t" << getTargetTripleName(Vec->Targ) << "\n";
4885656d797SCyndy Ishida     for (auto &Item : Vec->TargValues)
4895656d797SCyndy Ishida       Item.print(OS, Indent);
4905656d797SCyndy Ishida   }
4915656d797SCyndy Ishida }
4925656d797SCyndy Ishida 
4935656d797SCyndy Ishida template <>
printVecVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4945656d797SCyndy Ishida void printVecVal<DiffSymVec>(std::string Indent, const DiffOutput &Attr,
4955656d797SCyndy Ishida                              raw_ostream &OS) {
4965656d797SCyndy Ishida   if (Attr.Values.empty())
4975656d797SCyndy Ishida     return;
4985656d797SCyndy Ishida 
4995656d797SCyndy Ishida   OS << Indent << Attr.Name << "\n";
5005656d797SCyndy Ishida 
5015656d797SCyndy Ishida   std::vector<DiffSymVec *> SortedAttrs;
5025656d797SCyndy Ishida 
5035656d797SCyndy Ishida   llvm::transform(Attr.Values, std::back_inserter(SortedAttrs),
5045656d797SCyndy Ishida                   castValues<DiffSymVec>);
5055656d797SCyndy Ishida 
5065656d797SCyndy Ishida   llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
5075656d797SCyndy Ishida     return ValA->Targ < ValB->Targ;
5085656d797SCyndy Ishida   });
5095656d797SCyndy Ishida   for (auto *SymVec : SortedAttrs) {
5105656d797SCyndy Ishida     sortTargetValues<SymScalar>(SymVec->TargValues);
5115656d797SCyndy Ishida     OS << Indent << "\t" << getTargetTripleName(SymVec->Targ) << "\n";
5125656d797SCyndy Ishida     for (auto &Item : SymVec->TargValues)
5135656d797SCyndy Ishida       Item.print(OS, Indent, SymVec->Targ);
5145656d797SCyndy Ishida   }
5155656d797SCyndy Ishida }
5165656d797SCyndy Ishida 
printDifferences(raw_ostream & OS,const std::vector<DiffOutput> & Diffs,int IndentCounter)5175656d797SCyndy Ishida void DiffEngine::printDifferences(raw_ostream &OS,
5185656d797SCyndy Ishida                                   const std::vector<DiffOutput> &Diffs,
5195656d797SCyndy Ishida                                   int IndentCounter) {
5205656d797SCyndy Ishida   std::string Indent = std::string(IndentCounter, '\t');
5215656d797SCyndy Ishida   for (auto &Attr : Diffs) {
5225656d797SCyndy Ishida     switch (Attr.Kind) {
5235656d797SCyndy Ishida     case AD_Diff_Scalar_Str:
5245656d797SCyndy Ishida       if (IndentCounter == 0)
5255656d797SCyndy Ishida         printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(Indent,
5265656d797SCyndy Ishida                                                                      Attr, OS);
5275656d797SCyndy Ishida       break;
5285656d797SCyndy Ishida     case AD_Diff_Scalar_PackedVersion:
5295656d797SCyndy Ishida       printSingleVal<
5305656d797SCyndy Ishida           DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>>(Indent,
5315656d797SCyndy Ishida                                                                       Attr, OS);
5325656d797SCyndy Ishida       break;
5335656d797SCyndy Ishida     case AD_Diff_Scalar_Unsigned:
5345656d797SCyndy Ishida       printSingleVal<DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>>(Indent,
5355656d797SCyndy Ishida                                                                       Attr, OS);
5365656d797SCyndy Ishida       break;
5375656d797SCyndy Ishida     case AD_Diff_Scalar_Bool:
5385656d797SCyndy Ishida       printSingleVal<DiffScalarVal<bool, AD_Diff_Scalar_Bool>>(Indent, Attr,
5395656d797SCyndy Ishida                                                                OS);
5405656d797SCyndy Ishida       break;
5415656d797SCyndy Ishida     case AD_Str_Vec:
5425656d797SCyndy Ishida       printVecVal<DiffStrVec>(Indent, Attr, OS);
5435656d797SCyndy Ishida       break;
5445656d797SCyndy Ishida     case AD_Sym_Vec:
5455656d797SCyndy Ishida       printVecVal<DiffSymVec>(Indent, Attr, OS);
5465656d797SCyndy Ishida       break;
5475656d797SCyndy Ishida     case AD_Inline_Doc:
5485656d797SCyndy Ishida       if (!Attr.Values.empty()) {
5495656d797SCyndy Ishida         OS << Indent << Attr.Name << "\n";
5505656d797SCyndy Ishida         for (auto &Item : Attr.Values)
5515656d797SCyndy Ishida           if (InlineDoc *Doc = dyn_cast<InlineDoc>(Item.get()))
5525656d797SCyndy Ishida             if (!Doc->DocValues.empty()) {
5535656d797SCyndy Ishida               OS << Indent << "\t" << Doc->InstallName << "\n";
5545656d797SCyndy Ishida               printDifferences(OS, std::move(Doc->DocValues), 2);
5555656d797SCyndy Ishida             }
5565656d797SCyndy Ishida       }
5575656d797SCyndy Ishida       break;
5585656d797SCyndy Ishida     }
5595656d797SCyndy Ishida   }
5605656d797SCyndy Ishida }
5615656d797SCyndy Ishida 
compareFiles(raw_ostream & OS)5625656d797SCyndy Ishida bool DiffEngine::compareFiles(raw_ostream &OS) {
563ae182dbbSCyndy Ishida   if (*FileLHS == *FileRHS)
5645656d797SCyndy Ishida     return false;
565ae182dbbSCyndy Ishida   OS << "< " << std::string(FileLHS->getPath().data()) << "\n> "
566ae182dbbSCyndy Ishida      << std::string(FileRHS->getPath().data()) << "\n\n";
567ae182dbbSCyndy Ishida   std::vector<DiffOutput> Diffs = findDifferences(FileLHS, FileRHS);
5685656d797SCyndy Ishida   printDifferences(OS, Diffs, 0);
5695656d797SCyndy Ishida   return true;
5705656d797SCyndy Ishida }
571