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" 17*56709b86SCyndy 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 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> 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 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 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 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 63*56709b86SCyndy Ishida StringLiteral SymScalar::getSymbolNamePrefix(MachO::SymbolKind Kind) { 645b5ab80eSSam Powell switch (Kind) { 655b5ab80eSSam Powell case MachO::SymbolKind::GlobalSymbol: 665b5ab80eSSam Powell return ""; 675b5ab80eSSam Powell case MachO::SymbolKind::ObjectiveCClass: 68*56709b86SCyndy Ishida return ObjC2MetaClassNamePrefix; 695b5ab80eSSam Powell case MachO::SymbolKind ::ObjectiveCClassEHType: 70*56709b86SCyndy Ishida return ObjC2EHTypePrefix; 715b5ab80eSSam Powell case MachO::SymbolKind ::ObjectiveCInstanceVariable: 72*56709b86SCyndy Ishida return ObjC2IVarPrefix; 735b5ab80eSSam Powell } 745b5ab80eSSam Powell llvm_unreachable("Unknown llvm::MachO::SymbolKind enum"); 755b5ab80eSSam Powell } 765b5ab80eSSam Powell 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 955b5ab80eSSam Powell void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) { 965b5ab80eSSam Powell if (Val->getKind() == MachO::SymbolKind::ObjectiveCClass) { 975b5ab80eSSam Powell if (Targ.Arch == MachO::AK_i386 && 985b5ab80eSSam Powell Targ.Platform == MachO::PlatformKind::macOS) { 995b5ab80eSSam Powell OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") 100*56709b86SCyndy Ishida << ObjC1ClassNamePrefix << Val->getName() 1015b5ab80eSSam Powell << getFlagString(Val->getFlags()) << "\n"; 1025b5ab80eSSam Powell return; 1035b5ab80eSSam Powell } 104*56709b86SCyndy Ishida OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") 105*56709b86SCyndy Ishida << ObjC2ClassNamePrefix << Val->getName() 106*56709b86SCyndy Ishida << getFlagString(Val->getFlags()) << "\n"; 1075b5ab80eSSam Powell } 1085b5ab80eSSam Powell OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ") 109*56709b86SCyndy Ishida << getSymbolNamePrefix(Val->getKind()) << Val->getName() 1105b5ab80eSSam Powell << getFlagString(Val->getFlags()) << "\n"; 1115b5ab80eSSam Powell } 1125b5ab80eSSam Powell 1135b5ab80eSSam Powell bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS, 1145b5ab80eSSam Powell llvm::MachO::InterfaceFile::const_symbol_range RHS) { 1155b5ab80eSSam Powell return std::equal(LHS.begin(), LHS.end(), RHS.begin(), 1165b5ab80eSSam Powell [&](auto LHS, auto RHS) { return *LHS == *RHS; }); 1175b5ab80eSSam Powell } 1185b5ab80eSSam Powell 1195b5ab80eSSam Powell template <typename TargetVecT, typename ValTypeT, typename V> 1205b5ab80eSSam Powell void addDiffForTargSlice(V Val, Target Targ, DiffOutput &Diff, 1215b5ab80eSSam Powell InterfaceInputOrder Order) { 1225b5ab80eSSam Powell auto TargetVector = llvm::find_if( 1235b5ab80eSSam Powell Diff.Values, [&](const std::unique_ptr<AttributeDiff> &RawTVec) { 1245b5ab80eSSam Powell if (TargetVecT *TVec = dyn_cast<TargetVecT>(RawTVec.get())) 1255b5ab80eSSam Powell return TVec->Targ == Targ; 1265b5ab80eSSam Powell return false; 1275b5ab80eSSam Powell }); 1285b5ab80eSSam Powell if (TargetVector != Diff.Values.end()) { 1295b5ab80eSSam Powell ValTypeT NewVal(Order, Val); 1305b5ab80eSSam Powell cast<TargetVecT>(TargetVector->get())->TargValues.push_back(NewVal); 1315b5ab80eSSam Powell } else { 1325b5ab80eSSam Powell auto NewTargetVec = std::make_unique<TargetVecT>(Targ); 1335b5ab80eSSam Powell ValTypeT NewVal(Order, Val); 1345b5ab80eSSam Powell NewTargetVec->TargValues.push_back(NewVal); 1355b5ab80eSSam Powell Diff.Values.push_back(std::move(NewTargetVec)); 1365b5ab80eSSam Powell } 1375b5ab80eSSam Powell } 1385b5ab80eSSam Powell 1395b5ab80eSSam Powell DiffOutput getSingleAttrDiff(const std::vector<InterfaceFileRef> &IRefVec, 1405b5ab80eSSam Powell std::string Name, InterfaceInputOrder Order) { 1415b5ab80eSSam Powell DiffOutput Diff(Name); 1425b5ab80eSSam Powell Diff.Kind = AD_Str_Vec; 1435b5ab80eSSam Powell for (const auto &IRef : IRefVec) 1445b5ab80eSSam Powell for (auto Targ : IRef.targets()) 1455b5ab80eSSam Powell addDiffForTargSlice<DiffStrVec, 1465b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>( 1475b5ab80eSSam Powell IRef.getInstallName(), Targ, Diff, Order); 1485b5ab80eSSam Powell return Diff; 1495b5ab80eSSam Powell } 1505b5ab80eSSam Powell 1515b5ab80eSSam Powell DiffOutput 1525b5ab80eSSam Powell getSingleAttrDiff(const std::vector<std::pair<Target, std::string>> &PairVec, 1535b5ab80eSSam Powell std::string Name, InterfaceInputOrder Order) { 1545b5ab80eSSam Powell DiffOutput Diff(Name); 1555b5ab80eSSam Powell Diff.Kind = AD_Str_Vec; 1565b5ab80eSSam Powell for (const auto &Pair : PairVec) 1575b5ab80eSSam Powell addDiffForTargSlice<DiffStrVec, 1585b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>( 1595b5ab80eSSam Powell StringRef(Pair.second), Pair.first, Diff, Order); 1605b5ab80eSSam Powell return Diff; 1615b5ab80eSSam Powell } 1625b5ab80eSSam Powell 1635b5ab80eSSam Powell DiffOutput getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange, 1645b5ab80eSSam Powell std::string Name, InterfaceInputOrder Order) { 1655b5ab80eSSam Powell DiffOutput Diff(Name); 1665b5ab80eSSam Powell Diff.Kind = AD_Sym_Vec; 1675b5ab80eSSam Powell for (const auto *Sym : SymRange) 1685b5ab80eSSam Powell for (auto Targ : Sym->targets()) 1695b5ab80eSSam Powell addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Diff, Order); 1705b5ab80eSSam Powell return Diff; 1715b5ab80eSSam Powell } 1725b5ab80eSSam Powell 1735b5ab80eSSam Powell template <typename T> 1745b5ab80eSSam Powell DiffOutput getSingleAttrDiff(T SingleAttr, std::string Attribute) { 1755b5ab80eSSam Powell DiffOutput Diff(Attribute); 1765b5ab80eSSam Powell Diff.Kind = SingleAttr.getKind(); 1775b5ab80eSSam Powell Diff.Values.push_back(std::make_unique<T>(SingleAttr)); 1785b5ab80eSSam Powell return Diff; 1795b5ab80eSSam Powell } 1805b5ab80eSSam Powell 1815b5ab80eSSam Powell template <typename T, DiffAttrKind U> 1825b5ab80eSSam Powell void diffAttribute(std::string Name, std::vector<DiffOutput> &Output, 1835b5ab80eSSam Powell DiffScalarVal<T, U> Attr) { 1845b5ab80eSSam Powell Output.push_back(getSingleAttrDiff(Attr, Name)); 1855b5ab80eSSam Powell } 1865b5ab80eSSam Powell 1875b5ab80eSSam Powell template <typename T> 1885b5ab80eSSam Powell void diffAttribute(std::string Name, std::vector<DiffOutput> &Output, 1895b5ab80eSSam Powell const T &Val, InterfaceInputOrder Order) { 1905b5ab80eSSam Powell Output.push_back(getSingleAttrDiff(Val, Name, Order)); 1915b5ab80eSSam Powell } 1925b5ab80eSSam Powell 1935b5ab80eSSam Powell std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface, 1945b5ab80eSSam Powell InterfaceInputOrder Order) { 1955b5ab80eSSam Powell std::vector<DiffOutput> Output; 1965b5ab80eSSam Powell diffAttribute("Install Name", Output, 1975b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>( 1985b5ab80eSSam Powell Order, Interface->getInstallName())); 1995b5ab80eSSam Powell diffAttribute("Current Version", Output, 2005b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 2015b5ab80eSSam Powell Order, Interface->getCurrentVersion())); 2025b5ab80eSSam Powell diffAttribute("Compatibility Version", Output, 2035b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 2045b5ab80eSSam Powell Order, Interface->getCompatibilityVersion())); 2055b5ab80eSSam Powell diffAttribute("Swift ABI Version", Output, 2065b5ab80eSSam Powell DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>( 2075b5ab80eSSam Powell Order, Interface->getSwiftABIVersion())); 2085b5ab80eSSam Powell diffAttribute("InstallAPI", Output, 2095b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 2105b5ab80eSSam Powell Order, Interface->isInstallAPI())); 2115b5ab80eSSam Powell diffAttribute("Two Level Namespace", Output, 2125b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 2135b5ab80eSSam Powell Order, Interface->isTwoLevelNamespace())); 2145b5ab80eSSam Powell diffAttribute("Application Extension Safe", Output, 2155b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 2165b5ab80eSSam Powell Order, Interface->isApplicationExtensionSafe())); 2175b5ab80eSSam Powell diffAttribute("Reexported Libraries", Output, 2185b5ab80eSSam Powell Interface->reexportedLibraries(), Order); 2195b5ab80eSSam Powell diffAttribute("Allowable Clients", Output, Interface->allowableClients(), 2205b5ab80eSSam Powell Order); 2215b5ab80eSSam Powell diffAttribute("Parent Umbrellas", Output, Interface->umbrellas(), Order); 2225b5ab80eSSam Powell diffAttribute("Symbols", Output, Interface->symbols(), Order); 2235b5ab80eSSam Powell for (auto Doc : Interface->documents()) { 2245b5ab80eSSam Powell DiffOutput Documents("Inlined Reexported Frameworks/Libraries"); 2255b5ab80eSSam Powell Documents.Kind = AD_Inline_Doc; 2265b5ab80eSSam Powell Documents.Values.push_back(std::make_unique<InlineDoc>( 2275b5ab80eSSam Powell InlineDoc(Doc->getInstallName(), getSingleIF(Doc.get(), Order)))); 2285b5ab80eSSam Powell Output.push_back(std::move(Documents)); 2295b5ab80eSSam Powell } 2305b5ab80eSSam Powell return Output; 2315b5ab80eSSam Powell } 2325b5ab80eSSam Powell 2335b5ab80eSSam Powell void findAndAddDiff(const std::vector<InterfaceFileRef> &CollectedIRefVec, 2345b5ab80eSSam Powell const std::vector<InterfaceFileRef> &LookupIRefVec, 2355b5ab80eSSam Powell DiffOutput &Result, InterfaceInputOrder Order) { 2365b5ab80eSSam Powell Result.Kind = AD_Str_Vec; 2375b5ab80eSSam Powell for (const auto &IRef : CollectedIRefVec) 2385b5ab80eSSam Powell for (auto Targ : IRef.targets()) { 2395b5ab80eSSam Powell auto FoundIRef = llvm::find_if(LookupIRefVec, [&](const auto LIRef) { 2405b5ab80eSSam Powell auto FoundTarg = llvm::find(LIRef.targets(), Targ); 2415b5ab80eSSam Powell return (FoundTarg != LIRef.targets().end() && 2425b5ab80eSSam Powell IRef.getInstallName() == LIRef.getInstallName()); 2435b5ab80eSSam Powell }); 2445b5ab80eSSam Powell if (FoundIRef == LookupIRefVec.end()) 2455b5ab80eSSam Powell addDiffForTargSlice<DiffStrVec, 2465b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>( 2475b5ab80eSSam Powell IRef.getInstallName(), Targ, Result, Order); 2485b5ab80eSSam Powell } 2495b5ab80eSSam Powell } 2505b5ab80eSSam Powell 2515b5ab80eSSam Powell void findAndAddDiff( 2525b5ab80eSSam Powell const std::vector<std::pair<Target, std::string>> &CollectedPairs, 2535b5ab80eSSam Powell const std::vector<std::pair<Target, std::string>> &LookupPairs, 2545b5ab80eSSam Powell DiffOutput &Result, InterfaceInputOrder Order) { 2555b5ab80eSSam Powell Result.Kind = AD_Str_Vec; 2565b5ab80eSSam Powell for (const auto &Pair : CollectedPairs) { 2575b5ab80eSSam Powell auto FoundPair = llvm::find(LookupPairs, Pair); 2585b5ab80eSSam Powell if (FoundPair == LookupPairs.end()) 2595b5ab80eSSam Powell addDiffForTargSlice<DiffStrVec, 2605b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>( 2615b5ab80eSSam Powell StringRef(Pair.second), Pair.first, Result, Order); 2625b5ab80eSSam Powell } 2635b5ab80eSSam Powell } 2645b5ab80eSSam Powell 2655b5ab80eSSam Powell void findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms, 2665b5ab80eSSam Powell InterfaceFile::const_symbol_range LookupSyms, 2675b5ab80eSSam Powell DiffOutput &Result, InterfaceInputOrder Order) { 2685b5ab80eSSam Powell Result.Kind = AD_Sym_Vec; 2695b5ab80eSSam Powell for (const auto *Sym : CollectedSyms) 2705b5ab80eSSam Powell for (const auto Targ : Sym->targets()) { 2715b5ab80eSSam Powell auto FoundSym = llvm::find_if(LookupSyms, [&](const auto LSym) { 2725b5ab80eSSam Powell auto FoundTarg = llvm::find(LSym->targets(), Targ); 2735b5ab80eSSam Powell return (Sym->getName() == LSym->getName() && 2745b5ab80eSSam Powell Sym->getKind() == LSym->getKind() && 2755b5ab80eSSam Powell Sym->getFlags() == LSym->getFlags() && 2765b5ab80eSSam Powell FoundTarg != LSym->targets().end()); 2775b5ab80eSSam Powell }); 2785b5ab80eSSam Powell if (FoundSym == LookupSyms.end()) 2795b5ab80eSSam Powell addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order); 2805b5ab80eSSam Powell } 2815b5ab80eSSam Powell } 2825b5ab80eSSam Powell 2835b5ab80eSSam Powell template <typename T> 2845b5ab80eSSam Powell DiffOutput recordDifferences(T LHS, T RHS, std::string Attr) { 2855b5ab80eSSam Powell DiffOutput Diff(Attr); 2865b5ab80eSSam Powell if (LHS.getKind() == RHS.getKind()) { 2875b5ab80eSSam Powell Diff.Kind = LHS.getKind(); 2885b5ab80eSSam Powell Diff.Values.push_back(std::make_unique<T>(LHS)); 2895b5ab80eSSam Powell Diff.Values.push_back(std::make_unique<T>(RHS)); 2905b5ab80eSSam Powell } 2915b5ab80eSSam Powell return Diff; 2925b5ab80eSSam Powell } 2935b5ab80eSSam Powell 2945b5ab80eSSam Powell template <typename T> 2955b5ab80eSSam Powell DiffOutput recordDifferences(const std::vector<T> &LHS, 2965b5ab80eSSam Powell const std::vector<T> &RHS, std::string Attr) { 2975b5ab80eSSam Powell DiffOutput Diff(Attr); 2985b5ab80eSSam Powell Diff.Kind = AD_Str_Vec; 2995b5ab80eSSam Powell findAndAddDiff(LHS, RHS, Diff, lhs); 3005b5ab80eSSam Powell findAndAddDiff(RHS, LHS, Diff, rhs); 3015b5ab80eSSam Powell return Diff; 3025b5ab80eSSam Powell } 3035b5ab80eSSam Powell 3045b5ab80eSSam Powell DiffOutput recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS, 3055b5ab80eSSam Powell llvm::MachO::InterfaceFile::const_symbol_range RHS, 3065b5ab80eSSam Powell std::string Attr) { 3075b5ab80eSSam Powell DiffOutput Diff(Attr); 3085b5ab80eSSam Powell Diff.Kind = AD_Sym_Vec; 3095b5ab80eSSam Powell findAndAddDiff(LHS, RHS, Diff, lhs); 3105b5ab80eSSam Powell findAndAddDiff(RHS, LHS, Diff, rhs); 3115b5ab80eSSam Powell return Diff; 3125b5ab80eSSam Powell } 3135b5ab80eSSam Powell 3145b5ab80eSSam Powell std::vector<DiffOutput> 3155b5ab80eSSam Powell DiffEngine::findDifferences(const InterfaceFile *IFLHS, 3165b5ab80eSSam Powell const InterfaceFile *IFRHS) { 3175b5ab80eSSam Powell std::vector<DiffOutput> Output; 3185b5ab80eSSam Powell if (IFLHS->getInstallName() != IFRHS->getInstallName()) 3195b5ab80eSSam Powell Output.push_back(recordDifferences( 3205b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(lhs, 3215b5ab80eSSam Powell IFLHS->getInstallName()), 3225b5ab80eSSam Powell DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(rhs, 3235b5ab80eSSam Powell IFRHS->getInstallName()), 3245b5ab80eSSam Powell "Install Name")); 3255b5ab80eSSam Powell 3265b5ab80eSSam Powell if (IFLHS->getCurrentVersion() != IFRHS->getCurrentVersion()) 3275b5ab80eSSam Powell Output.push_back(recordDifferences( 3285b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 3295b5ab80eSSam Powell lhs, IFLHS->getCurrentVersion()), 3305b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 3315b5ab80eSSam Powell rhs, IFRHS->getCurrentVersion()), 3325b5ab80eSSam Powell "Current Version")); 3335b5ab80eSSam Powell if (IFLHS->getCompatibilityVersion() != IFRHS->getCompatibilityVersion()) 3345b5ab80eSSam Powell Output.push_back(recordDifferences( 3355b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 3365b5ab80eSSam Powell lhs, IFLHS->getCompatibilityVersion()), 3375b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>( 3385b5ab80eSSam Powell rhs, IFRHS->getCompatibilityVersion()), 3395b5ab80eSSam Powell "Compatibility Version")); 3405b5ab80eSSam Powell if (IFLHS->getSwiftABIVersion() != IFRHS->getSwiftABIVersion()) 3415b5ab80eSSam Powell Output.push_back( 3425b5ab80eSSam Powell recordDifferences(DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>( 3435b5ab80eSSam Powell lhs, IFLHS->getSwiftABIVersion()), 3445b5ab80eSSam Powell DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>( 3455b5ab80eSSam Powell rhs, IFRHS->getSwiftABIVersion()), 3465b5ab80eSSam Powell "Swift ABI Version")); 3475b5ab80eSSam Powell if (IFLHS->isInstallAPI() != IFRHS->isInstallAPI()) 3485b5ab80eSSam Powell Output.push_back(recordDifferences( 3495b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>(lhs, IFLHS->isInstallAPI()), 3505b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>(rhs, IFRHS->isInstallAPI()), 3515b5ab80eSSam Powell "InstallAPI")); 3525b5ab80eSSam Powell 3535b5ab80eSSam Powell if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace()) 3545b5ab80eSSam Powell Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 3555b5ab80eSSam Powell lhs, IFLHS->isTwoLevelNamespace()), 3565b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 3575b5ab80eSSam Powell rhs, IFRHS->isTwoLevelNamespace()), 3585b5ab80eSSam Powell "Two Level Namespace")); 3595b5ab80eSSam Powell 3605b5ab80eSSam Powell if (IFLHS->isApplicationExtensionSafe() != 3615b5ab80eSSam Powell IFRHS->isApplicationExtensionSafe()) 3625b5ab80eSSam Powell Output.push_back( 3635b5ab80eSSam Powell recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 3645b5ab80eSSam Powell lhs, IFLHS->isApplicationExtensionSafe()), 3655b5ab80eSSam Powell DiffScalarVal<bool, AD_Diff_Scalar_Bool>( 3665b5ab80eSSam Powell rhs, IFRHS->isApplicationExtensionSafe()), 3675b5ab80eSSam Powell "Application Extension Safe")); 3685b5ab80eSSam Powell 3695b5ab80eSSam Powell if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries()) 3705b5ab80eSSam Powell Output.push_back(recordDifferences(IFLHS->reexportedLibraries(), 3715b5ab80eSSam Powell IFRHS->reexportedLibraries(), 3725b5ab80eSSam Powell "Reexported Libraries")); 3735b5ab80eSSam Powell 3745b5ab80eSSam Powell if (IFLHS->allowableClients() != IFRHS->allowableClients()) 3755b5ab80eSSam Powell Output.push_back(recordDifferences(IFLHS->allowableClients(), 3765b5ab80eSSam Powell IFRHS->allowableClients(), 3775b5ab80eSSam Powell "Allowable Clients")); 3785b5ab80eSSam Powell 3795b5ab80eSSam Powell if (IFLHS->umbrellas() != IFRHS->umbrellas()) 3805b5ab80eSSam Powell Output.push_back(recordDifferences(IFLHS->umbrellas(), IFRHS->umbrellas(), 3815b5ab80eSSam Powell "Parent Umbrellas")); 3825b5ab80eSSam Powell 3835b5ab80eSSam Powell if (!checkSymbolEquality(IFLHS->symbols(), IFRHS->symbols())) 3845b5ab80eSSam Powell Output.push_back( 3855b5ab80eSSam Powell recordDifferences(IFLHS->symbols(), IFRHS->symbols(), "Symbols")); 3865b5ab80eSSam Powell 3875b5ab80eSSam Powell if (IFLHS->documents() != IFRHS->documents()) { 3885b5ab80eSSam Powell DiffOutput Docs("Inlined Reexported Frameworks/Libraries"); 3895b5ab80eSSam Powell Docs.Kind = AD_Inline_Doc; 3905b5ab80eSSam Powell std::vector<StringRef> DocsInserted; 3915b5ab80eSSam Powell // Iterate through inline frameworks/libraries from interface file and find 3925b5ab80eSSam Powell // match based on install name. 3935b5ab80eSSam Powell for (auto DocLHS : IFLHS->documents()) { 3945b5ab80eSSam Powell auto Pair = llvm::find_if(IFRHS->documents(), [&](const auto &DocRHS) { 3955b5ab80eSSam Powell return (DocLHS->getInstallName() == DocRHS->getInstallName()); 3965b5ab80eSSam Powell }); 3975b5ab80eSSam Powell // If a match found, recursively get differences between the pair. 3985b5ab80eSSam Powell if (Pair != IFRHS->documents().end()) { 3995b5ab80eSSam Powell InlineDoc PairDiff = 4005b5ab80eSSam Powell InlineDoc(DocLHS->getInstallName(), 4015b5ab80eSSam Powell findDifferences(DocLHS.get(), Pair->get())); 4025b5ab80eSSam Powell if (!PairDiff.DocValues.empty()) 4035b5ab80eSSam Powell Docs.Values.push_back( 4045b5ab80eSSam Powell std::make_unique<InlineDoc>(std::move(PairDiff))); 4055b5ab80eSSam Powell } 4065b5ab80eSSam Powell // If a match is not found, get attributes from single item. 4075b5ab80eSSam Powell else 4085b5ab80eSSam Powell Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc( 4095b5ab80eSSam Powell DocLHS->getInstallName(), getSingleIF(DocLHS.get(), lhs)))); 4105b5ab80eSSam Powell DocsInserted.push_back(DocLHS->getInstallName()); 4115b5ab80eSSam Powell } 4125b5ab80eSSam Powell for (auto DocRHS : IFRHS->documents()) { 4135b5ab80eSSam Powell auto WasGathered = 4145b5ab80eSSam Powell llvm::find_if(DocsInserted, [&](const auto &GatheredDoc) { 4155b5ab80eSSam Powell return (GatheredDoc == DocRHS->getInstallName()); 4165b5ab80eSSam Powell }); 4175b5ab80eSSam Powell if (WasGathered == DocsInserted.end()) 4185b5ab80eSSam Powell Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc( 4195b5ab80eSSam Powell DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs)))); 4205b5ab80eSSam Powell } 4215b5ab80eSSam Powell if (!Docs.Values.empty()) 4225b5ab80eSSam Powell Output.push_back(std::move(Docs)); 4235b5ab80eSSam Powell } 4245b5ab80eSSam Powell return Output; 4255b5ab80eSSam Powell } 4265b5ab80eSSam Powell 4275b5ab80eSSam Powell template <typename T> 4285b5ab80eSSam Powell void printSingleVal(std::string Indent, const DiffOutput &Attr, 4295b5ab80eSSam Powell raw_ostream &OS) { 4305b5ab80eSSam Powell if (Attr.Values.empty()) 4315b5ab80eSSam Powell return; 4325b5ab80eSSam Powell OS << Indent << Attr.Name << "\n"; 4335b5ab80eSSam Powell for (auto &RawItem : Attr.Values) 4345b5ab80eSSam Powell if (T *Item = dyn_cast<T>(RawItem.get())) 4355b5ab80eSSam Powell Item->print(OS, Indent); 4365b5ab80eSSam Powell } 4375b5ab80eSSam Powell 4385b5ab80eSSam Powell template <typename T> 4395b5ab80eSSam Powell T *castValues(const std::unique_ptr<AttributeDiff> &RawAttr) { 4405b5ab80eSSam Powell T *CastAttr = cast<T>(RawAttr.get()); 4415b5ab80eSSam Powell return CastAttr; 4425b5ab80eSSam Powell } 4435b5ab80eSSam Powell 4445b5ab80eSSam Powell template <typename T> void sortTargetValues(std::vector<T> &TargValues) { 4455b5ab80eSSam Powell llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) { 4465b5ab80eSSam Powell return ValA.getOrder() < ValB.getOrder(); 4475b5ab80eSSam Powell }); 4485b5ab80eSSam Powell llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) { 4495b5ab80eSSam Powell return ValA.getOrder() == ValB.getOrder() && ValA.getVal() < ValB.getVal(); 4505b5ab80eSSam Powell }); 4515b5ab80eSSam Powell } 4525b5ab80eSSam Powell 4535b5ab80eSSam Powell template <typename T> 4545b5ab80eSSam Powell void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) { 4555b5ab80eSSam Powell if (Attr.Values.empty()) 4565b5ab80eSSam Powell return; 4575b5ab80eSSam Powell 4585b5ab80eSSam Powell OS << Indent << Attr.Name << "\n"; 4595b5ab80eSSam Powell 4605b5ab80eSSam Powell std::vector<T *> SortedAttrs; 4615b5ab80eSSam Powell 4625b5ab80eSSam Powell llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), castValues<T>); 4635b5ab80eSSam Powell 4645b5ab80eSSam Powell llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) { 4655b5ab80eSSam Powell return ValA->Targ < ValB->Targ; 4665b5ab80eSSam Powell }); 4675b5ab80eSSam Powell 4685b5ab80eSSam Powell for (auto *Vec : SortedAttrs) { 4695b5ab80eSSam Powell sortTargetValues<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>( 4705b5ab80eSSam Powell Vec->TargValues); 4715b5ab80eSSam Powell OS << Indent << "\t" << getTargetTripleName(Vec->Targ) << "\n"; 4725b5ab80eSSam Powell for (auto &Item : Vec->TargValues) 4735b5ab80eSSam Powell Item.print(OS, Indent); 4745b5ab80eSSam Powell } 4755b5ab80eSSam Powell } 4765b5ab80eSSam Powell 4775b5ab80eSSam Powell template <> 4785b5ab80eSSam Powell void printVecVal<DiffSymVec>(std::string Indent, const DiffOutput &Attr, 4795b5ab80eSSam Powell raw_ostream &OS) { 4805b5ab80eSSam Powell if (Attr.Values.empty()) 4815b5ab80eSSam Powell return; 4825b5ab80eSSam Powell 4835b5ab80eSSam Powell OS << Indent << Attr.Name << "\n"; 4845b5ab80eSSam Powell 4855b5ab80eSSam Powell std::vector<DiffSymVec *> SortedAttrs; 4865b5ab80eSSam Powell 4875b5ab80eSSam Powell llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), 4885b5ab80eSSam Powell castValues<DiffSymVec>); 4895b5ab80eSSam Powell 4905b5ab80eSSam Powell llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) { 4915b5ab80eSSam Powell return ValA->Targ < ValB->Targ; 4925b5ab80eSSam Powell }); 4935b5ab80eSSam Powell for (auto *SymVec : SortedAttrs) { 4945b5ab80eSSam Powell sortTargetValues<SymScalar>(SymVec->TargValues); 4955b5ab80eSSam Powell OS << Indent << "\t" << getTargetTripleName(SymVec->Targ) << "\n"; 4965b5ab80eSSam Powell for (auto &Item : SymVec->TargValues) 4975b5ab80eSSam Powell Item.print(OS, Indent, SymVec->Targ); 4985b5ab80eSSam Powell } 4995b5ab80eSSam Powell } 5005b5ab80eSSam Powell 5015b5ab80eSSam Powell void DiffEngine::printDifferences(raw_ostream &OS, 5025b5ab80eSSam Powell const std::vector<DiffOutput> &Diffs, 5035b5ab80eSSam Powell int IndentCounter) { 5045b5ab80eSSam Powell std::string Indent = std::string(IndentCounter, '\t'); 5055b5ab80eSSam Powell for (auto &Attr : Diffs) { 5065b5ab80eSSam Powell switch (Attr.Kind) { 5075b5ab80eSSam Powell case AD_Diff_Scalar_Str: 5085b5ab80eSSam Powell if (IndentCounter == 0) 5095b5ab80eSSam Powell printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(Indent, 5105b5ab80eSSam Powell Attr, OS); 5115b5ab80eSSam Powell break; 5125b5ab80eSSam Powell case AD_Diff_Scalar_PackedVersion: 5135b5ab80eSSam Powell printSingleVal< 5145b5ab80eSSam Powell DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>>(Indent, 5155b5ab80eSSam Powell Attr, OS); 5165b5ab80eSSam Powell break; 5175b5ab80eSSam Powell case AD_Diff_Scalar_Unsigned: 5185b5ab80eSSam Powell printSingleVal<DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>>(Indent, 5195b5ab80eSSam Powell Attr, OS); 5205b5ab80eSSam Powell break; 5215b5ab80eSSam Powell case AD_Diff_Scalar_Bool: 5225b5ab80eSSam Powell printSingleVal<DiffScalarVal<bool, AD_Diff_Scalar_Bool>>(Indent, Attr, 5235b5ab80eSSam Powell OS); 5245b5ab80eSSam Powell break; 5255b5ab80eSSam Powell case AD_Str_Vec: 5265b5ab80eSSam Powell printVecVal<DiffStrVec>(Indent, Attr, OS); 5275b5ab80eSSam Powell break; 5285b5ab80eSSam Powell case AD_Sym_Vec: 5295b5ab80eSSam Powell printVecVal<DiffSymVec>(Indent, Attr, OS); 5305b5ab80eSSam Powell break; 5315b5ab80eSSam Powell case AD_Inline_Doc: 5325b5ab80eSSam Powell if (!Attr.Values.empty()) { 5335b5ab80eSSam Powell OS << Indent << Attr.Name << "\n"; 5345b5ab80eSSam Powell for (auto &Item : Attr.Values) 5355b5ab80eSSam Powell if (InlineDoc *Doc = dyn_cast<InlineDoc>(Item.get())) 5365b5ab80eSSam Powell if (!Doc->DocValues.empty()) { 5375b5ab80eSSam Powell OS << Indent << "\t" << Doc->InstallName << "\n"; 5385b5ab80eSSam Powell printDifferences(OS, std::move(Doc->DocValues), 2); 5395b5ab80eSSam Powell } 5405b5ab80eSSam Powell } 5415b5ab80eSSam Powell break; 5425b5ab80eSSam Powell } 5435b5ab80eSSam Powell } 5445b5ab80eSSam Powell } 5455b5ab80eSSam Powell 5465b5ab80eSSam Powell bool DiffEngine::compareFiles(raw_ostream &OS) { 5475b5ab80eSSam Powell const auto *IFLHS = &(FileLHS->getInterfaceFile()); 5485b5ab80eSSam Powell const auto *IFRHS = &(FileRHS->getInterfaceFile()); 5495b5ab80eSSam Powell if (*IFLHS == *IFRHS) 5505b5ab80eSSam Powell return false; 5515b5ab80eSSam Powell OS << "< " << std::string(IFLHS->getPath().data()) << "\n> " 5525b5ab80eSSam Powell << std::string(IFRHS->getPath().data()) << "\n\n"; 5535b5ab80eSSam Powell std::vector<DiffOutput> Diffs = findDifferences(IFLHS, IFRHS); 5545b5ab80eSSam Powell printDifferences(OS, Diffs, 0); 5555b5ab80eSSam Powell return true; 5565b5ab80eSSam Powell } 557