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