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