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