aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-tapi-diff/DiffEngine.cpp')
-rw-r--r--llvm/tools/llvm-tapi-diff/DiffEngine.cpp556
1 files changed, 556 insertions, 0 deletions
diff --git a/llvm/tools/llvm-tapi-diff/DiffEngine.cpp b/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
new file mode 100644
index 000000000000..ff60d52f5c65
--- /dev/null
+++ b/llvm/tools/llvm-tapi-diff/DiffEngine.cpp
@@ -0,0 +1,556 @@
+//===-- DiffEngine.cpp - Structural file comparison -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the implementation of the llvm-tapi difference
+// engine, which structurally compares two tbd files.
+//
+//===----------------------------------------------------------------------===/
+#include "DiffEngine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TextAPI/InterfaceFile.h"
+#include "llvm/TextAPI/Symbol.h"
+#include "llvm/TextAPI/Target.h"
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+StringRef setOrderIndicator(InterfaceInputOrder Order) {
+ return ((Order == lhs) ? "< " : "> ");
+}
+
+// The following template specialization implementations
+// need to be explicitly placed into the llvm namespace
+// to work around a GCC 4.8 bug.
+namespace llvm {
+
+template <typename T, DiffAttrKind U>
+inline void DiffScalarVal<T, U>::print(raw_ostream &OS, std::string Indent) {
+ OS << Indent << "\t" << setOrderIndicator(Order) << Val << "\n";
+}
+
+template <>
+inline void
+DiffScalarVal<StringRef, AD_Diff_Scalar_Str>::print(raw_ostream &OS,
+ std::string Indent) {
+ OS << Indent << "\t\t" << setOrderIndicator(Order) << Val << "\n";
+}
+
+template <>
+inline void
+DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>::print(raw_ostream &OS,
+ std::string Indent) {
+ OS << Indent << "\t" << setOrderIndicator(Order) << std::to_string(Val)
+ << "\n";
+}
+
+template <>
+inline void
+DiffScalarVal<bool, AD_Diff_Scalar_Bool>::print(raw_ostream &OS,
+ std::string Indent) {
+ OS << Indent << "\t" << setOrderIndicator(Order)
+ << ((Val == true) ? "true" : "false") << "\n";
+}
+
+} // end namespace llvm
+
+StringLiteral SymScalar::getSymbolNamePrefix(MachO::SymbolKind Kind) {
+ switch (Kind) {
+ case MachO::SymbolKind::GlobalSymbol:
+ return StringLiteral("");
+ case MachO::SymbolKind::ObjectiveCClass:
+ return ObjC2MetaClassNamePrefix;
+ case MachO::SymbolKind ::ObjectiveCClassEHType:
+ return ObjC2EHTypePrefix;
+ case MachO::SymbolKind ::ObjectiveCInstanceVariable:
+ return ObjC2IVarPrefix;
+ }
+ llvm_unreachable("Unknown llvm::MachO::SymbolKind enum");
+}
+
+std::string SymScalar::stringifySymbolFlag(MachO::SymbolFlags Flag) {
+ switch (Flag) {
+ case MachO::SymbolFlags::None:
+ return "";
+ case MachO::SymbolFlags::ThreadLocalValue:
+ return "Thread-Local";
+ case MachO::SymbolFlags::WeakDefined:
+ return "Weak-Defined";
+ case MachO::SymbolFlags::WeakReferenced:
+ return "Weak-Referenced";
+ case MachO::SymbolFlags::Undefined:
+ return "Undefined";
+ case MachO::SymbolFlags::Rexported:
+ return "Reexported";
+ }
+ llvm_unreachable("Unknown llvm::MachO::SymbolFlags enum");
+}
+
+void SymScalar::print(raw_ostream &OS, std::string Indent, MachO::Target Targ) {
+ if (Val->getKind() == MachO::SymbolKind::ObjectiveCClass) {
+ if (Targ.Arch == MachO::AK_i386 &&
+ Targ.Platform == MachO::PlatformKind::macOS) {
+ OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
+ << ObjC1ClassNamePrefix << Val->getName()
+ << getFlagString(Val->getFlags()) << "\n";
+ return;
+ }
+ OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
+ << ObjC2ClassNamePrefix << Val->getName()
+ << getFlagString(Val->getFlags()) << "\n";
+ }
+ OS << Indent << "\t\t" << ((Order == lhs) ? "< " : "> ")
+ << getSymbolNamePrefix(Val->getKind()) << Val->getName()
+ << getFlagString(Val->getFlags()) << "\n";
+}
+
+bool checkSymbolEquality(llvm::MachO::InterfaceFile::const_symbol_range LHS,
+ llvm::MachO::InterfaceFile::const_symbol_range RHS) {
+ return std::equal(LHS.begin(), LHS.end(), RHS.begin(),
+ [&](auto LHS, auto RHS) { return *LHS == *RHS; });
+}
+
+template <typename TargetVecT, typename ValTypeT, typename V>
+void addDiffForTargSlice(V Val, Target Targ, DiffOutput &Diff,
+ InterfaceInputOrder Order) {
+ auto TargetVector = llvm::find_if(
+ Diff.Values, [&](const std::unique_ptr<AttributeDiff> &RawTVec) {
+ if (TargetVecT *TVec = dyn_cast<TargetVecT>(RawTVec.get()))
+ return TVec->Targ == Targ;
+ return false;
+ });
+ if (TargetVector != Diff.Values.end()) {
+ ValTypeT NewVal(Order, Val);
+ cast<TargetVecT>(TargetVector->get())->TargValues.push_back(NewVal);
+ } else {
+ auto NewTargetVec = std::make_unique<TargetVecT>(Targ);
+ ValTypeT NewVal(Order, Val);
+ NewTargetVec->TargValues.push_back(NewVal);
+ Diff.Values.push_back(std::move(NewTargetVec));
+ }
+}
+
+DiffOutput getSingleAttrDiff(const std::vector<InterfaceFileRef> &IRefVec,
+ std::string Name, InterfaceInputOrder Order) {
+ DiffOutput Diff(Name);
+ Diff.Kind = AD_Str_Vec;
+ for (const auto &IRef : IRefVec)
+ for (auto Targ : IRef.targets())
+ addDiffForTargSlice<DiffStrVec,
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
+ IRef.getInstallName(), Targ, Diff, Order);
+ return Diff;
+}
+
+DiffOutput
+getSingleAttrDiff(const std::vector<std::pair<Target, std::string>> &PairVec,
+ std::string Name, InterfaceInputOrder Order) {
+ DiffOutput Diff(Name);
+ Diff.Kind = AD_Str_Vec;
+ for (const auto &Pair : PairVec)
+ addDiffForTargSlice<DiffStrVec,
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
+ StringRef(Pair.second), Pair.first, Diff, Order);
+ return Diff;
+}
+
+DiffOutput getSingleAttrDiff(InterfaceFile::const_symbol_range SymRange,
+ std::string Name, InterfaceInputOrder Order) {
+ DiffOutput Diff(Name);
+ Diff.Kind = AD_Sym_Vec;
+ for (const auto *Sym : SymRange)
+ for (auto Targ : Sym->targets())
+ addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Diff, Order);
+ return Diff;
+}
+
+template <typename T>
+DiffOutput getSingleAttrDiff(T SingleAttr, std::string Attribute) {
+ DiffOutput Diff(Attribute);
+ Diff.Kind = SingleAttr.getKind();
+ Diff.Values.push_back(std::make_unique<T>(SingleAttr));
+ return Diff;
+}
+
+template <typename T, DiffAttrKind U>
+void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
+ DiffScalarVal<T, U> Attr) {
+ Output.push_back(getSingleAttrDiff(Attr, Name));
+}
+
+template <typename T>
+void diffAttribute(std::string Name, std::vector<DiffOutput> &Output,
+ const T &Val, InterfaceInputOrder Order) {
+ Output.push_back(getSingleAttrDiff(Val, Name, Order));
+}
+
+std::vector<DiffOutput> getSingleIF(InterfaceFile *Interface,
+ InterfaceInputOrder Order) {
+ std::vector<DiffOutput> Output;
+ diffAttribute("Install Name", Output,
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(
+ Order, Interface->getInstallName()));
+ diffAttribute("Current Version", Output,
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ Order, Interface->getCurrentVersion()));
+ diffAttribute("Compatibility Version", Output,
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ Order, Interface->getCompatibilityVersion()));
+ diffAttribute("Swift ABI Version", Output,
+ DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
+ Order, Interface->getSwiftABIVersion()));
+ diffAttribute("InstallAPI", Output,
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ Order, Interface->isInstallAPI()));
+ diffAttribute("Two Level Namespace", Output,
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ Order, Interface->isTwoLevelNamespace()));
+ diffAttribute("Application Extension Safe", Output,
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ Order, Interface->isApplicationExtensionSafe()));
+ diffAttribute("Reexported Libraries", Output,
+ Interface->reexportedLibraries(), Order);
+ diffAttribute("Allowable Clients", Output, Interface->allowableClients(),
+ Order);
+ diffAttribute("Parent Umbrellas", Output, Interface->umbrellas(), Order);
+ diffAttribute("Symbols", Output, Interface->symbols(), Order);
+ for (auto Doc : Interface->documents()) {
+ DiffOutput Documents("Inlined Reexported Frameworks/Libraries");
+ Documents.Kind = AD_Inline_Doc;
+ Documents.Values.push_back(std::make_unique<InlineDoc>(
+ InlineDoc(Doc->getInstallName(), getSingleIF(Doc.get(), Order))));
+ Output.push_back(std::move(Documents));
+ }
+ return Output;
+}
+
+void findAndAddDiff(const std::vector<InterfaceFileRef> &CollectedIRefVec,
+ const std::vector<InterfaceFileRef> &LookupIRefVec,
+ DiffOutput &Result, InterfaceInputOrder Order) {
+ Result.Kind = AD_Str_Vec;
+ for (const auto &IRef : CollectedIRefVec)
+ for (auto Targ : IRef.targets()) {
+ auto FoundIRef = llvm::find_if(LookupIRefVec, [&](const auto LIRef) {
+ auto FoundTarg = llvm::find(LIRef.targets(), Targ);
+ return (FoundTarg != LIRef.targets().end() &&
+ IRef.getInstallName() == LIRef.getInstallName());
+ });
+ if (FoundIRef == LookupIRefVec.end())
+ addDiffForTargSlice<DiffStrVec,
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
+ IRef.getInstallName(), Targ, Result, Order);
+ }
+}
+
+void findAndAddDiff(
+ const std::vector<std::pair<Target, std::string>> &CollectedPairs,
+ const std::vector<std::pair<Target, std::string>> &LookupPairs,
+ DiffOutput &Result, InterfaceInputOrder Order) {
+ Result.Kind = AD_Str_Vec;
+ for (const auto &Pair : CollectedPairs) {
+ auto FoundPair = llvm::find(LookupPairs, Pair);
+ if (FoundPair == LookupPairs.end())
+ addDiffForTargSlice<DiffStrVec,
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
+ StringRef(Pair.second), Pair.first, Result, Order);
+ }
+}
+
+void findAndAddDiff(InterfaceFile::const_symbol_range CollectedSyms,
+ InterfaceFile::const_symbol_range LookupSyms,
+ DiffOutput &Result, InterfaceInputOrder Order) {
+ Result.Kind = AD_Sym_Vec;
+ for (const auto *Sym : CollectedSyms)
+ for (const auto Targ : Sym->targets()) {
+ auto FoundSym = llvm::find_if(LookupSyms, [&](const auto LSym) {
+ auto FoundTarg = llvm::find(LSym->targets(), Targ);
+ return (Sym->getName() == LSym->getName() &&
+ Sym->getKind() == LSym->getKind() &&
+ Sym->getFlags() == LSym->getFlags() &&
+ FoundTarg != LSym->targets().end());
+ });
+ if (FoundSym == LookupSyms.end())
+ addDiffForTargSlice<DiffSymVec, SymScalar>(Sym, Targ, Result, Order);
+ }
+}
+
+template <typename T>
+DiffOutput recordDifferences(T LHS, T RHS, std::string Attr) {
+ DiffOutput Diff(Attr);
+ if (LHS.getKind() == RHS.getKind()) {
+ Diff.Kind = LHS.getKind();
+ Diff.Values.push_back(std::make_unique<T>(LHS));
+ Diff.Values.push_back(std::make_unique<T>(RHS));
+ }
+ return Diff;
+}
+
+template <typename T>
+DiffOutput recordDifferences(const std::vector<T> &LHS,
+ const std::vector<T> &RHS, std::string Attr) {
+ DiffOutput Diff(Attr);
+ Diff.Kind = AD_Str_Vec;
+ findAndAddDiff(LHS, RHS, Diff, lhs);
+ findAndAddDiff(RHS, LHS, Diff, rhs);
+ return Diff;
+}
+
+DiffOutput recordDifferences(llvm::MachO::InterfaceFile::const_symbol_range LHS,
+ llvm::MachO::InterfaceFile::const_symbol_range RHS,
+ std::string Attr) {
+ DiffOutput Diff(Attr);
+ Diff.Kind = AD_Sym_Vec;
+ findAndAddDiff(LHS, RHS, Diff, lhs);
+ findAndAddDiff(RHS, LHS, Diff, rhs);
+ return Diff;
+}
+
+std::vector<DiffOutput>
+DiffEngine::findDifferences(const InterfaceFile *IFLHS,
+ const InterfaceFile *IFRHS) {
+ std::vector<DiffOutput> Output;
+ if (IFLHS->getInstallName() != IFRHS->getInstallName())
+ Output.push_back(recordDifferences(
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(lhs,
+ IFLHS->getInstallName()),
+ DiffScalarVal<StringRef, AD_Diff_Scalar_Str>(rhs,
+ IFRHS->getInstallName()),
+ "Install Name"));
+
+ if (IFLHS->getCurrentVersion() != IFRHS->getCurrentVersion())
+ Output.push_back(recordDifferences(
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ lhs, IFLHS->getCurrentVersion()),
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ rhs, IFRHS->getCurrentVersion()),
+ "Current Version"));
+ if (IFLHS->getCompatibilityVersion() != IFRHS->getCompatibilityVersion())
+ Output.push_back(recordDifferences(
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ lhs, IFLHS->getCompatibilityVersion()),
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>(
+ rhs, IFRHS->getCompatibilityVersion()),
+ "Compatibility Version"));
+ if (IFLHS->getSwiftABIVersion() != IFRHS->getSwiftABIVersion())
+ Output.push_back(
+ recordDifferences(DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
+ lhs, IFLHS->getSwiftABIVersion()),
+ DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>(
+ rhs, IFRHS->getSwiftABIVersion()),
+ "Swift ABI Version"));
+ if (IFLHS->isInstallAPI() != IFRHS->isInstallAPI())
+ Output.push_back(recordDifferences(
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(lhs, IFLHS->isInstallAPI()),
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(rhs, IFRHS->isInstallAPI()),
+ "InstallAPI"));
+
+ if (IFLHS->isTwoLevelNamespace() != IFRHS->isTwoLevelNamespace())
+ Output.push_back(recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ lhs, IFLHS->isTwoLevelNamespace()),
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ rhs, IFRHS->isTwoLevelNamespace()),
+ "Two Level Namespace"));
+
+ if (IFLHS->isApplicationExtensionSafe() !=
+ IFRHS->isApplicationExtensionSafe())
+ Output.push_back(
+ recordDifferences(DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ lhs, IFLHS->isApplicationExtensionSafe()),
+ DiffScalarVal<bool, AD_Diff_Scalar_Bool>(
+ rhs, IFRHS->isApplicationExtensionSafe()),
+ "Application Extension Safe"));
+
+ if (IFLHS->reexportedLibraries() != IFRHS->reexportedLibraries())
+ Output.push_back(recordDifferences(IFLHS->reexportedLibraries(),
+ IFRHS->reexportedLibraries(),
+ "Reexported Libraries"));
+
+ if (IFLHS->allowableClients() != IFRHS->allowableClients())
+ Output.push_back(recordDifferences(IFLHS->allowableClients(),
+ IFRHS->allowableClients(),
+ "Allowable Clients"));
+
+ if (IFLHS->umbrellas() != IFRHS->umbrellas())
+ Output.push_back(recordDifferences(IFLHS->umbrellas(), IFRHS->umbrellas(),
+ "Parent Umbrellas"));
+
+ if (!checkSymbolEquality(IFLHS->symbols(), IFRHS->symbols()))
+ Output.push_back(
+ recordDifferences(IFLHS->symbols(), IFRHS->symbols(), "Symbols"));
+
+ if (IFLHS->documents() != IFRHS->documents()) {
+ DiffOutput Docs("Inlined Reexported Frameworks/Libraries");
+ Docs.Kind = AD_Inline_Doc;
+ std::vector<StringRef> DocsInserted;
+ // Iterate through inline frameworks/libraries from interface file and find
+ // match based on install name.
+ for (auto DocLHS : IFLHS->documents()) {
+ auto Pair = llvm::find_if(IFRHS->documents(), [&](const auto &DocRHS) {
+ return (DocLHS->getInstallName() == DocRHS->getInstallName());
+ });
+ // If a match found, recursively get differences between the pair.
+ if (Pair != IFRHS->documents().end()) {
+ InlineDoc PairDiff =
+ InlineDoc(DocLHS->getInstallName(),
+ findDifferences(DocLHS.get(), Pair->get()));
+ if (!PairDiff.DocValues.empty())
+ Docs.Values.push_back(
+ std::make_unique<InlineDoc>(std::move(PairDiff)));
+ }
+ // If a match is not found, get attributes from single item.
+ else
+ Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
+ DocLHS->getInstallName(), getSingleIF(DocLHS.get(), lhs))));
+ DocsInserted.push_back(DocLHS->getInstallName());
+ }
+ for (auto DocRHS : IFRHS->documents()) {
+ auto WasGathered =
+ llvm::find_if(DocsInserted, [&](const auto &GatheredDoc) {
+ return (GatheredDoc == DocRHS->getInstallName());
+ });
+ if (WasGathered == DocsInserted.end())
+ Docs.Values.push_back(std::make_unique<InlineDoc>(InlineDoc(
+ DocRHS->getInstallName(), getSingleIF(DocRHS.get(), rhs))));
+ }
+ if (!Docs.Values.empty())
+ Output.push_back(std::move(Docs));
+ }
+ return Output;
+}
+
+template <typename T>
+void printSingleVal(std::string Indent, const DiffOutput &Attr,
+ raw_ostream &OS) {
+ if (Attr.Values.empty())
+ return;
+ OS << Indent << Attr.Name << "\n";
+ for (auto &RawItem : Attr.Values)
+ if (T *Item = dyn_cast<T>(RawItem.get()))
+ Item->print(OS, Indent);
+}
+
+template <typename T>
+T *castValues(const std::unique_ptr<AttributeDiff> &RawAttr) {
+ T *CastAttr = cast<T>(RawAttr.get());
+ return CastAttr;
+}
+
+template <typename T> void sortTargetValues(std::vector<T> &TargValues) {
+ llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
+ return ValA.getOrder() < ValB.getOrder();
+ });
+ llvm::stable_sort(TargValues, [](const auto &ValA, const auto &ValB) {
+ return ValA.getOrder() == ValB.getOrder() && ValA.getVal() < ValB.getVal();
+ });
+}
+
+template <typename T>
+void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) {
+ if (Attr.Values.empty())
+ return;
+
+ OS << Indent << Attr.Name << "\n";
+
+ std::vector<T *> SortedAttrs;
+
+ llvm::transform(Attr.Values, std::back_inserter(SortedAttrs), castValues<T>);
+
+ llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
+ return ValA->Targ < ValB->Targ;
+ });
+
+ for (auto *Vec : SortedAttrs) {
+ sortTargetValues<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(
+ Vec->TargValues);
+ OS << Indent << "\t" << getTargetTripleName(Vec->Targ) << "\n";
+ for (auto &Item : Vec->TargValues)
+ Item.print(OS, Indent);
+ }
+}
+
+template <>
+void printVecVal<DiffSymVec>(std::string Indent, const DiffOutput &Attr,
+ raw_ostream &OS) {
+ if (Attr.Values.empty())
+ return;
+
+ OS << Indent << Attr.Name << "\n";
+
+ std::vector<DiffSymVec *> SortedAttrs;
+
+ llvm::transform(Attr.Values, std::back_inserter(SortedAttrs),
+ castValues<DiffSymVec>);
+
+ llvm::sort(SortedAttrs, [&](const auto &ValA, const auto &ValB) {
+ return ValA->Targ < ValB->Targ;
+ });
+ for (auto *SymVec : SortedAttrs) {
+ sortTargetValues<SymScalar>(SymVec->TargValues);
+ OS << Indent << "\t" << getTargetTripleName(SymVec->Targ) << "\n";
+ for (auto &Item : SymVec->TargValues)
+ Item.print(OS, Indent, SymVec->Targ);
+ }
+}
+
+void DiffEngine::printDifferences(raw_ostream &OS,
+ const std::vector<DiffOutput> &Diffs,
+ int IndentCounter) {
+ std::string Indent = std::string(IndentCounter, '\t');
+ for (auto &Attr : Diffs) {
+ switch (Attr.Kind) {
+ case AD_Diff_Scalar_Str:
+ if (IndentCounter == 0)
+ printSingleVal<DiffScalarVal<StringRef, AD_Diff_Scalar_Str>>(Indent,
+ Attr, OS);
+ break;
+ case AD_Diff_Scalar_PackedVersion:
+ printSingleVal<
+ DiffScalarVal<PackedVersion, AD_Diff_Scalar_PackedVersion>>(Indent,
+ Attr, OS);
+ break;
+ case AD_Diff_Scalar_Unsigned:
+ printSingleVal<DiffScalarVal<uint8_t, AD_Diff_Scalar_Unsigned>>(Indent,
+ Attr, OS);
+ break;
+ case AD_Diff_Scalar_Bool:
+ printSingleVal<DiffScalarVal<bool, AD_Diff_Scalar_Bool>>(Indent, Attr,
+ OS);
+ break;
+ case AD_Str_Vec:
+ printVecVal<DiffStrVec>(Indent, Attr, OS);
+ break;
+ case AD_Sym_Vec:
+ printVecVal<DiffSymVec>(Indent, Attr, OS);
+ break;
+ case AD_Inline_Doc:
+ if (!Attr.Values.empty()) {
+ OS << Indent << Attr.Name << "\n";
+ for (auto &Item : Attr.Values)
+ if (InlineDoc *Doc = dyn_cast<InlineDoc>(Item.get()))
+ if (!Doc->DocValues.empty()) {
+ OS << Indent << "\t" << Doc->InstallName << "\n";
+ printDifferences(OS, std::move(Doc->DocValues), 2);
+ }
+ }
+ break;
+ }
+ }
+}
+
+bool DiffEngine::compareFiles(raw_ostream &OS) {
+ const auto *IFLHS = &(FileLHS->getInterfaceFile());
+ const auto *IFRHS = &(FileRHS->getInterfaceFile());
+ if (*IFLHS == *IFRHS)
+ return false;
+ OS << "< " << std::string(IFLHS->getPath().data()) << "\n> "
+ << std::string(IFRHS->getPath().data()) << "\n\n";
+ std::vector<DiffOutput> Diffs = findDifferences(IFLHS, IFRHS);
+ printDifferences(OS, Diffs, 0);
+ return true;
+}