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