15b5ab80eSSam Powell //===-- DiffEngine.cpp - Structural file comparison -----------------------===//
25b5ab80eSSam Powell //
35b5ab80eSSam Powell // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45b5ab80eSSam Powell // See https://llvm.org/LICENSE.txt for license information.
55b5ab80eSSam Powell // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65b5ab80eSSam Powell //
75b5ab80eSSam Powell //===----------------------------------------------------------------------===//
85b5ab80eSSam Powell //
95b5ab80eSSam Powell // This file defines the implementation of the llvm-tapi difference
105b5ab80eSSam Powell // engine, which structurally compares two tbd files.
115b5ab80eSSam Powell //
125b5ab80eSSam Powell //===----------------------------------------------------------------------===/
135b5ab80eSSam Powell #include "DiffEngine.h"
145b5ab80eSSam Powell #include "llvm/Support/Casting.h"
155b5ab80eSSam Powell #include "llvm/Support/raw_ostream.h"
165b5ab80eSSam Powell #include "llvm/TextAPI/InterfaceFile.h"
1756709b86SCyndy Ishida #include "llvm/TextAPI/Symbol.h"
185b5ab80eSSam Powell #include "llvm/TextAPI/Target.h"
195b5ab80eSSam Powell 
205b5ab80eSSam Powell using namespace llvm;
215b5ab80eSSam Powell using namespace MachO;
225b5ab80eSSam Powell using namespace object;
235b5ab80eSSam Powell 
setOrderIndicator(InterfaceInputOrder Order)245b5ab80eSSam Powell StringRef setOrderIndicator(InterfaceInputOrder Order) {
255b5ab80eSSam Powell   return ((Order == lhs) ? "< " : "> ");
265b5ab80eSSam Powell }
275b5ab80eSSam Powell 
285b5ab80eSSam Powell // The following template specialization implementations
295b5ab80eSSam Powell // need to be explicitly placed into the llvm namespace
305b5ab80eSSam Powell // to work around a GCC 4.8 bug.
315b5ab80eSSam Powell namespace llvm {
325b5ab80eSSam Powell 
335b5ab80eSSam Powell template <typename T, DiffAttrKind U>
print(raw_ostream & OS,std::string Indent)345b5ab80eSSam Powell inline void DiffScalarVal<T, U>::print(raw_ostream &OS, std::string Indent) {
355b5ab80eSSam Powell   OS << Indent << "\t" << setOrderIndicator(Order) << Val << "\n";
365b5ab80eSSam Powell }
375b5ab80eSSam Powell 
385b5ab80eSSam Powell template <>
395b5ab80eSSam Powell inline void
print(raw_ostream & OS,std::string Indent)405b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>::print(raw_ostream &OS,
415b5ab80eSSam Powell                                                     std::string Indent) {
425b5ab80eSSam Powell   OS << Indent << "\t\t" << setOrderIndicator(Order) << Val << "\n";
435b5ab80eSSam Powell }
445b5ab80eSSam Powell 
455b5ab80eSSam Powell template <>
465b5ab80eSSam Powell inline void
print(raw_ostream & OS,std::string Indent)475b5ab80eSSam Powell DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>::print(raw_ostream &OS,
485b5ab80eSSam Powell                                                        std::string Indent) {
495b5ab80eSSam Powell   OS << Indent << "\t" << setOrderIndicator(Order) << std::to_string(Val)
505b5ab80eSSam Powell      << "\n";
515b5ab80eSSam Powell }
525b5ab80eSSam Powell 
535b5ab80eSSam Powell template <>
545b5ab80eSSam Powell inline void
print(raw_ostream & OS,std::string Indent)555b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>::print(raw_ostream &OS,
565b5ab80eSSam Powell                                                 std::string Indent) {
575b5ab80eSSam Powell   OS << Indent << "\t" << setOrderIndicator(Order)
585b5ab80eSSam Powell      << ((Val == true) ? "true" : "false") << "\n";
595b5ab80eSSam Powell }
605b5ab80eSSam Powell 
615b5ab80eSSam Powell } // end namespace llvm
625b5ab80eSSam Powell 
getSymbolNamePrefix(MachO::SymbolKind Kind)6356709b86SCyndy Ishida StringLiteral SymScalar::getSymbolNamePrefix(MachO::SymbolKind Kind) {
645b5ab80eSSam Powell   switch (Kind) {
655b5ab80eSSam Powell   case MachO::SymbolKind::GlobalSymbol:
66fb9f9497SCyndy Ishida     return StringLiteral("");
675b5ab80eSSam Powell   case MachO::SymbolKind::ObjectiveCClass:
6856709b86SCyndy Ishida     return ObjC2MetaClassNamePrefix;
695b5ab80eSSam Powell   case MachO::SymbolKind ::ObjectiveCClassEHType:
7056709b86SCyndy Ishida     return ObjC2EHTypePrefix;
715b5ab80eSSam Powell   case MachO::SymbolKind ::ObjectiveCInstanceVariable:
7256709b86SCyndy Ishida     return ObjC2IVarPrefix;
735b5ab80eSSam Powell   }
745b5ab80eSSam Powell   llvm_unreachable("Unknown llvm::MachO::SymbolKind enum");
755b5ab80eSSam Powell }
765b5ab80eSSam Powell 
stringifySymbolFlag(MachO::SymbolFlags Flag)775b5ab80eSSam Powell std::string SymScalar::stringifySymbolFlag(MachO::SymbolFlags Flag) {
785b5ab80eSSam Powell   switch (Flag) {
795b5ab80eSSam Powell   case MachO::SymbolFlags::None:
805b5ab80eSSam Powell     return "";
815b5ab80eSSam Powell   case MachO::SymbolFlags::ThreadLocalValue:
825b5ab80eSSam Powell     return "Thread-Local";
835b5ab80eSSam Powell   case MachO::SymbolFlags::WeakDefined:
845b5ab80eSSam Powell     return "Weak-Defined";
855b5ab80eSSam Powell   case MachO::SymbolFlags::WeakReferenced:
865b5ab80eSSam Powell     return "Weak-Referenced";
875b5ab80eSSam Powell   case MachO::SymbolFlags::Undefined:
885b5ab80eSSam Powell     return "Undefined";
895b5ab80eSSam Powell   case MachO::SymbolFlags::Rexported:
905b5ab80eSSam Powell     return "Reexported";
915b5ab80eSSam Powell   }
925b5ab80eSSam Powell   llvm_unreachable("Unknown llvm::MachO::SymbolFlags enum");
935b5ab80eSSam Powell }
945b5ab80eSSam Powell 
print(raw_ostream & OS,std::string Indent,MachO::Target Targ)955b5ab80eSSam Powell void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) {
965b5ab80eSSam Powell   if (Val->getKind() == MachO::SymbolKind::ObjectiveCClass) {
97*3025c3edSJuergen Ributzka     if (Targ.Arch == MachO::AK_i386 && Targ.Platform == MachO::PLATFORM_MACOS) {
985b5ab80eSSam Powell       OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
9956709b86SCyndy Ishida          << ObjC1ClassNamePrefix << Val->getName()
1005b5ab80eSSam Powell          << getFlagString(Val->getFlags()) << "\n";
1015b5ab80eSSam Powell       return;
1025b5ab80eSSam Powell     }
10356709b86SCyndy Ishida     OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
10456709b86SCyndy Ishida        << ObjC2ClassNamePrefix << Val->getName()
10556709b86SCyndy Ishida        << getFlagString(Val->getFlags()) << "\n";
1065b5ab80eSSam Powell   }
1075b5ab80eSSam Powell   OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
10856709b86SCyndy Ishida      << getSymbolNamePrefix(Val->getKind()) << Val->getName()
1095b5ab80eSSam Powell      << getFlagString(Val->getFlags()) << "\n";
1105b5ab80eSSam Powell }
1115b5ab80eSSam Powell 
checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,llvm::MachO::InterfaceFile::const_symbol_range RHS)1125b5ab80eSSam Powell bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,
1135b5ab80eSSam Powell                          llvm::MachO::InterfaceFile::const_symbol_range RHS) {
1145b5ab80eSSam Powell   return std::equal(LHS.begin(), LHS.end(), RHS.begin(),
1155b5ab80eSSam Powell                     [&](auto LHS, auto RHS) { return *LHS == *RHS; });
1165b5ab80eSSam Powell }
1175b5ab80eSSam Powell 
1185b5ab80eSSam Powell template <typename TargetVecT, typename ValTypeT, typename V>
addDiffForTargSlice(V Val,Target Targ,DiffOutput & Diff,InterfaceInputOrder Order)1195b5ab80eSSam Powell void addDiffForTargSlice(V Val, Target Targ, DiffOutput &Diff,
1205b5ab80eSSam Powell                          InterfaceInputOrder Order) {
1215b5ab80eSSam Powell   auto TargetVector = llvm::find_if(
1225b5ab80eSSam Powell       Diff.Values, [&](const std::unique_ptr<AttributeDiff> &RawTVec) {
1235b5ab80eSSam Powell         if (TargetVecT *TVec = dyn_cast<TargetVecT>(RawTVec.get()))
1245b5ab80eSSam Powell           return TVec->Targ == Targ;
1255b5ab80eSSam Powell         return false;
1265b5ab80eSSam Powell       });
1275b5ab80eSSam Powell   if (TargetVector != Diff.Values.end()) {
1285b5ab80eSSam Powell     ValTypeT NewVal(Order, Val);
1295b5ab80eSSam Powell     cast<TargetVecT>(TargetVector->get())->TargValues.push_back(NewVal);
1305b5ab80eSSam Powell   } else {
1315b5ab80eSSam Powell     auto NewTargetVec = std::make_unique<TargetVecT>(Targ);
1325b5ab80eSSam Powell     ValTypeT NewVal(Order, Val);
1335b5ab80eSSam Powell     NewTargetVec->TargValues.push_back(NewVal);
1345b5ab80eSSam Powell     Diff.Values.push_back(std::move(NewTargetVec));
1355b5ab80eSSam Powell   }
1365b5ab80eSSam Powell }
1375b5ab80eSSam Powell 
getSingleAttrDiff(const std::vector<InterfaceFileRef> & IRefVec,std::string Name,InterfaceInputOrder Order)1385b5ab80eSSam Powell DiffOutput getSingleAttrDiff(const std::vector<InterfaceFileRef> &IRefVec,
1395b5ab80eSSam Powell                              std::string Name, InterfaceInputOrder Order) {
1405b5ab80eSSam Powell   DiffOutput Diff(Name);
1415b5ab80eSSam Powell   Diff.Kind = AD_Str_Vec;
1425b5ab80eSSam Powell   for (const auto &IRef : IRefVec)
1435b5ab80eSSam Powell     for (auto Targ : IRef.targets())
1445b5ab80eSSam Powell       addDiffForTargSlice<DiffStrVec,
1455b5ab80eSSam Powell                           DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
1465b5ab80eSSam Powell           IRef.getInstallName(), Targ, Diff, Order);
1475b5ab80eSSam Powell   return Diff;
1485b5ab80eSSam Powell }
1495b5ab80eSSam Powell 
1505b5ab80eSSam Powell DiffOutput
getSingleAttrDiff(const std::vector<std::pair<Target,std::string>> & PairVec,std::string Name,InterfaceInputOrder Order)1515b5ab80eSSam Powell getSingleAttrDiff(const std::vector<std::pair<Target, std::string>> &PairVec,
1525b5ab80eSSam Powell                   std::string Name, InterfaceInputOrder Order) {
1535b5ab80eSSam Powell   DiffOutput Diff(Name);
1545b5ab80eSSam Powell   Diff.Kind = AD_Str_Vec;
1555b5ab80eSSam Powell   for (const auto &Pair : PairVec)
1565b5ab80eSSam Powell     addDiffForTargSlice<DiffStrVec,
1575b5ab80eSSam Powell                         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
1585b5ab80eSSam Powell         StringRef(Pair.second), Pair.first, Diff, Order);
1595b5ab80eSSam Powell   return Diff;
1605b5ab80eSSam Powell }
1615b5ab80eSSam Powell 
getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,std::string Name,InterfaceInputOrder Order)1625b5ab80eSSam Powell DiffOutput getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,
1635b5ab80eSSam Powell                              std::string Name, InterfaceInputOrder Order) {
1645b5ab80eSSam Powell   DiffOutput Diff(Name);
1655b5ab80eSSam Powell   Diff.Kind = AD_Sym_Vec;
1665b5ab80eSSam Powell   for (const auto *Sym : SymRange)
1675b5ab80eSSam Powell     for (auto Targ : Sym->targets())
1685b5ab80eSSam Powell       addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Diff, Order);
1695b5ab80eSSam Powell   return Diff;
1705b5ab80eSSam Powell }
1715b5ab80eSSam Powell 
1725b5ab80eSSam Powell template <typename T>
getSingleAttrDiff(T SingleAttr,std::string Attribute)1735b5ab80eSSam Powell DiffOutput getSingleAttrDiff(T SingleAttr, std::string Attribute) {
1745b5ab80eSSam Powell   DiffOutput Diff(Attribute);
1755b5ab80eSSam Powell   Diff.Kind = SingleAttr.getKind();
1765b5ab80eSSam Powell   Diff.Values.push_back(std::make_unique<T>(SingleAttr));
1775b5ab80eSSam Powell   return Diff;
1785b5ab80eSSam Powell }
1795b5ab80eSSam Powell 
1805b5ab80eSSam Powell template <typename T, DiffAttrKind U>
diffAttribute(std::string Name,std::vector<DiffOutput> & Output,DiffScalarVal<T,U> Attr)1815b5ab80eSSam Powell void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
1825b5ab80eSSam Powell                    DiffScalarVal<T, U> Attr) {
1835b5ab80eSSam Powell   Output.push_back(getSingleAttrDiff(Attr, Name));
1845b5ab80eSSam Powell }
1855b5ab80eSSam Powell 
1865b5ab80eSSam Powell template <typename T>
diffAttribute(std::string Name,std::vector<DiffOutput> & Output,const T & Val,InterfaceInputOrder Order)1875b5ab80eSSam Powell void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
1885b5ab80eSSam Powell                    const T &Val, InterfaceInputOrder Order) {
1895b5ab80eSSam Powell   Output.push_back(getSingleAttrDiff(Val, Name, Order));
1905b5ab80eSSam Powell }
1915b5ab80eSSam Powell 
getSingleIF(InterfaceFile * Interface,InterfaceInputOrder Order)1925b5ab80eSSam Powell std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface,
1935b5ab80eSSam Powell                                     InterfaceInputOrder Order) {
1945b5ab80eSSam Powell   std::vector<DiffOutput> Output;
1955b5ab80eSSam Powell   diffAttribute("Install Name", Output,
1965b5ab80eSSam Powell                 DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(
1975b5ab80eSSam Powell                     Order, Interface->getInstallName()));
1985b5ab80eSSam Powell   diffAttribute("Current Version", Output,
1995b5ab80eSSam Powell                 DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
2005b5ab80eSSam Powell                     Order, Interface->getCurrentVersion()));
2015b5ab80eSSam Powell   diffAttribute("Compatibility Version", Output,
2025b5ab80eSSam Powell                 DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
2035b5ab80eSSam Powell                     Order, Interface->getCompatibilityVersion()));
2045b5ab80eSSam Powell   diffAttribute("Swift ABI Version", Output,
2055b5ab80eSSam Powell                 DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
2065b5ab80eSSam Powell                     Order, Interface->getSwiftABIVersion()));
2075b5ab80eSSam Powell   diffAttribute("InstallAPI", Output,
2085b5ab80eSSam Powell                 DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
2095b5ab80eSSam Powell                     Order, Interface->isInstallAPI()));
2105b5ab80eSSam Powell   diffAttribute("Two Level Namespace", Output,
2115b5ab80eSSam Powell                 DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
2125b5ab80eSSam Powell                     Order, Interface->isTwoLevelNamespace()));
2135b5ab80eSSam Powell   diffAttribute("Application Extension Safe", Output,
2145b5ab80eSSam Powell                 DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
2155b5ab80eSSam Powell                     Order, Interface->isApplicationExtensionSafe()));
2165b5ab80eSSam Powell   diffAttribute("Reexported Libraries", Output,
2175b5ab80eSSam Powell                 Interface->reexportedLibraries(), Order);
2185b5ab80eSSam Powell   diffAttribute("Allowable Clients", Output, Interface->allowableClients(),
2195b5ab80eSSam Powell                 Order);
2205b5ab80eSSam Powell   diffAttribute("Parent Umbrellas", Output, Interface->umbrellas(), Order);
2215b5ab80eSSam Powell   diffAttribute("Symbols", Output, Interface->symbols(), Order);
2225b5ab80eSSam Powell   for (auto Doc : Interface->documents()) {
2235b5ab80eSSam Powell     DiffOutput Documents("Inlined Reexported Frameworks/Libraries");
2245b5ab80eSSam Powell     Documents.Kind = AD_Inline_Doc;
2255b5ab80eSSam Powell     Documents.Values.push_back(std::make_unique<InlineDoc>(
2265b5ab80eSSam Powell         InlineDoc(Doc->getInstallName(), getSingleIF(Doc.get(), Order))));
2275b5ab80eSSam Powell     Output.push_back(std::move(Documents));
2285b5ab80eSSam Powell   }
2295b5ab80eSSam Powell   return Output;
2305b5ab80eSSam Powell }
2315b5ab80eSSam Powell 
findAndAddDiff(const std::vector<InterfaceFileRef> & CollectedIRefVec,const std::vector<InterfaceFileRef> & LookupIRefVec,DiffOutput & Result,InterfaceInputOrder Order)2325b5ab80eSSam Powell void findAndAddDiff(const std::vector<InterfaceFileRef> &CollectedIRefVec,
2335b5ab80eSSam Powell                     const std::vector<InterfaceFileRef> &LookupIRefVec,
2345b5ab80eSSam Powell                     DiffOutput &Result, InterfaceInputOrder Order) {
2355b5ab80eSSam Powell   Result.Kind = AD_Str_Vec;
2365b5ab80eSSam Powell   for (const auto &IRef : CollectedIRefVec)
2375b5ab80eSSam Powell     for (auto Targ : IRef.targets()) {
2385b5ab80eSSam Powell       auto FoundIRef = llvm::find_if(LookupIRefVec, [&](const auto LIRef) {
2395b5ab80eSSam Powell         auto FoundTarg = llvm::find(LIRef.targets(), Targ);
2405b5ab80eSSam Powell         return (FoundTarg != LIRef.targets().end() &&
2415b5ab80eSSam Powell                 IRef.getInstallName() == LIRef.getInstallName());
2425b5ab80eSSam Powell       });
2435b5ab80eSSam Powell       if (FoundIRef == LookupIRefVec.end())
2445b5ab80eSSam Powell         addDiffForTargSlice<DiffStrVec,
2455b5ab80eSSam Powell                             DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
2465b5ab80eSSam Powell             IRef.getInstallName(), Targ, Result, Order);
2475b5ab80eSSam Powell     }
2485b5ab80eSSam Powell }
2495b5ab80eSSam Powell 
findAndAddDiff(const std::vector<std::pair<Target,std::string>> & CollectedPairs,const std::vector<std::pair<Target,std::string>> & LookupPairs,DiffOutput & Result,InterfaceInputOrder Order)2505b5ab80eSSam Powell void findAndAddDiff(
2515b5ab80eSSam Powell     const std::vector<std::pair<Target, std::string>> &CollectedPairs,
2525b5ab80eSSam Powell     const std::vector<std::pair<Target, std::string>> &LookupPairs,
2535b5ab80eSSam Powell     DiffOutput &Result, InterfaceInputOrder Order) {
2545b5ab80eSSam Powell   Result.Kind = AD_Str_Vec;
2555b5ab80eSSam Powell   for (const auto &Pair : CollectedPairs) {
2565b5ab80eSSam Powell     auto FoundPair = llvm::find(LookupPairs, Pair);
2575b5ab80eSSam Powell     if (FoundPair == LookupPairs.end())
2585b5ab80eSSam Powell       addDiffForTargSlice<DiffStrVec,
2595b5ab80eSSam Powell                           DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
2605b5ab80eSSam Powell           StringRef(Pair.second), Pair.first, Result, Order);
2615b5ab80eSSam Powell   }
2625b5ab80eSSam Powell }
2635b5ab80eSSam Powell 
findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,InterfaceFile::const_symbol_range LookupSyms,DiffOutput & Result,InterfaceInputOrder Order)2645b5ab80eSSam Powell void findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,
2655b5ab80eSSam Powell                     InterfaceFile::const_symbol_range LookupSyms,
2665b5ab80eSSam Powell                     DiffOutput &Result, InterfaceInputOrder Order) {
2675b5ab80eSSam Powell   Result.Kind = AD_Sym_Vec;
2685b5ab80eSSam Powell   for (const auto *Sym : CollectedSyms)
2695b5ab80eSSam Powell     for (const auto Targ : Sym->targets()) {
2705b5ab80eSSam Powell       auto FoundSym = llvm::find_if(LookupSyms, [&](const auto LSym) {
2715b5ab80eSSam Powell         auto FoundTarg = llvm::find(LSym->targets(), Targ);
2725b5ab80eSSam Powell         return (Sym->getName() == LSym->getName() &&
2735b5ab80eSSam Powell                 Sym->getKind() == LSym->getKind() &&
2745b5ab80eSSam Powell                 Sym->getFlags() == LSym->getFlags() &&
2755b5ab80eSSam Powell                 FoundTarg != LSym->targets().end());
2765b5ab80eSSam Powell       });
2775b5ab80eSSam Powell       if (FoundSym == LookupSyms.end())
2785b5ab80eSSam Powell         addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order);
2795b5ab80eSSam Powell     }
2805b5ab80eSSam Powell }
2815b5ab80eSSam Powell 
2825b5ab80eSSam Powell template <typename T>
recordDifferences(T LHS,T RHS,std::string Attr)2835b5ab80eSSam Powell DiffOutput recordDifferences(T LHS, T RHS, std::string Attr) {
2845b5ab80eSSam Powell   DiffOutput Diff(Attr);
2855b5ab80eSSam Powell   if (LHS.getKind() == RHS.getKind()) {
2865b5ab80eSSam Powell     Diff.Kind = LHS.getKind();
2875b5ab80eSSam Powell     Diff.Values.push_back(std::make_unique<T>(LHS));
2885b5ab80eSSam Powell     Diff.Values.push_back(std::make_unique<T>(RHS));
2895b5ab80eSSam Powell   }
2905b5ab80eSSam Powell   return Diff;
2915b5ab80eSSam Powell }
2925b5ab80eSSam Powell 
2935b5ab80eSSam Powell template <typename T>
recordDifferences(const std::vector<T> & LHS,const std::vector<T> & RHS,std::string Attr)2945b5ab80eSSam Powell DiffOutput recordDifferences(const std::vector<T> &LHS,
2955b5ab80eSSam Powell                              const std::vector<T> &RHS, std::string Attr) {
2965b5ab80eSSam Powell   DiffOutput Diff(Attr);
2975b5ab80eSSam Powell   Diff.Kind = AD_Str_Vec;
2985b5ab80eSSam Powell   findAndAddDiff(LHS, RHS, Diff, lhs);
2995b5ab80eSSam Powell   findAndAddDiff(RHS, LHS, Diff, rhs);
3005b5ab80eSSam Powell   return Diff;
3015b5ab80eSSam Powell }
3025b5ab80eSSam Powell 
recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,llvm::MachO::InterfaceFile::const_symbol_range RHS,std::string Attr)3035b5ab80eSSam Powell DiffOutput recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,
3045b5ab80eSSam Powell                              llvm::MachO::InterfaceFile::const_symbol_range RHS,
3055b5ab80eSSam Powell                              std::string Attr) {
3065b5ab80eSSam Powell   DiffOutput Diff(Attr);
3075b5ab80eSSam Powell   Diff.Kind = AD_Sym_Vec;
3085b5ab80eSSam Powell   findAndAddDiff(LHS, RHS, Diff, lhs);
3095b5ab80eSSam Powell   findAndAddDiff(RHS, LHS, Diff, rhs);
3105b5ab80eSSam Powell   return Diff;
3115b5ab80eSSam Powell }
3125b5ab80eSSam Powell 
3135b5ab80eSSam Powell std::vector<DiffOutput>
findDifferences(const InterfaceFile * IFLHS,const InterfaceFile * IFRHS)3145b5ab80eSSam Powell DiffEngine::findDifferences(const InterfaceFile *IFLHS,
3155b5ab80eSSam Powell                             const InterfaceFile *IFRHS) {
3165b5ab80eSSam Powell   std::vector<DiffOutput> Output;
3175b5ab80eSSam Powell   if (IFLHS->getInstallName() != IFRHS->getInstallName())
3185b5ab80eSSam Powell     Output.push_back(recordDifferences(
3195b5ab80eSSam Powell         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(lhs,
3205b5ab80eSSam Powell                                                      IFLHS->getInstallName()),
3215b5ab80eSSam Powell         DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(rhs,
3225b5ab80eSSam Powell                                                      IFRHS->getInstallName()),
3235b5ab80eSSam Powell         "Install Name"));
3245b5ab80eSSam Powell 
3255b5ab80eSSam Powell   if (IFLHS->getCurrentVersion() != IFRHS->getCurrentVersion())
3265b5ab80eSSam Powell     Output.push_back(recordDifferences(
3275b5ab80eSSam Powell         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3285b5ab80eSSam Powell             lhs, IFLHS->getCurrentVersion()),
3295b5ab80eSSam Powell         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3305b5ab80eSSam Powell             rhs, IFRHS->getCurrentVersion()),
3315b5ab80eSSam Powell         "Current Version"));
3325b5ab80eSSam Powell   if (IFLHS->getCompatibilityVersion() != IFRHS->getCompatibilityVersion())
3335b5ab80eSSam Powell     Output.push_back(recordDifferences(
3345b5ab80eSSam Powell         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3355b5ab80eSSam Powell             lhs, IFLHS->getCompatibilityVersion()),
3365b5ab80eSSam Powell         DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
3375b5ab80eSSam Powell             rhs, IFRHS->getCompatibilityVersion()),
3385b5ab80eSSam Powell         "Compatibility Version"));
3395b5ab80eSSam Powell   if (IFLHS->getSwiftABIVersion() != IFRHS->getSwiftABIVersion())
3405b5ab80eSSam Powell     Output.push_back(
3415b5ab80eSSam Powell         recordDifferences(DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
3425b5ab80eSSam Powell                               lhs, IFLHS->getSwiftABIVersion()),
3435b5ab80eSSam Powell                           DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
3445b5ab80eSSam Powell                               rhs, IFRHS->getSwiftABIVersion()),
3455b5ab80eSSam Powell                           "Swift ABI Version"));
3465b5ab80eSSam Powell   if (IFLHS->isInstallAPI() != IFRHS->isInstallAPI())
3475b5ab80eSSam Powell     Output.push_back(recordDifferences(
3485b5ab80eSSam Powell         DiffScalarVal<bool, AD_Diff_Scalar_Bool>(lhs, IFLHS->isInstallAPI()),
3495b5ab80eSSam Powell         DiffScalarVal<bool, AD_Diff_Scalar_Bool>(rhs, IFRHS->isInstallAPI()),
3505b5ab80eSSam Powell         "InstallAPI"));
3515b5ab80eSSam Powell 
3525b5ab80eSSam Powell   if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace())
3535b5ab80eSSam Powell     Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3545b5ab80eSSam Powell                                            lhs, IFLHS->isTwoLevelNamespace()),
3555b5ab80eSSam Powell                                        DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3565b5ab80eSSam Powell                                            rhs, IFRHS->isTwoLevelNamespace()),
3575b5ab80eSSam Powell                                        "Two Level Namespace"));
3585b5ab80eSSam Powell 
3595b5ab80eSSam Powell   if (IFLHS->isApplicationExtensionSafe() !=
3605b5ab80eSSam Powell       IFRHS->isApplicationExtensionSafe())
3615b5ab80eSSam Powell     Output.push_back(
3625b5ab80eSSam Powell         recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3635b5ab80eSSam Powell                               lhs, IFLHS->isApplicationExtensionSafe()),
3645b5ab80eSSam Powell                           DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
3655b5ab80eSSam Powell                               rhs, IFRHS->isApplicationExtensionSafe()),
3665b5ab80eSSam Powell                           "Application Extension Safe"));
3675b5ab80eSSam Powell 
3685b5ab80eSSam Powell   if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries())
3695b5ab80eSSam Powell     Output.push_back(recordDifferences(IFLHS->reexportedLibraries(),
3705b5ab80eSSam Powell                                        IFRHS->reexportedLibraries(),
3715b5ab80eSSam Powell                                        "Reexported Libraries"));
3725b5ab80eSSam Powell 
3735b5ab80eSSam Powell   if (IFLHS->allowableClients() != IFRHS->allowableClients())
3745b5ab80eSSam Powell     Output.push_back(recordDifferences(IFLHS->allowableClients(),
3755b5ab80eSSam Powell                                        IFRHS->allowableClients(),
3765b5ab80eSSam Powell                                        "Allowable Clients"));
3775b5ab80eSSam Powell 
3785b5ab80eSSam Powell   if (IFLHS->umbrellas() != IFRHS->umbrellas())
3795b5ab80eSSam Powell     Output.push_back(recordDifferences(IFLHS->umbrellas(), IFRHS->umbrellas(),
3805b5ab80eSSam Powell                                        "Parent Umbrellas"));
3815b5ab80eSSam Powell 
3825b5ab80eSSam Powell   if (!checkSymbolEquality(IFLHS->symbols(), IFRHS->symbols()))
3835b5ab80eSSam Powell     Output.push_back(
3845b5ab80eSSam Powell         recordDifferences(IFLHS->symbols(), IFRHS->symbols(), "Symbols"));
3855b5ab80eSSam Powell 
3865b5ab80eSSam Powell   if (IFLHS->documents() != IFRHS->documents()) {
3875b5ab80eSSam Powell     DiffOutput Docs("Inlined Reexported Frameworks/Libraries");
3885b5ab80eSSam Powell     Docs.Kind = AD_Inline_Doc;
3895b5ab80eSSam Powell     std::vector<StringRef> DocsInserted;
3905b5ab80eSSam Powell     // Iterate through inline frameworks/libraries from interface file and find
3915b5ab80eSSam Powell     // match based on install name.
3925b5ab80eSSam Powell     for (auto DocLHS : IFLHS->documents()) {
3935b5ab80eSSam Powell       auto Pair = llvm::find_if(IFRHS->documents(), [&](const auto &DocRHS) {
3945b5ab80eSSam Powell         return (DocLHS->getInstallName() == DocRHS->getInstallName());
3955b5ab80eSSam Powell       });
3965b5ab80eSSam Powell       // If a match found, recursively get differences between the pair.
3975b5ab80eSSam Powell       if (Pair != IFRHS->documents().end()) {
3985b5ab80eSSam Powell         InlineDoc PairDiff =
3995b5ab80eSSam Powell             InlineDoc(DocLHS->getInstallName(),
4005b5ab80eSSam Powell                       findDifferences(DocLHS.get(), Pair->get()));
4015b5ab80eSSam Powell         if (!PairDiff.DocValues.empty())
4025b5ab80eSSam Powell           Docs.Values.push_back(
4035b5ab80eSSam Powell               std::make_unique<InlineDoc>(std::move(PairDiff)));
4045b5ab80eSSam Powell       }
4055b5ab80eSSam Powell       // If a match is not found, get attributes from single item.
4065b5ab80eSSam Powell       else
4075b5ab80eSSam Powell         Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
4085b5ab80eSSam Powell             DocLHS->getInstallName(), getSingleIF(DocLHS.get(), lhs))));
4095b5ab80eSSam Powell       DocsInserted.push_back(DocLHS->getInstallName());
4105b5ab80eSSam Powell     }
4115b5ab80eSSam Powell     for (auto DocRHS : IFRHS->documents()) {
4125b5ab80eSSam Powell       auto WasGathered =
4135b5ab80eSSam Powell           llvm::find_if(DocsInserted, [&](const auto &GatheredDoc) {
4145b5ab80eSSam Powell             return (GatheredDoc == DocRHS->getInstallName());
4155b5ab80eSSam Powell           });
4165b5ab80eSSam Powell       if (WasGathered == DocsInserted.end())
4175b5ab80eSSam Powell         Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
4185b5ab80eSSam Powell             DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs))));
4195b5ab80eSSam Powell     }
4205b5ab80eSSam Powell     if (!Docs.Values.empty())
4215b5ab80eSSam Powell       Output.push_back(std::move(Docs));
4225b5ab80eSSam Powell   }
4235b5ab80eSSam Powell   return Output;
4245b5ab80eSSam Powell }
4255b5ab80eSSam Powell 
4265b5ab80eSSam Powell template <typename T>
printSingleVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4275b5ab80eSSam Powell void printSingleVal(std::string Indent, const DiffOutput &Attr,
4285b5ab80eSSam Powell                     raw_ostream &OS) {
4295b5ab80eSSam Powell   if (Attr.Values.empty())
4305b5ab80eSSam Powell     return;
4315b5ab80eSSam Powell   OS << Indent << Attr.Name << "\n";
4325b5ab80eSSam Powell   for (auto &RawItem : Attr.Values)
4335b5ab80eSSam Powell     if (T *Item = dyn_cast<T>(RawItem.get()))
4345b5ab80eSSam Powell       Item->print(OS, Indent);
4355b5ab80eSSam Powell }
4365b5ab80eSSam Powell 
4375b5ab80eSSam Powell template <typename T>
castValues(const std::unique_ptr<AttributeDiff> & RawAttr)4385b5ab80eSSam Powell T *castValues(const std::unique_ptr<AttributeDiff> &RawAttr) {
4395b5ab80eSSam Powell   T *CastAttr = cast<T>(RawAttr.get());
4405b5ab80eSSam Powell   return CastAttr;
4415b5ab80eSSam Powell }
4425b5ab80eSSam Powell 
sortTargetValues(std::vector<T> & TargValues)4435b5ab80eSSam Powell template <typename T> void sortTargetValues(std::vector<T> &TargValues) {
4445b5ab80eSSam Powell   llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
4455b5ab80eSSam Powell     return ValA.getOrder() < ValB.getOrder();
4465b5ab80eSSam Powell   });
4475b5ab80eSSam Powell   llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
4485b5ab80eSSam Powell     return ValA.getOrder() == ValB.getOrder() && ValA.getVal() < ValB.getVal();
4495b5ab80eSSam Powell   });
4505b5ab80eSSam Powell }
4515b5ab80eSSam Powell 
4525b5ab80eSSam Powell template <typename T>
printVecVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4535b5ab80eSSam Powell void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) {
4545b5ab80eSSam Powell   if (Attr.Values.empty())
4555b5ab80eSSam Powell     return;
4565b5ab80eSSam Powell 
4575b5ab80eSSam Powell   OS << Indent << Attr.Name << "\n";
4585b5ab80eSSam Powell 
4595b5ab80eSSam Powell   std::vector<T *> SortedAttrs;
4605b5ab80eSSam Powell 
4615b5ab80eSSam Powell   llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), castValues<T>);
4625b5ab80eSSam Powell 
4635b5ab80eSSam Powell   llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
4645b5ab80eSSam Powell     return ValA->Targ < ValB->Targ;
4655b5ab80eSSam Powell   });
4665b5ab80eSSam Powell 
4675b5ab80eSSam Powell   for (auto *Vec : SortedAttrs) {
4685b5ab80eSSam Powell     sortTargetValues<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
4695b5ab80eSSam Powell         Vec->TargValues);
4705b5ab80eSSam Powell     OS << Indent << "\t" << getTargetTripleName(Vec->Targ) << "\n";
4715b5ab80eSSam Powell     for (auto &Item : Vec->TargValues)
4725b5ab80eSSam Powell       Item.print(OS, Indent);
4735b5ab80eSSam Powell   }
4745b5ab80eSSam Powell }
4755b5ab80eSSam Powell 
4765b5ab80eSSam Powell template <>
printVecVal(std::string Indent,const DiffOutput & Attr,raw_ostream & OS)4775b5ab80eSSam Powell void printVecVal<DiffSymVec>(std::string Indent, const DiffOutput &Attr,
4785b5ab80eSSam Powell                              raw_ostream &OS) {
4795b5ab80eSSam Powell   if (Attr.Values.empty())
4805b5ab80eSSam Powell     return;
4815b5ab80eSSam Powell 
4825b5ab80eSSam Powell   OS << Indent << Attr.Name << "\n";
4835b5ab80eSSam Powell 
4845b5ab80eSSam Powell   std::vector<DiffSymVec *> SortedAttrs;
4855b5ab80eSSam Powell 
4865b5ab80eSSam Powell   llvm::transform(Attr.Values, std::back_inserter(SortedAttrs),
4875b5ab80eSSam Powell                   castValues<DiffSymVec>);
4885b5ab80eSSam Powell 
4895b5ab80eSSam Powell   llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
4905b5ab80eSSam Powell     return ValA->Targ < ValB->Targ;
4915b5ab80eSSam Powell   });
4925b5ab80eSSam Powell   for (auto *SymVec : SortedAttrs) {
4935b5ab80eSSam Powell     sortTargetValues<SymScalar>(SymVec->TargValues);
4945b5ab80eSSam Powell     OS << Indent << "\t" << getTargetTripleName(SymVec->Targ) << "\n";
4955b5ab80eSSam Powell     for (auto &Item : SymVec->TargValues)
4965b5ab80eSSam Powell       Item.print(OS, Indent, SymVec->Targ);
4975b5ab80eSSam Powell   }
4985b5ab80eSSam Powell }
4995b5ab80eSSam Powell 
printDifferences(raw_ostream & OS,const std::vector<DiffOutput> & Diffs,int IndentCounter)5005b5ab80eSSam Powell void DiffEngine::printDifferences(raw_ostream &OS,
5015b5ab80eSSam Powell                                   const std::vector<DiffOutput> &Diffs,
5025b5ab80eSSam Powell                                   int IndentCounter) {
5035b5ab80eSSam Powell   std::string Indent = std::string(IndentCounter, '\t');
5045b5ab80eSSam Powell   for (auto &Attr : Diffs) {
5055b5ab80eSSam Powell     switch (Attr.Kind) {
5065b5ab80eSSam Powell     case AD_Diff_Scalar_Str:
5075b5ab80eSSam Powell       if (IndentCounter == 0)
5085b5ab80eSSam Powell         printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(Indent,
5095b5ab80eSSam Powell                                                                      Attr, OS);
5105b5ab80eSSam Powell       break;
5115b5ab80eSSam Powell     case AD_Diff_Scalar_PackedVersion:
5125b5ab80eSSam Powell       printSingleVal<
5135b5ab80eSSam Powell           DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>>(Indent,
5145b5ab80eSSam Powell                                                                       Attr, OS);
5155b5ab80eSSam Powell       break;
5165b5ab80eSSam Powell     case AD_Diff_Scalar_Unsigned:
5175b5ab80eSSam Powell       printSingleVal<DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>>(Indent,
5185b5ab80eSSam Powell                                                                       Attr, OS);
5195b5ab80eSSam Powell       break;
5205b5ab80eSSam Powell     case AD_Diff_Scalar_Bool:
5215b5ab80eSSam Powell       printSingleVal<DiffScalarVal<bool, AD_Diff_Scalar_Bool>>(Indent, Attr,
5225b5ab80eSSam Powell                                                                OS);
5235b5ab80eSSam Powell       break;
5245b5ab80eSSam Powell     case AD_Str_Vec:
5255b5ab80eSSam Powell       printVecVal<DiffStrVec>(Indent, Attr, OS);
5265b5ab80eSSam Powell       break;
5275b5ab80eSSam Powell     case AD_Sym_Vec:
5285b5ab80eSSam Powell       printVecVal<DiffSymVec>(Indent, Attr, OS);
5295b5ab80eSSam Powell       break;
5305b5ab80eSSam Powell     case AD_Inline_Doc:
5315b5ab80eSSam Powell       if (!Attr.Values.empty()) {
5325b5ab80eSSam Powell         OS << Indent << Attr.Name << "\n";
5335b5ab80eSSam Powell         for (auto &Item : Attr.Values)
5345b5ab80eSSam Powell           if (InlineDoc *Doc = dyn_cast<InlineDoc>(Item.get()))
5355b5ab80eSSam Powell             if (!Doc->DocValues.empty()) {
5365b5ab80eSSam Powell               OS << Indent << "\t" << Doc->InstallName << "\n";
5375b5ab80eSSam Powell               printDifferences(OS, std::move(Doc->DocValues), 2);
5385b5ab80eSSam Powell             }
5395b5ab80eSSam Powell       }
5405b5ab80eSSam Powell       break;
5415b5ab80eSSam Powell     }
5425b5ab80eSSam Powell   }
5435b5ab80eSSam Powell }
5445b5ab80eSSam Powell 
compareFiles(raw_ostream & OS)5455b5ab80eSSam Powell bool DiffEngine::compareFiles(raw_ostream &OS) {
5465b5ab80eSSam Powell   const auto *IFLHS = &(FileLHS->getInterfaceFile());
5475b5ab80eSSam Powell   const auto *IFRHS = &(FileRHS->getInterfaceFile());
5485b5ab80eSSam Powell   if (*IFLHS == *IFRHS)
5495b5ab80eSSam Powell     return false;
5505b5ab80eSSam Powell   OS << "< " << std::string(IFLHS->getPath().data()) << "\n> "
5515b5ab80eSSam Powell      << std::string(IFRHS->getPath().data()) << "\n\n";
5525b5ab80eSSam Powell   std::vector<DiffOutput> Diffs = findDifferences(IFLHS, IFRHS);
5535b5ab80eSSam Powell   printDifferences(OS, Diffs, 0);
5545b5ab80eSSam Powell   return true;
5555b5ab80eSSam Powell }
556