xref: /llvm-project/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp (revision f01d45cf97714a8751f1712b158c34bb28ce0ce3)
1e98a4c5aSCarlos Alberto Enciso //===-- LVCompare.cpp -----------------------------------------------------===//
2e98a4c5aSCarlos Alberto Enciso //
3e98a4c5aSCarlos Alberto Enciso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e98a4c5aSCarlos Alberto Enciso // See https://llvm.org/LICENSE.txt for license information.
5e98a4c5aSCarlos Alberto Enciso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e98a4c5aSCarlos Alberto Enciso //
7e98a4c5aSCarlos Alberto Enciso //===----------------------------------------------------------------------===//
8e98a4c5aSCarlos Alberto Enciso //
9e98a4c5aSCarlos Alberto Enciso // This implements the LVCompare class.
10e98a4c5aSCarlos Alberto Enciso //
11e98a4c5aSCarlos Alberto Enciso //===----------------------------------------------------------------------===//
12e98a4c5aSCarlos Alberto Enciso 
13e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
14e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
15e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
16e98a4c5aSCarlos Alberto Enciso #include <tuple>
17e98a4c5aSCarlos Alberto Enciso 
18e98a4c5aSCarlos Alberto Enciso using namespace llvm;
19e98a4c5aSCarlos Alberto Enciso using namespace llvm::logicalview;
20e98a4c5aSCarlos Alberto Enciso 
21e98a4c5aSCarlos Alberto Enciso #define DEBUG_TYPE "Compare"
22e98a4c5aSCarlos Alberto Enciso 
23e98a4c5aSCarlos Alberto Enciso namespace {
24e98a4c5aSCarlos Alberto Enciso 
25e98a4c5aSCarlos Alberto Enciso enum class LVCompareItem { Scope, Symbol, Type, Line, Total };
26e98a4c5aSCarlos Alberto Enciso enum class LVCompareIndex { Header, Expected, Missing, Added };
27e98a4c5aSCarlos Alberto Enciso using LVCompareEntry = std::tuple<const char *, unsigned, unsigned, unsigned>;
28e98a4c5aSCarlos Alberto Enciso using LVCompareInfo = std::map<LVCompareItem, LVCompareEntry>;
29e98a4c5aSCarlos Alberto Enciso LVCompareInfo Results = {
30e98a4c5aSCarlos Alberto Enciso     {LVCompareItem::Line, LVCompareEntry("Lines", 0, 0, 0)},
31e98a4c5aSCarlos Alberto Enciso     {LVCompareItem::Scope, LVCompareEntry("Scopes", 0, 0, 0)},
32e98a4c5aSCarlos Alberto Enciso     {LVCompareItem::Symbol, LVCompareEntry("Symbols", 0, 0, 0)},
33e98a4c5aSCarlos Alberto Enciso     {LVCompareItem::Type, LVCompareEntry("Types", 0, 0, 0)},
34e98a4c5aSCarlos Alberto Enciso     {LVCompareItem::Total, LVCompareEntry("Total", 0, 0, 0)}};
35e98a4c5aSCarlos Alberto Enciso static LVCompareInfo::iterator IterTotal = Results.end();
36e98a4c5aSCarlos Alberto Enciso 
37e98a4c5aSCarlos Alberto Enciso constexpr unsigned getHeader() {
38e98a4c5aSCarlos Alberto Enciso   return static_cast<unsigned>(LVCompareIndex::Header);
39e98a4c5aSCarlos Alberto Enciso }
40e98a4c5aSCarlos Alberto Enciso constexpr unsigned getExpected() {
41e98a4c5aSCarlos Alberto Enciso   return static_cast<unsigned>(LVCompareIndex::Expected);
42e98a4c5aSCarlos Alberto Enciso }
43e98a4c5aSCarlos Alberto Enciso constexpr unsigned getMissing() {
44e98a4c5aSCarlos Alberto Enciso   return static_cast<unsigned>(LVCompareIndex::Missing);
45e98a4c5aSCarlos Alberto Enciso }
46e98a4c5aSCarlos Alberto Enciso constexpr unsigned getAdded() {
47e98a4c5aSCarlos Alberto Enciso   return static_cast<unsigned>(LVCompareIndex::Added);
48e98a4c5aSCarlos Alberto Enciso }
49e98a4c5aSCarlos Alberto Enciso 
50e98a4c5aSCarlos Alberto Enciso LVCompare *CurrentComparator = nullptr;
51e98a4c5aSCarlos Alberto Enciso 
52e98a4c5aSCarlos Alberto Enciso void zeroResults() {
53e98a4c5aSCarlos Alberto Enciso   // In case the same reader instance is used.
54e98a4c5aSCarlos Alberto Enciso   for (LVCompareInfo::reference Entry : Results) {
55e98a4c5aSCarlos Alberto Enciso     std::get<getExpected()>(Entry.second) = 0;
56e98a4c5aSCarlos Alberto Enciso     std::get<getMissing()>(Entry.second) = 0;
57e98a4c5aSCarlos Alberto Enciso     std::get<getAdded()>(Entry.second) = 0;
58e98a4c5aSCarlos Alberto Enciso   }
59e98a4c5aSCarlos Alberto Enciso   IterTotal = Results.find(LVCompareItem::Total);
60e98a4c5aSCarlos Alberto Enciso   assert(IterTotal != Results.end());
61e98a4c5aSCarlos Alberto Enciso }
62e98a4c5aSCarlos Alberto Enciso 
63e98a4c5aSCarlos Alberto Enciso LVCompareInfo::iterator getResultsEntry(LVElement *Element) {
64e98a4c5aSCarlos Alberto Enciso   LVCompareItem Kind;
65e98a4c5aSCarlos Alberto Enciso   if (Element->getIsLine())
66e98a4c5aSCarlos Alberto Enciso     Kind = LVCompareItem::Line;
67e98a4c5aSCarlos Alberto Enciso   else if (Element->getIsScope())
68e98a4c5aSCarlos Alberto Enciso     Kind = LVCompareItem::Scope;
69e98a4c5aSCarlos Alberto Enciso   else if (Element->getIsSymbol())
70e98a4c5aSCarlos Alberto Enciso     Kind = LVCompareItem::Symbol;
71e98a4c5aSCarlos Alberto Enciso   else
72e98a4c5aSCarlos Alberto Enciso     Kind = LVCompareItem::Type;
73e98a4c5aSCarlos Alberto Enciso 
74e98a4c5aSCarlos Alberto Enciso   // Used to update the expected, missing or added entry for the given kind.
75e98a4c5aSCarlos Alberto Enciso   LVCompareInfo::iterator Iter = Results.find(Kind);
76e98a4c5aSCarlos Alberto Enciso   assert(Iter != Results.end());
77e98a4c5aSCarlos Alberto Enciso   return Iter;
78e98a4c5aSCarlos Alberto Enciso }
79e98a4c5aSCarlos Alberto Enciso 
80e98a4c5aSCarlos Alberto Enciso void updateExpected(LVElement *Element) {
81e98a4c5aSCarlos Alberto Enciso   LVCompareInfo::iterator Iter = getResultsEntry(Element);
82e98a4c5aSCarlos Alberto Enciso   // Update total for expected.
83e98a4c5aSCarlos Alberto Enciso   ++std::get<getExpected()>(IterTotal->second);
84e98a4c5aSCarlos Alberto Enciso   // Update total for specific element kind.
85e98a4c5aSCarlos Alberto Enciso   ++std::get<getExpected()>(Iter->second);
86e98a4c5aSCarlos Alberto Enciso }
87e98a4c5aSCarlos Alberto Enciso 
88e98a4c5aSCarlos Alberto Enciso void updateMissingOrAdded(LVElement *Element, LVComparePass Pass) {
89e98a4c5aSCarlos Alberto Enciso   LVCompareInfo::iterator Iter = getResultsEntry(Element);
90e98a4c5aSCarlos Alberto Enciso   if (Pass == LVComparePass::Missing) {
91e98a4c5aSCarlos Alberto Enciso     ++std::get<getMissing()>(IterTotal->second);
92e98a4c5aSCarlos Alberto Enciso     ++std::get<getMissing()>(Iter->second);
93e98a4c5aSCarlos Alberto Enciso   } else {
94e98a4c5aSCarlos Alberto Enciso     ++std::get<getAdded()>(IterTotal->second);
95e98a4c5aSCarlos Alberto Enciso     ++std::get<getAdded()>(Iter->second);
96e98a4c5aSCarlos Alberto Enciso   }
97e98a4c5aSCarlos Alberto Enciso }
98e98a4c5aSCarlos Alberto Enciso 
99e98a4c5aSCarlos Alberto Enciso } // namespace
100e98a4c5aSCarlos Alberto Enciso 
101e98a4c5aSCarlos Alberto Enciso LVCompare &LVCompare::getInstance() {
102e98a4c5aSCarlos Alberto Enciso   static LVCompare DefaultComparator(outs());
103e98a4c5aSCarlos Alberto Enciso   return CurrentComparator ? *CurrentComparator : DefaultComparator;
104e98a4c5aSCarlos Alberto Enciso }
105e98a4c5aSCarlos Alberto Enciso 
106e98a4c5aSCarlos Alberto Enciso void LVCompare::setInstance(LVCompare *Comparator) {
107e98a4c5aSCarlos Alberto Enciso   CurrentComparator = Comparator;
108e98a4c5aSCarlos Alberto Enciso }
109e98a4c5aSCarlos Alberto Enciso 
110e98a4c5aSCarlos Alberto Enciso LVCompare::LVCompare(raw_ostream &OS) : OS(OS) {
111e98a4c5aSCarlos Alberto Enciso   PrintLines = options().getPrintLines();
112e98a4c5aSCarlos Alberto Enciso   PrintSymbols = options().getPrintSymbols();
113e98a4c5aSCarlos Alberto Enciso   PrintTypes = options().getPrintTypes();
114e98a4c5aSCarlos Alberto Enciso   PrintScopes =
115e98a4c5aSCarlos Alberto Enciso       options().getPrintScopes() || PrintLines || PrintSymbols || PrintTypes;
116e98a4c5aSCarlos Alberto Enciso }
117e98a4c5aSCarlos Alberto Enciso 
118e98a4c5aSCarlos Alberto Enciso Error LVCompare::execute(LVReader *ReferenceReader, LVReader *TargetReader) {
119e98a4c5aSCarlos Alberto Enciso   setInstance(this);
120e98a4c5aSCarlos Alberto Enciso   // In the case of added elements, the 'Reference' reader will be modified;
121e98a4c5aSCarlos Alberto Enciso   // those elements will be added to it. Update the current reader instance.
122e98a4c5aSCarlos Alberto Enciso   LVReader::setInstance(ReferenceReader);
123e98a4c5aSCarlos Alberto Enciso 
124e98a4c5aSCarlos Alberto Enciso   auto PrintHeader = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) {
125e98a4c5aSCarlos Alberto Enciso     LLVM_DEBUG({
126e98a4c5aSCarlos Alberto Enciso       dbgs() << "[Reference] " << LHS->getName() << "\n"
127e98a4c5aSCarlos Alberto Enciso              << "[Target] " << RHS->getName() << "\n";
128e98a4c5aSCarlos Alberto Enciso     });
129e98a4c5aSCarlos Alberto Enciso     OS << "\nReference: " << formattedName(LHS->getName()) << "\n"
130e98a4c5aSCarlos Alberto Enciso        << "Target:    " << formattedName(RHS->getName()) << "\n";
131e98a4c5aSCarlos Alberto Enciso   };
132e98a4c5aSCarlos Alberto Enciso 
133e98a4c5aSCarlos Alberto Enciso   // We traverse the given scopes tree ('Reference' and 'Target') twice.
134e98a4c5aSCarlos Alberto Enciso   // The first time we look for missing items from the 'Reference' and the
135e98a4c5aSCarlos Alberto Enciso   // second time we look for items added to the 'Target'.
136e98a4c5aSCarlos Alberto Enciso   // The comparison test includes the name, lexical level, type, source
137e98a4c5aSCarlos Alberto Enciso   // location, etc.
138e98a4c5aSCarlos Alberto Enciso   LVScopeRoot *ReferenceRoot = ReferenceReader->getScopesRoot();
139e98a4c5aSCarlos Alberto Enciso   LVScopeRoot *TargetRoot = TargetReader->getScopesRoot();
140e98a4c5aSCarlos Alberto Enciso   ReferenceRoot->setIsInCompare();
141e98a4c5aSCarlos Alberto Enciso   TargetRoot->setIsInCompare();
142e98a4c5aSCarlos Alberto Enciso 
143e98a4c5aSCarlos Alberto Enciso   // Reset possible previous results.
144e98a4c5aSCarlos Alberto Enciso   zeroResults();
145e98a4c5aSCarlos Alberto Enciso 
146e98a4c5aSCarlos Alberto Enciso   if (options().getCompareContext()) {
147e98a4c5aSCarlos Alberto Enciso     // Perform a logical view comparison as a whole unit. We start at the
148e98a4c5aSCarlos Alberto Enciso     // root reference; at each scope an equal test is applied to its children.
149e98a4c5aSCarlos Alberto Enciso     // If a difference is found, the current path is marked as missing.
150e98a4c5aSCarlos Alberto Enciso     auto CompareViews = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) -> Error {
151e98a4c5aSCarlos Alberto Enciso       LHS->markMissingParents(RHS, /*TraverseChildren=*/true);
152e98a4c5aSCarlos Alberto Enciso       if (LHS->getIsMissingLink() && options().getReportAnyView()) {
153e98a4c5aSCarlos Alberto Enciso         // As we are printing a missing tree, enable formatting.
154e98a4c5aSCarlos Alberto Enciso         options().setPrintFormatting();
155e98a4c5aSCarlos Alberto Enciso         OS << "\nMissing Tree:\n";
156e98a4c5aSCarlos Alberto Enciso         if (Error Err = LHS->doPrint(/*Split=*/false, /*Match=*/false,
157e98a4c5aSCarlos Alberto Enciso                                      /*Print=*/true, OS))
158e98a4c5aSCarlos Alberto Enciso           return Err;
159e98a4c5aSCarlos Alberto Enciso         options().resetPrintFormatting();
160e98a4c5aSCarlos Alberto Enciso       }
161e98a4c5aSCarlos Alberto Enciso 
162e98a4c5aSCarlos Alberto Enciso       return Error::success();
163e98a4c5aSCarlos Alberto Enciso     };
164e98a4c5aSCarlos Alberto Enciso 
165e98a4c5aSCarlos Alberto Enciso     // If the user has requested printing details for the comparison, we
166e98a4c5aSCarlos Alberto Enciso     // disable the indentation and the added/missing tags ('+'/'-'), as the
167e98a4c5aSCarlos Alberto Enciso     // details are just a list of elements.
168e98a4c5aSCarlos Alberto Enciso     options().resetPrintFormatting();
169e98a4c5aSCarlos Alberto Enciso 
170e98a4c5aSCarlos Alberto Enciso     PrintHeader(ReferenceRoot, TargetRoot);
171e98a4c5aSCarlos Alberto Enciso     Reader = ReferenceReader;
172e98a4c5aSCarlos Alberto Enciso     if (Error Err = CompareViews(ReferenceRoot, TargetRoot))
173e98a4c5aSCarlos Alberto Enciso       return Err;
174e98a4c5aSCarlos Alberto Enciso     FirstMissing = true;
175e98a4c5aSCarlos Alberto Enciso     ReferenceRoot->report(LVComparePass::Missing);
176e98a4c5aSCarlos Alberto Enciso 
177e98a4c5aSCarlos Alberto Enciso     PrintHeader(TargetRoot, ReferenceRoot);
178e98a4c5aSCarlos Alberto Enciso     Reader = TargetReader;
179e98a4c5aSCarlos Alberto Enciso     if (Error Err = CompareViews(TargetRoot, ReferenceRoot))
180e98a4c5aSCarlos Alberto Enciso       return Err;
181e98a4c5aSCarlos Alberto Enciso     FirstMissing = true;
182e98a4c5aSCarlos Alberto Enciso     TargetRoot->report(LVComparePass::Added);
183e98a4c5aSCarlos Alberto Enciso 
184e98a4c5aSCarlos Alberto Enciso     options().setPrintFormatting();
185e98a4c5aSCarlos Alberto Enciso 
186e98a4c5aSCarlos Alberto Enciso     // Display a summary with the elements missing and/or added.
187e98a4c5aSCarlos Alberto Enciso     printSummary();
188e98a4c5aSCarlos Alberto Enciso   } else {
189e98a4c5aSCarlos Alberto Enciso     // Perform logical elements comparison. An equal test is apply to each
190e98a4c5aSCarlos Alberto Enciso     // element. If a difference is found, the reference element is marked as
191e98a4c5aSCarlos Alberto Enciso     // 'missing'.
192e98a4c5aSCarlos Alberto Enciso     // The final comparison result will show the 'Reference' scopes tree,
193e98a4c5aSCarlos Alberto Enciso     // having both missing and added elements.
194e98a4c5aSCarlos Alberto Enciso     using LVScopeLink = std::map<LVScope *, LVScope *>;
195e98a4c5aSCarlos Alberto Enciso     LVScopeLink ScopeLinks;
196e98a4c5aSCarlos Alberto Enciso     auto CompareReaders = [&](LVReader *LHS, LVReader *RHS, LVElements &Set,
197e98a4c5aSCarlos Alberto Enciso                               LVComparePass Pass) -> Error {
198e98a4c5aSCarlos Alberto Enciso       auto FindMatch = [&](auto &References, auto &Targets,
199e98a4c5aSCarlos Alberto Enciso                            const char *Category) -> Error {
200e98a4c5aSCarlos Alberto Enciso         LVElements Elements;
201e98a4c5aSCarlos Alberto Enciso         for (LVElement *Reference : References) {
202e98a4c5aSCarlos Alberto Enciso           // Report elements that can be printed; ignore logical elements that
203e98a4c5aSCarlos Alberto Enciso           // have qualifiers.
204e98a4c5aSCarlos Alberto Enciso           if (Reference->getIncludeInPrint()) {
205e98a4c5aSCarlos Alberto Enciso             if (Pass == LVComparePass::Missing)
206e98a4c5aSCarlos Alberto Enciso               updateExpected(Reference);
207e98a4c5aSCarlos Alberto Enciso             Reference->setIsInCompare();
208e98a4c5aSCarlos Alberto Enciso             LVElement *CurrentTarget = nullptr;
2096e18003aSKazu Hirata             if (llvm::any_of(Targets, [&](auto Target) -> bool {
210e98a4c5aSCarlos Alberto Enciso                   CurrentTarget = Target;
211e98a4c5aSCarlos Alberto Enciso                   return Reference->equals(Target);
212e98a4c5aSCarlos Alberto Enciso                 })) {
213e98a4c5aSCarlos Alberto Enciso               if (Pass == LVComparePass::Missing && Reference->getIsScope()) {
214e98a4c5aSCarlos Alberto Enciso                 // If the elements being compared are scopes and are a match,
215e98a4c5aSCarlos Alberto Enciso                 // they are recorded, to be used when creating the augmented
216e98a4c5aSCarlos Alberto Enciso                 // tree, as insertion points for the "added" items.
217e98a4c5aSCarlos Alberto Enciso                 ScopeLinks.emplace(static_cast<LVScope *>(CurrentTarget),
218e98a4c5aSCarlos Alberto Enciso                                    static_cast<LVScope *>(Reference));
219e98a4c5aSCarlos Alberto Enciso               }
220e98a4c5aSCarlos Alberto Enciso             } else {
221e98a4c5aSCarlos Alberto Enciso               // Element is missing or added.
222e98a4c5aSCarlos Alberto Enciso               Pass == LVComparePass::Missing ? Reference->setIsMissing()
223e98a4c5aSCarlos Alberto Enciso                                              : Reference->setIsAdded();
224e98a4c5aSCarlos Alberto Enciso               Elements.push_back(Reference);
225e98a4c5aSCarlos Alberto Enciso               updateMissingOrAdded(Reference, Pass);
226e98a4c5aSCarlos Alberto Enciso               // Record missing/added element.
227e98a4c5aSCarlos Alberto Enciso               addPassEntry(Reader, Reference, Pass);
228e98a4c5aSCarlos Alberto Enciso             }
229e98a4c5aSCarlos Alberto Enciso           }
230e98a4c5aSCarlos Alberto Enciso         }
231e98a4c5aSCarlos Alberto Enciso         if (Pass == LVComparePass::Added)
232e98a4c5aSCarlos Alberto Enciso           // Record all the current missing elements for this category.
233e98a4c5aSCarlos Alberto Enciso           Set.insert(Set.end(), Elements.begin(), Elements.end());
234e98a4c5aSCarlos Alberto Enciso         if (options().getReportList()) {
235e98a4c5aSCarlos Alberto Enciso           if (Elements.size()) {
236e98a4c5aSCarlos Alberto Enciso             OS << "\n(" << Elements.size() << ") "
237e98a4c5aSCarlos Alberto Enciso                << (Pass == LVComparePass::Missing ? "Missing" : "Added") << " "
238e98a4c5aSCarlos Alberto Enciso                << Category << ":\n";
239e98a4c5aSCarlos Alberto Enciso             for (const LVElement *Element : Elements) {
240e98a4c5aSCarlos Alberto Enciso               if (Error Err = Element->doPrint(/*Split=*/false, /*Match=*/false,
241e98a4c5aSCarlos Alberto Enciso                                                /*Print=*/true, OS))
242e98a4c5aSCarlos Alberto Enciso                 return Err;
243e98a4c5aSCarlos Alberto Enciso             }
244e98a4c5aSCarlos Alberto Enciso           }
245e98a4c5aSCarlos Alberto Enciso         }
246e98a4c5aSCarlos Alberto Enciso 
247e98a4c5aSCarlos Alberto Enciso         return Error::success();
248e98a4c5aSCarlos Alberto Enciso       };
249e98a4c5aSCarlos Alberto Enciso 
250e98a4c5aSCarlos Alberto Enciso       // First compare the scopes, so they will be inserted at the front of
251e98a4c5aSCarlos Alberto Enciso       // the missing elements list. When they are moved, their children are
252e98a4c5aSCarlos Alberto Enciso       // moved as well and no additional work is required.
253e98a4c5aSCarlos Alberto Enciso       if (options().getCompareScopes())
254e98a4c5aSCarlos Alberto Enciso         if (Error Err = FindMatch(LHS->getScopes(), RHS->getScopes(), "Scopes"))
255e98a4c5aSCarlos Alberto Enciso           return Err;
256e98a4c5aSCarlos Alberto Enciso       if (options().getCompareSymbols())
257e98a4c5aSCarlos Alberto Enciso         if (Error Err =
258e98a4c5aSCarlos Alberto Enciso                 FindMatch(LHS->getSymbols(), RHS->getSymbols(), "Symbols"))
259e98a4c5aSCarlos Alberto Enciso           return Err;
260e98a4c5aSCarlos Alberto Enciso       if (options().getCompareTypes())
261e98a4c5aSCarlos Alberto Enciso         if (Error Err = FindMatch(LHS->getTypes(), RHS->getTypes(), "Types"))
262e98a4c5aSCarlos Alberto Enciso           return Err;
263e98a4c5aSCarlos Alberto Enciso       if (options().getCompareLines())
264e98a4c5aSCarlos Alberto Enciso         if (Error Err = FindMatch(LHS->getLines(), RHS->getLines(), "Lines"))
265e98a4c5aSCarlos Alberto Enciso           return Err;
266e98a4c5aSCarlos Alberto Enciso 
267e98a4c5aSCarlos Alberto Enciso       return Error::success();
268e98a4c5aSCarlos Alberto Enciso     };
269e98a4c5aSCarlos Alberto Enciso 
270e98a4c5aSCarlos Alberto Enciso     // If the user has requested printing details for the comparison, we
271e98a4c5aSCarlos Alberto Enciso     // disable the indentation and the added/missing tags ('+'/'-'), as the
272e98a4c5aSCarlos Alberto Enciso     // details are just a list of elements.
273e98a4c5aSCarlos Alberto Enciso     options().resetPrintFormatting();
274e98a4c5aSCarlos Alberto Enciso 
275e98a4c5aSCarlos Alberto Enciso     PrintHeader(ReferenceRoot, TargetRoot);
276e98a4c5aSCarlos Alberto Enciso     // Include the root in the expected count.
277e98a4c5aSCarlos Alberto Enciso     updateExpected(ReferenceRoot);
278e98a4c5aSCarlos Alberto Enciso 
279e98a4c5aSCarlos Alberto Enciso     LVElements ElementsToAdd;
280e98a4c5aSCarlos Alberto Enciso     Reader = ReferenceReader;
281e98a4c5aSCarlos Alberto Enciso     if (Error Err = CompareReaders(ReferenceReader, TargetReader, ElementsToAdd,
282e98a4c5aSCarlos Alberto Enciso                                    LVComparePass::Missing))
283e98a4c5aSCarlos Alberto Enciso       return Err;
284e98a4c5aSCarlos Alberto Enciso     Reader = TargetReader;
285e98a4c5aSCarlos Alberto Enciso     if (Error Err = CompareReaders(TargetReader, ReferenceReader, ElementsToAdd,
286e98a4c5aSCarlos Alberto Enciso                                    LVComparePass::Added))
287e98a4c5aSCarlos Alberto Enciso       return Err;
288e98a4c5aSCarlos Alberto Enciso 
289e98a4c5aSCarlos Alberto Enciso     LLVM_DEBUG({
290e98a4c5aSCarlos Alberto Enciso       dbgs() << "\nReference/Target Scope links:\n";
291e98a4c5aSCarlos Alberto Enciso       for (LVScopeLink::const_reference Entry : ScopeLinks)
292e98a4c5aSCarlos Alberto Enciso         dbgs() << "Source: " << hexSquareString(Entry.first->getOffset()) << " "
293e98a4c5aSCarlos Alberto Enciso                << "Destination: " << hexSquareString(Entry.second->getOffset())
294e98a4c5aSCarlos Alberto Enciso                << "\n";
295e98a4c5aSCarlos Alberto Enciso       dbgs() << "\n";
296e98a4c5aSCarlos Alberto Enciso     });
297e98a4c5aSCarlos Alberto Enciso 
298e98a4c5aSCarlos Alberto Enciso     // Add the 'missing' elements from the 'Target' into the 'Reference'.
299e98a4c5aSCarlos Alberto Enciso     // First insert the missing scopes, as they include any missing children.
300e98a4c5aSCarlos Alberto Enciso     LVScope *Parent = nullptr;
301e98a4c5aSCarlos Alberto Enciso     for (LVElement *Element : ElementsToAdd) {
302e98a4c5aSCarlos Alberto Enciso       LLVM_DEBUG({
303e98a4c5aSCarlos Alberto Enciso         dbgs() << "Element to Insert: " << hexSquareString(Element->getOffset())
304e98a4c5aSCarlos Alberto Enciso                << ", Parent: "
305e98a4c5aSCarlos Alberto Enciso                << hexSquareString(Element->getParentScope()->getOffset())
306e98a4c5aSCarlos Alberto Enciso                << "\n";
307e98a4c5aSCarlos Alberto Enciso       });
308e98a4c5aSCarlos Alberto Enciso       // Skip already inserted elements. They were inserted, if their parents
309e98a4c5aSCarlos Alberto Enciso       // were missing. When inserting them, all the children are moved.
310e98a4c5aSCarlos Alberto Enciso       if (Element->getHasMoved())
311e98a4c5aSCarlos Alberto Enciso         continue;
312e98a4c5aSCarlos Alberto Enciso 
313e98a4c5aSCarlos Alberto Enciso       // We need to find an insertion point in the reference scopes tree.
314e98a4c5aSCarlos Alberto Enciso       Parent = Element->getParentScope();
315*f01d45cfSKazu Hirata       auto It = ScopeLinks.find(Parent);
316*f01d45cfSKazu Hirata       if (It != ScopeLinks.end()) {
317*f01d45cfSKazu Hirata         LVScope *InsertionPoint = It->second;
318e98a4c5aSCarlos Alberto Enciso         LLVM_DEBUG({
319e98a4c5aSCarlos Alberto Enciso           dbgs() << "Inserted at: "
320e98a4c5aSCarlos Alberto Enciso                  << hexSquareString(InsertionPoint->getOffset()) << "\n";
321e98a4c5aSCarlos Alberto Enciso         });
322e98a4c5aSCarlos Alberto Enciso         if (Parent->removeElement(Element)) {
323e98a4c5aSCarlos Alberto Enciso           // Be sure we have a current compile unit.
324e98a4c5aSCarlos Alberto Enciso           getReader().setCompileUnit(InsertionPoint->getCompileUnitParent());
325e98a4c5aSCarlos Alberto Enciso           InsertionPoint->addElement(Element);
326e98a4c5aSCarlos Alberto Enciso           Element->updateLevel(InsertionPoint, /*Moved=*/true);
327e98a4c5aSCarlos Alberto Enciso         }
328e98a4c5aSCarlos Alberto Enciso       }
329e98a4c5aSCarlos Alberto Enciso     }
330e98a4c5aSCarlos Alberto Enciso 
331e98a4c5aSCarlos Alberto Enciso     options().setPrintFormatting();
332e98a4c5aSCarlos Alberto Enciso 
333e98a4c5aSCarlos Alberto Enciso     // Display the augmented reference scopes tree.
334e98a4c5aSCarlos Alberto Enciso     if (options().getReportAnyView())
335e98a4c5aSCarlos Alberto Enciso       if (Error Err = ReferenceReader->doPrint())
336e98a4c5aSCarlos Alberto Enciso         return Err;
337e98a4c5aSCarlos Alberto Enciso 
338e98a4c5aSCarlos Alberto Enciso     LLVM_DEBUG({
339e98a4c5aSCarlos Alberto Enciso       dbgs() << "\nModified Reference Reader";
340e98a4c5aSCarlos Alberto Enciso       if (Error Err = ReferenceReader->doPrint())
341e98a4c5aSCarlos Alberto Enciso         return Err;
342e98a4c5aSCarlos Alberto Enciso       dbgs() << "\nModified Target Reader";
343e98a4c5aSCarlos Alberto Enciso       if (Error Err = TargetReader->doPrint())
344e98a4c5aSCarlos Alberto Enciso         return Err;
345e98a4c5aSCarlos Alberto Enciso     });
346e98a4c5aSCarlos Alberto Enciso 
347e98a4c5aSCarlos Alberto Enciso     // Display a summary with the elements missing and/or added.
348e98a4c5aSCarlos Alberto Enciso     printSummary();
349e98a4c5aSCarlos Alberto Enciso   }
350e98a4c5aSCarlos Alberto Enciso 
351e98a4c5aSCarlos Alberto Enciso   return Error::success();
352e98a4c5aSCarlos Alberto Enciso }
353e98a4c5aSCarlos Alberto Enciso 
354e98a4c5aSCarlos Alberto Enciso void LVCompare::printCurrentStack() {
355e98a4c5aSCarlos Alberto Enciso   for (const LVScope *Scope : ScopeStack) {
356e98a4c5aSCarlos Alberto Enciso     Scope->printAttributes(OS);
357e98a4c5aSCarlos Alberto Enciso     OS << Scope->lineNumberAsString(/*ShowZero=*/true) << " " << Scope->kind()
358e98a4c5aSCarlos Alberto Enciso        << " " << formattedName(Scope->getName()) << "\n";
359e98a4c5aSCarlos Alberto Enciso   }
360e98a4c5aSCarlos Alberto Enciso }
361e98a4c5aSCarlos Alberto Enciso 
362e98a4c5aSCarlos Alberto Enciso void LVCompare::printItem(LVElement *Element, LVComparePass Pass) {
363e98a4c5aSCarlos Alberto Enciso   // Record expected, missing, added.
364e98a4c5aSCarlos Alberto Enciso   updateExpected(Element);
365e98a4c5aSCarlos Alberto Enciso   updateMissingOrAdded(Element, Pass);
366e98a4c5aSCarlos Alberto Enciso 
367e98a4c5aSCarlos Alberto Enciso   // Record missing/added element.
368e98a4c5aSCarlos Alberto Enciso   if (Element->getIsMissing())
369e98a4c5aSCarlos Alberto Enciso     addPassEntry(Reader, Element, Pass);
370e98a4c5aSCarlos Alberto Enciso 
371e98a4c5aSCarlos Alberto Enciso   if ((!PrintLines && Element->getIsLine()) ||
372e98a4c5aSCarlos Alberto Enciso       (!PrintScopes && Element->getIsScope()) ||
373e98a4c5aSCarlos Alberto Enciso       (!PrintSymbols && Element->getIsSymbol()) ||
374e98a4c5aSCarlos Alberto Enciso       (!PrintTypes && Element->getIsType()))
375e98a4c5aSCarlos Alberto Enciso     return;
376e98a4c5aSCarlos Alberto Enciso 
377e98a4c5aSCarlos Alberto Enciso   if (Element->getIsMissing()) {
378e98a4c5aSCarlos Alberto Enciso     if (FirstMissing) {
379e98a4c5aSCarlos Alberto Enciso       OS << "\n";
380e98a4c5aSCarlos Alberto Enciso       FirstMissing = false;
381e98a4c5aSCarlos Alberto Enciso     }
382e98a4c5aSCarlos Alberto Enciso 
383e98a4c5aSCarlos Alberto Enciso     StringRef Kind = Element->kind();
384e98a4c5aSCarlos Alberto Enciso     StringRef Name =
385e98a4c5aSCarlos Alberto Enciso         Element->getIsLine() ? Element->getPathname() : Element->getName();
386e98a4c5aSCarlos Alberto Enciso     StringRef Status = (Pass == LVComparePass::Missing) ? "Missing" : "Added";
387e98a4c5aSCarlos Alberto Enciso     OS << Status << " " << Kind << " '" << Name << "'";
388e98a4c5aSCarlos Alberto Enciso     if (Element->getLineNumber() > 0)
389e98a4c5aSCarlos Alberto Enciso       OS << " at line " << Element->getLineNumber();
390e98a4c5aSCarlos Alberto Enciso     OS << "\n";
391e98a4c5aSCarlos Alberto Enciso 
392e98a4c5aSCarlos Alberto Enciso     if (options().getReportList()) {
393e98a4c5aSCarlos Alberto Enciso       printCurrentStack();
394e98a4c5aSCarlos Alberto Enciso       Element->printAttributes(OS);
395e98a4c5aSCarlos Alberto Enciso       OS << Element->lineNumberAsString(/*ShowZero=*/true) << " " << Kind << " "
396e98a4c5aSCarlos Alberto Enciso          << Name << "\n";
397e98a4c5aSCarlos Alberto Enciso     }
398e98a4c5aSCarlos Alberto Enciso   }
399e98a4c5aSCarlos Alberto Enciso }
400e98a4c5aSCarlos Alberto Enciso 
401e98a4c5aSCarlos Alberto Enciso void LVCompare::printSummary() const {
402e98a4c5aSCarlos Alberto Enciso   if (!options().getPrintSummary())
403e98a4c5aSCarlos Alberto Enciso     return;
404e98a4c5aSCarlos Alberto Enciso   std::string Separator = std::string(40, '-');
405e98a4c5aSCarlos Alberto Enciso   auto PrintSeparator = [&]() { OS << Separator << "\n"; };
406e98a4c5aSCarlos Alberto Enciso   auto PrintHeadingRow = [&](const char *T, const char *U, const char *V,
407e98a4c5aSCarlos Alberto Enciso                              const char *W) {
408e98a4c5aSCarlos Alberto Enciso     OS << format("%-9s%9s  %9s  %9s\n", T, U, V, W);
409e98a4c5aSCarlos Alberto Enciso   };
410e98a4c5aSCarlos Alberto Enciso   auto PrintDataRow = [&](const char *T, unsigned U, unsigned V, unsigned W) {
411e98a4c5aSCarlos Alberto Enciso     OS << format("%-9s%9d  %9d  %9d\n", T, U, V, W);
412e98a4c5aSCarlos Alberto Enciso   };
413e98a4c5aSCarlos Alberto Enciso 
414e98a4c5aSCarlos Alberto Enciso   OS << "\n";
415e98a4c5aSCarlos Alberto Enciso   PrintSeparator();
416e98a4c5aSCarlos Alberto Enciso   PrintHeadingRow("Element", "Expected", "Missing", "Added");
417e98a4c5aSCarlos Alberto Enciso   PrintSeparator();
418e98a4c5aSCarlos Alberto Enciso   for (LVCompareInfo::reference Entry : Results) {
419e98a4c5aSCarlos Alberto Enciso     if (Entry.first == LVCompareItem::Total)
420e98a4c5aSCarlos Alberto Enciso       PrintSeparator();
421e98a4c5aSCarlos Alberto Enciso     PrintDataRow(std::get<getHeader()>(Entry.second),
422e98a4c5aSCarlos Alberto Enciso                  std::get<getExpected()>(Entry.second),
423e98a4c5aSCarlos Alberto Enciso                  std::get<getMissing()>(Entry.second),
424e98a4c5aSCarlos Alberto Enciso                  std::get<getAdded()>(Entry.second));
425e98a4c5aSCarlos Alberto Enciso   }
426e98a4c5aSCarlos Alberto Enciso }
427e98a4c5aSCarlos Alberto Enciso 
428e98a4c5aSCarlos Alberto Enciso void LVCompare::print(raw_ostream &OS) const { OS << "LVCompare\n"; }
429