1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2020-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License. You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker // https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Maria Teguiani
19*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
20*9e3b08aeSAndroid Build Coastguard Worker // Author: Ignes Simeonova
21*9e3b08aeSAndroid Build Coastguard Worker
22*9e3b08aeSAndroid Build Coastguard Worker #include "comparison.h"
23*9e3b08aeSAndroid Build Coastguard Worker
24*9e3b08aeSAndroid Build Coastguard Worker #include <algorithm>
25*9e3b08aeSAndroid Build Coastguard Worker #include <array>
26*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
27*9e3b08aeSAndroid Build Coastguard Worker #include <functional>
28*9e3b08aeSAndroid Build Coastguard Worker #include <map>
29*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
30*9e3b08aeSAndroid Build Coastguard Worker #include <ostream>
31*9e3b08aeSAndroid Build Coastguard Worker #include <set>
32*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
33*9e3b08aeSAndroid Build Coastguard Worker #include <string>
34*9e3b08aeSAndroid Build Coastguard Worker #include <string_view>
35*9e3b08aeSAndroid Build Coastguard Worker #include <unordered_map>
36*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
37*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
38*9e3b08aeSAndroid Build Coastguard Worker
39*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
40*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
41*9e3b08aeSAndroid Build Coastguard Worker #include "order.h"
42*9e3b08aeSAndroid Build Coastguard Worker #include "runtime.h"
43*9e3b08aeSAndroid Build Coastguard Worker #include "scc.h"
44*9e3b08aeSAndroid Build Coastguard Worker
45*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
46*9e3b08aeSAndroid Build Coastguard Worker namespace diff {
47*9e3b08aeSAndroid Build Coastguard Worker
48*9e3b08aeSAndroid Build Coastguard Worker namespace {
49*9e3b08aeSAndroid Build Coastguard Worker
50*9e3b08aeSAndroid Build Coastguard Worker struct IgnoreDescriptor {
51*9e3b08aeSAndroid Build Coastguard Worker std::string_view name;
52*9e3b08aeSAndroid Build Coastguard Worker Ignore::Value value;
53*9e3b08aeSAndroid Build Coastguard Worker };
54*9e3b08aeSAndroid Build Coastguard Worker
55*9e3b08aeSAndroid Build Coastguard Worker constexpr std::array<IgnoreDescriptor, 9> kIgnores{{
56*9e3b08aeSAndroid Build Coastguard Worker {"type_declaration_status", Ignore::TYPE_DECLARATION_STATUS },
57*9e3b08aeSAndroid Build Coastguard Worker {"symbol_type_presence", Ignore::SYMBOL_TYPE_PRESENCE },
58*9e3b08aeSAndroid Build Coastguard Worker {"primitive_type_encoding", Ignore::PRIMITIVE_TYPE_ENCODING },
59*9e3b08aeSAndroid Build Coastguard Worker {"member_size", Ignore::MEMBER_SIZE },
60*9e3b08aeSAndroid Build Coastguard Worker {"enum_underlying_type", Ignore::ENUM_UNDERLYING_TYPE },
61*9e3b08aeSAndroid Build Coastguard Worker {"qualifier", Ignore::QUALIFIER },
62*9e3b08aeSAndroid Build Coastguard Worker {"linux_symbol_crc", Ignore::SYMBOL_CRC },
63*9e3b08aeSAndroid Build Coastguard Worker {"interface_addition", Ignore::INTERFACE_ADDITION },
64*9e3b08aeSAndroid Build Coastguard Worker {"type_definition_addition", Ignore::TYPE_DEFINITION_ADDITION },
65*9e3b08aeSAndroid Build Coastguard Worker }};
66*9e3b08aeSAndroid Build Coastguard Worker
67*9e3b08aeSAndroid Build Coastguard Worker } // namespace
68*9e3b08aeSAndroid Build Coastguard Worker
ParseIgnore(std::string_view ignore)69*9e3b08aeSAndroid Build Coastguard Worker std::optional<Ignore::Value> ParseIgnore(std::string_view ignore) {
70*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [name, value] : kIgnores) {
71*9e3b08aeSAndroid Build Coastguard Worker if (name == ignore) {
72*9e3b08aeSAndroid Build Coastguard Worker return {value};
73*9e3b08aeSAndroid Build Coastguard Worker }
74*9e3b08aeSAndroid Build Coastguard Worker }
75*9e3b08aeSAndroid Build Coastguard Worker return {};
76*9e3b08aeSAndroid Build Coastguard Worker }
77*9e3b08aeSAndroid Build Coastguard Worker
operator <<(std::ostream & os,IgnoreUsage)78*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, IgnoreUsage) {
79*9e3b08aeSAndroid Build Coastguard Worker os << "ignore options:";
80*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [name, _] : kIgnores) {
81*9e3b08aeSAndroid Build Coastguard Worker os << ' ' << name;
82*9e3b08aeSAndroid Build Coastguard Worker }
83*9e3b08aeSAndroid Build Coastguard Worker return os << '\n';
84*9e3b08aeSAndroid Build Coastguard Worker }
85*9e3b08aeSAndroid Build Coastguard Worker
86*9e3b08aeSAndroid Build Coastguard Worker namespace {
87*9e3b08aeSAndroid Build Coastguard Worker
88*9e3b08aeSAndroid Build Coastguard Worker struct Result {
89*9e3b08aeSAndroid Build Coastguard Worker // Used when two nodes cannot be meaningfully compared.
MarkIncomparablestg::diff::__anon19fbf5d30211::Result90*9e3b08aeSAndroid Build Coastguard Worker Result& MarkIncomparable() {
91*9e3b08aeSAndroid Build Coastguard Worker same = false;
92*9e3b08aeSAndroid Build Coastguard Worker diff.has_changes = true;
93*9e3b08aeSAndroid Build Coastguard Worker return *this;
94*9e3b08aeSAndroid Build Coastguard Worker }
95*9e3b08aeSAndroid Build Coastguard Worker
96*9e3b08aeSAndroid Build Coastguard Worker // Used when a node attribute has changed.
AddNodeDiffstg::diff::__anon19fbf5d30211::Result97*9e3b08aeSAndroid Build Coastguard Worker void AddNodeDiff(const std::string& text) {
98*9e3b08aeSAndroid Build Coastguard Worker same = false;
99*9e3b08aeSAndroid Build Coastguard Worker diff.has_changes = true;
100*9e3b08aeSAndroid Build Coastguard Worker diff.Add(text, {});
101*9e3b08aeSAndroid Build Coastguard Worker }
102*9e3b08aeSAndroid Build Coastguard Worker
103*9e3b08aeSAndroid Build Coastguard Worker // Used when a node attribute may have changed.
104*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
MaybeAddNodeDiffstg::diff::__anon19fbf5d30211::Result105*9e3b08aeSAndroid Build Coastguard Worker void MaybeAddNodeDiff(
106*9e3b08aeSAndroid Build Coastguard Worker const std::string& text, const T& before, const T& after) {
107*9e3b08aeSAndroid Build Coastguard Worker if (before != after) {
108*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
109*9e3b08aeSAndroid Build Coastguard Worker os << text << " changed from " << before << " to " << after;
110*9e3b08aeSAndroid Build Coastguard Worker AddNodeDiff(os.str());
111*9e3b08aeSAndroid Build Coastguard Worker }
112*9e3b08aeSAndroid Build Coastguard Worker }
113*9e3b08aeSAndroid Build Coastguard Worker
114*9e3b08aeSAndroid Build Coastguard Worker // Used when a node attribute may have changed, lazy version.
115*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
MaybeAddNodeDiffstg::diff::__anon19fbf5d30211::Result116*9e3b08aeSAndroid Build Coastguard Worker void MaybeAddNodeDiff(const std::function<void(std::ostream&)>& text,
117*9e3b08aeSAndroid Build Coastguard Worker const T& before, const T& after) {
118*9e3b08aeSAndroid Build Coastguard Worker if (before != after) {
119*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
120*9e3b08aeSAndroid Build Coastguard Worker text(os);
121*9e3b08aeSAndroid Build Coastguard Worker os << " changed from " << before << " to " << after;
122*9e3b08aeSAndroid Build Coastguard Worker AddNodeDiff(os.str());
123*9e3b08aeSAndroid Build Coastguard Worker }
124*9e3b08aeSAndroid Build Coastguard Worker }
125*9e3b08aeSAndroid Build Coastguard Worker
126*9e3b08aeSAndroid Build Coastguard Worker // Used when node attributes are optional values.
127*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
MaybeAddNodeDiffstg::diff::__anon19fbf5d30211::Result128*9e3b08aeSAndroid Build Coastguard Worker void MaybeAddNodeDiff(const std::string& text, const std::optional<T>& before,
129*9e3b08aeSAndroid Build Coastguard Worker const std::optional<T>& after) {
130*9e3b08aeSAndroid Build Coastguard Worker if (before && after) {
131*9e3b08aeSAndroid Build Coastguard Worker MaybeAddNodeDiff(text, *before, *after);
132*9e3b08aeSAndroid Build Coastguard Worker } else if (before) {
133*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
134*9e3b08aeSAndroid Build Coastguard Worker os << text << ' ' << *before << " was removed";
135*9e3b08aeSAndroid Build Coastguard Worker AddNodeDiff(os.str());
136*9e3b08aeSAndroid Build Coastguard Worker } else if (after) {
137*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
138*9e3b08aeSAndroid Build Coastguard Worker os << text << ' ' << *after << " was added";
139*9e3b08aeSAndroid Build Coastguard Worker AddNodeDiff(os.str());
140*9e3b08aeSAndroid Build Coastguard Worker }
141*9e3b08aeSAndroid Build Coastguard Worker }
142*9e3b08aeSAndroid Build Coastguard Worker
143*9e3b08aeSAndroid Build Coastguard Worker // Used when an edge has been removed or added.
AddEdgeDiffstg::diff::__anon19fbf5d30211::Result144*9e3b08aeSAndroid Build Coastguard Worker void AddEdgeDiff(const std::string& text, const Comparison& comparison) {
145*9e3b08aeSAndroid Build Coastguard Worker same = false;
146*9e3b08aeSAndroid Build Coastguard Worker diff.Add(text, comparison);
147*9e3b08aeSAndroid Build Coastguard Worker }
148*9e3b08aeSAndroid Build Coastguard Worker
149*9e3b08aeSAndroid Build Coastguard Worker // Used when an edge to a possible comparison is present.
MaybeAddEdgeDiffstg::diff::__anon19fbf5d30211::Result150*9e3b08aeSAndroid Build Coastguard Worker void MaybeAddEdgeDiff(const std::string& text,
151*9e3b08aeSAndroid Build Coastguard Worker const std::pair<bool, Comparison>& p) {
152*9e3b08aeSAndroid Build Coastguard Worker same &= p.first;
153*9e3b08aeSAndroid Build Coastguard Worker const auto& comparison = p.second;
154*9e3b08aeSAndroid Build Coastguard Worker if (comparison != Comparison{}) {
155*9e3b08aeSAndroid Build Coastguard Worker diff.Add(text, comparison);
156*9e3b08aeSAndroid Build Coastguard Worker }
157*9e3b08aeSAndroid Build Coastguard Worker }
158*9e3b08aeSAndroid Build Coastguard Worker
159*9e3b08aeSAndroid Build Coastguard Worker // Used when an edge to a possible comparison is present, lazy version.
MaybeAddEdgeDiffstg::diff::__anon19fbf5d30211::Result160*9e3b08aeSAndroid Build Coastguard Worker void MaybeAddEdgeDiff(const std::function<void(std::ostream&)>& text,
161*9e3b08aeSAndroid Build Coastguard Worker const std::pair<bool, Comparison>& p) {
162*9e3b08aeSAndroid Build Coastguard Worker same &= p.first;
163*9e3b08aeSAndroid Build Coastguard Worker const auto& comparison = p.second;
164*9e3b08aeSAndroid Build Coastguard Worker if (comparison != Comparison{}) {
165*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
166*9e3b08aeSAndroid Build Coastguard Worker text(os);
167*9e3b08aeSAndroid Build Coastguard Worker diff.Add(os.str(), comparison);
168*9e3b08aeSAndroid Build Coastguard Worker }
169*9e3b08aeSAndroid Build Coastguard Worker }
170*9e3b08aeSAndroid Build Coastguard Worker
171*9e3b08aeSAndroid Build Coastguard Worker bool same = true;
172*9e3b08aeSAndroid Build Coastguard Worker Diff diff;
173*9e3b08aeSAndroid Build Coastguard Worker };
174*9e3b08aeSAndroid Build Coastguard Worker
175*9e3b08aeSAndroid Build Coastguard Worker struct ResolveTypedef {
ResolveTypedefstg::diff::__anon19fbf5d30211::ResolveTypedef176*9e3b08aeSAndroid Build Coastguard Worker ResolveTypedef(const Graph& graph, Id& id, std::vector<std::string>& names)
177*9e3b08aeSAndroid Build Coastguard Worker : graph(graph), id(id), names(names) {}
178*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::ResolveTypedef179*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Typedef& x) {
180*9e3b08aeSAndroid Build Coastguard Worker id = x.referred_type_id;
181*9e3b08aeSAndroid Build Coastguard Worker names.push_back(x.name);
182*9e3b08aeSAndroid Build Coastguard Worker return true;
183*9e3b08aeSAndroid Build Coastguard Worker }
184*9e3b08aeSAndroid Build Coastguard Worker
185*9e3b08aeSAndroid Build Coastguard Worker template <typename Node>
operator ()stg::diff::__anon19fbf5d30211::ResolveTypedef186*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Node&) {
187*9e3b08aeSAndroid Build Coastguard Worker return false;
188*9e3b08aeSAndroid Build Coastguard Worker }
189*9e3b08aeSAndroid Build Coastguard Worker
190*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
191*9e3b08aeSAndroid Build Coastguard Worker Id& id;
192*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::string>& names;
193*9e3b08aeSAndroid Build Coastguard Worker };
194*9e3b08aeSAndroid Build Coastguard Worker
195*9e3b08aeSAndroid Build Coastguard Worker using Qualifiers = std::set<Qualifier>;
196*9e3b08aeSAndroid Build Coastguard Worker
197*9e3b08aeSAndroid Build Coastguard Worker struct ResolveQualifier {
ResolveQualifierstg::diff::__anon19fbf5d30211::ResolveQualifier198*9e3b08aeSAndroid Build Coastguard Worker ResolveQualifier(const Graph& graph, Id& id, Qualifiers& qualifiers)
199*9e3b08aeSAndroid Build Coastguard Worker : graph(graph), id(id), qualifiers(qualifiers) {}
200*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::ResolveQualifier201*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Qualified& x) {
202*9e3b08aeSAndroid Build Coastguard Worker id = x.qualified_type_id;
203*9e3b08aeSAndroid Build Coastguard Worker qualifiers.insert(x.qualifier);
204*9e3b08aeSAndroid Build Coastguard Worker return true;
205*9e3b08aeSAndroid Build Coastguard Worker }
206*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::ResolveQualifier207*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Array&) {
208*9e3b08aeSAndroid Build Coastguard Worker // There should be no qualifiers here.
209*9e3b08aeSAndroid Build Coastguard Worker qualifiers.clear();
210*9e3b08aeSAndroid Build Coastguard Worker return false;
211*9e3b08aeSAndroid Build Coastguard Worker }
212*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::ResolveQualifier213*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Function&) {
214*9e3b08aeSAndroid Build Coastguard Worker // There should be no qualifiers here.
215*9e3b08aeSAndroid Build Coastguard Worker qualifiers.clear();
216*9e3b08aeSAndroid Build Coastguard Worker return false;
217*9e3b08aeSAndroid Build Coastguard Worker }
218*9e3b08aeSAndroid Build Coastguard Worker
219*9e3b08aeSAndroid Build Coastguard Worker template <typename Node>
operator ()stg::diff::__anon19fbf5d30211::ResolveQualifier220*9e3b08aeSAndroid Build Coastguard Worker bool operator()(const Node&) {
221*9e3b08aeSAndroid Build Coastguard Worker return false;
222*9e3b08aeSAndroid Build Coastguard Worker }
223*9e3b08aeSAndroid Build Coastguard Worker
224*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
225*9e3b08aeSAndroid Build Coastguard Worker Id& id;
226*9e3b08aeSAndroid Build Coastguard Worker Qualifiers& qualifiers;
227*9e3b08aeSAndroid Build Coastguard Worker };
228*9e3b08aeSAndroid Build Coastguard Worker
229*9e3b08aeSAndroid Build Coastguard Worker // Separate qualifiers from underlying type.
230*9e3b08aeSAndroid Build Coastguard Worker //
231*9e3b08aeSAndroid Build Coastguard Worker // The caller must always be prepared to receive a different type as qualifiers
232*9e3b08aeSAndroid Build Coastguard Worker // are sometimes discarded.
ResolveQualifiers(const Graph & graph,Id id)233*9e3b08aeSAndroid Build Coastguard Worker std::pair<Id, Qualifiers> ResolveQualifiers(const Graph& graph, Id id) {
234*9e3b08aeSAndroid Build Coastguard Worker std::pair<Id, Qualifiers> result = {id, {}};
235*9e3b08aeSAndroid Build Coastguard Worker ResolveQualifier resolve(graph, result.first, result.second);
236*9e3b08aeSAndroid Build Coastguard Worker while (graph.Apply(resolve, result.first)) {}
237*9e3b08aeSAndroid Build Coastguard Worker return result;
238*9e3b08aeSAndroid Build Coastguard Worker }
239*9e3b08aeSAndroid Build Coastguard Worker
240*9e3b08aeSAndroid Build Coastguard Worker struct MatchingKey {
MatchingKeystg::diff::__anon19fbf5d30211::MatchingKey241*9e3b08aeSAndroid Build Coastguard Worker explicit MatchingKey(const Graph& graph) : graph(graph) {}
242*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey243*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(Id id) {
244*9e3b08aeSAndroid Build Coastguard Worker return graph.Apply(*this, id);
245*9e3b08aeSAndroid Build Coastguard Worker }
246*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey247*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const BaseClass& x) {
248*9e3b08aeSAndroid Build Coastguard Worker return (*this)(x.type_id);
249*9e3b08aeSAndroid Build Coastguard Worker }
250*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey251*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const Method& x) {
252*9e3b08aeSAndroid Build Coastguard Worker return x.name + ',' + x.mangled_name;
253*9e3b08aeSAndroid Build Coastguard Worker }
254*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey255*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const Member& x) {
256*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty()) {
257*9e3b08aeSAndroid Build Coastguard Worker return x.name;
258*9e3b08aeSAndroid Build Coastguard Worker }
259*9e3b08aeSAndroid Build Coastguard Worker return (*this)(x.type_id);
260*9e3b08aeSAndroid Build Coastguard Worker }
261*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey262*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const VariantMember& x) {
263*9e3b08aeSAndroid Build Coastguard Worker return x.name;
264*9e3b08aeSAndroid Build Coastguard Worker }
265*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::MatchingKey266*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const StructUnion& x) {
267*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty()) {
268*9e3b08aeSAndroid Build Coastguard Worker return x.name;
269*9e3b08aeSAndroid Build Coastguard Worker }
270*9e3b08aeSAndroid Build Coastguard Worker if (x.definition) {
271*9e3b08aeSAndroid Build Coastguard Worker const auto& members = x.definition->members;
272*9e3b08aeSAndroid Build Coastguard Worker for (const auto& member : members) {
273*9e3b08aeSAndroid Build Coastguard Worker const auto recursive = (*this)(member);
274*9e3b08aeSAndroid Build Coastguard Worker if (!recursive.empty()) {
275*9e3b08aeSAndroid Build Coastguard Worker return recursive + '+';
276*9e3b08aeSAndroid Build Coastguard Worker }
277*9e3b08aeSAndroid Build Coastguard Worker }
278*9e3b08aeSAndroid Build Coastguard Worker }
279*9e3b08aeSAndroid Build Coastguard Worker return {};
280*9e3b08aeSAndroid Build Coastguard Worker }
281*9e3b08aeSAndroid Build Coastguard Worker
282*9e3b08aeSAndroid Build Coastguard Worker template <typename Node>
operator ()stg::diff::__anon19fbf5d30211::MatchingKey283*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const Node&) {
284*9e3b08aeSAndroid Build Coastguard Worker return {};
285*9e3b08aeSAndroid Build Coastguard Worker }
286*9e3b08aeSAndroid Build Coastguard Worker
287*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
288*9e3b08aeSAndroid Build Coastguard Worker };
289*9e3b08aeSAndroid Build Coastguard Worker
290*9e3b08aeSAndroid Build Coastguard Worker using KeyIndexPairs = std::vector<std::pair<std::string, size_t>>;
291*9e3b08aeSAndroid Build Coastguard Worker
MatchingKeys(const Graph & graph,const std::vector<Id> & ids)292*9e3b08aeSAndroid Build Coastguard Worker KeyIndexPairs MatchingKeys(const Graph& graph, const std::vector<Id>& ids) {
293*9e3b08aeSAndroid Build Coastguard Worker KeyIndexPairs keys;
294*9e3b08aeSAndroid Build Coastguard Worker const auto size = ids.size();
295*9e3b08aeSAndroid Build Coastguard Worker keys.reserve(size);
296*9e3b08aeSAndroid Build Coastguard Worker size_t anonymous_ix = 0;
297*9e3b08aeSAndroid Build Coastguard Worker for (size_t ix = 0; ix < size; ++ix) {
298*9e3b08aeSAndroid Build Coastguard Worker auto key = MatchingKey(graph)(ids[ix]);
299*9e3b08aeSAndroid Build Coastguard Worker if (key.empty()) {
300*9e3b08aeSAndroid Build Coastguard Worker key = "#anon#" + std::to_string(anonymous_ix++);
301*9e3b08aeSAndroid Build Coastguard Worker }
302*9e3b08aeSAndroid Build Coastguard Worker keys.emplace_back(key, ix);
303*9e3b08aeSAndroid Build Coastguard Worker }
304*9e3b08aeSAndroid Build Coastguard Worker std::stable_sort(keys.begin(), keys.end());
305*9e3b08aeSAndroid Build Coastguard Worker return keys;
306*9e3b08aeSAndroid Build Coastguard Worker }
307*9e3b08aeSAndroid Build Coastguard Worker
MatchingKeys(const Enumeration::Enumerators & enums)308*9e3b08aeSAndroid Build Coastguard Worker KeyIndexPairs MatchingKeys(const Enumeration::Enumerators& enums) {
309*9e3b08aeSAndroid Build Coastguard Worker KeyIndexPairs names;
310*9e3b08aeSAndroid Build Coastguard Worker const auto size = enums.size();
311*9e3b08aeSAndroid Build Coastguard Worker names.reserve(size);
312*9e3b08aeSAndroid Build Coastguard Worker for (size_t ix = 0; ix < size; ++ix) {
313*9e3b08aeSAndroid Build Coastguard Worker const auto& name = enums[ix].first;
314*9e3b08aeSAndroid Build Coastguard Worker names.emplace_back(name, ix);
315*9e3b08aeSAndroid Build Coastguard Worker }
316*9e3b08aeSAndroid Build Coastguard Worker std::stable_sort(names.begin(), names.end());
317*9e3b08aeSAndroid Build Coastguard Worker return names;
318*9e3b08aeSAndroid Build Coastguard Worker }
319*9e3b08aeSAndroid Build Coastguard Worker
320*9e3b08aeSAndroid Build Coastguard Worker using MatchedPairs =
321*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::pair<std::optional<size_t>, std::optional<size_t>>>;
322*9e3b08aeSAndroid Build Coastguard Worker
PairUp(const KeyIndexPairs & keys1,const KeyIndexPairs & keys2)323*9e3b08aeSAndroid Build Coastguard Worker MatchedPairs PairUp(const KeyIndexPairs& keys1, const KeyIndexPairs& keys2) {
324*9e3b08aeSAndroid Build Coastguard Worker MatchedPairs pairs;
325*9e3b08aeSAndroid Build Coastguard Worker pairs.reserve(std::max(keys1.size(), keys2.size()));
326*9e3b08aeSAndroid Build Coastguard Worker auto it1 = keys1.begin();
327*9e3b08aeSAndroid Build Coastguard Worker auto it2 = keys2.begin();
328*9e3b08aeSAndroid Build Coastguard Worker const auto end1 = keys1.end();
329*9e3b08aeSAndroid Build Coastguard Worker const auto end2 = keys2.end();
330*9e3b08aeSAndroid Build Coastguard Worker while (it1 != end1 || it2 != end2) {
331*9e3b08aeSAndroid Build Coastguard Worker if (it2 == end2 || (it1 != end1 && it1->first < it2->first)) {
332*9e3b08aeSAndroid Build Coastguard Worker // removed
333*9e3b08aeSAndroid Build Coastguard Worker pairs.push_back({{it1->second}, {}});
334*9e3b08aeSAndroid Build Coastguard Worker ++it1;
335*9e3b08aeSAndroid Build Coastguard Worker } else if (it1 == end1 || (it2 != end2 && it1->first > it2->first)) {
336*9e3b08aeSAndroid Build Coastguard Worker // added
337*9e3b08aeSAndroid Build Coastguard Worker pairs.push_back({{}, {it2->second}});
338*9e3b08aeSAndroid Build Coastguard Worker ++it2;
339*9e3b08aeSAndroid Build Coastguard Worker } else {
340*9e3b08aeSAndroid Build Coastguard Worker // in both
341*9e3b08aeSAndroid Build Coastguard Worker pairs.push_back({{it1->second}, {it2->second}});
342*9e3b08aeSAndroid Build Coastguard Worker ++it1;
343*9e3b08aeSAndroid Build Coastguard Worker ++it2;
344*9e3b08aeSAndroid Build Coastguard Worker }
345*9e3b08aeSAndroid Build Coastguard Worker }
346*9e3b08aeSAndroid Build Coastguard Worker return pairs;
347*9e3b08aeSAndroid Build Coastguard Worker }
348*9e3b08aeSAndroid Build Coastguard Worker
QualifiersMessage(Qualifier qualifier,const std::string & action)349*9e3b08aeSAndroid Build Coastguard Worker std::string QualifiersMessage(Qualifier qualifier, const std::string& action) {
350*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
351*9e3b08aeSAndroid Build Coastguard Worker os << "qualifier " << qualifier << ' ' << action;
352*9e3b08aeSAndroid Build Coastguard Worker return os.str();
353*9e3b08aeSAndroid Build Coastguard Worker }
354*9e3b08aeSAndroid Build Coastguard Worker
355*9e3b08aeSAndroid Build Coastguard Worker struct CompareWorker {
CompareWorkerstg::diff::__anon19fbf5d30211::CompareWorker356*9e3b08aeSAndroid Build Coastguard Worker CompareWorker(Runtime& runtime, const Ignore& ignore, const Graph& graph,
357*9e3b08aeSAndroid Build Coastguard Worker Outcomes& outcomes)
358*9e3b08aeSAndroid Build Coastguard Worker : ignore(ignore), graph(graph), outcomes(outcomes),
359*9e3b08aeSAndroid Build Coastguard Worker queried(runtime, "compare.queried"),
360*9e3b08aeSAndroid Build Coastguard Worker already_compared(runtime, "compare.already_compared"),
361*9e3b08aeSAndroid Build Coastguard Worker being_compared(runtime, "compare.being_compared"),
362*9e3b08aeSAndroid Build Coastguard Worker really_compared(runtime, "compare.really_compared"),
363*9e3b08aeSAndroid Build Coastguard Worker equivalent(runtime, "compare.equivalent"),
364*9e3b08aeSAndroid Build Coastguard Worker inequivalent(runtime, "compare.inequivalent"),
365*9e3b08aeSAndroid Build Coastguard Worker scc_size(runtime, "compare.scc_size") {}
366*9e3b08aeSAndroid Build Coastguard Worker
367*9e3b08aeSAndroid Build Coastguard Worker /*
368*9e3b08aeSAndroid Build Coastguard Worker * We compute a diff for every visited node.
369*9e3b08aeSAndroid Build Coastguard Worker *
370*9e3b08aeSAndroid Build Coastguard Worker * Each node has one of:
371*9e3b08aeSAndroid Build Coastguard Worker *
372*9e3b08aeSAndroid Build Coastguard Worker * 1. same == true; perhaps only tentative edge differences
373*9e3b08aeSAndroid Build Coastguard Worker * 2. same == false; at least one definitive node or edge difference
374*9e3b08aeSAndroid Build Coastguard Worker *
375*9e3b08aeSAndroid Build Coastguard Worker * On the first visit to a node we can put a placeholder in, the value of same
376*9e3b08aeSAndroid Build Coastguard Worker * is irrelevant, the diff may contain local and edge differences. If an SCC
377*9e3b08aeSAndroid Build Coastguard Worker * contains only internal edge differences (and equivalently same is true)
378*9e3b08aeSAndroid Build Coastguard Worker * then the differences can all (eventually) be discarded.
379*9e3b08aeSAndroid Build Coastguard Worker *
380*9e3b08aeSAndroid Build Coastguard Worker * On exit from the first visit to a node, same reflects the tree of
381*9e3b08aeSAndroid Build Coastguard Worker * comparisons below that node in the DFS and similarly, the diff graph
382*9e3b08aeSAndroid Build Coastguard Worker * starting from the node contains a subtree of this tree plus potentially
383*9e3b08aeSAndroid Build Coastguard Worker * edges to existing nodes to the side or below (already visited SCCs,
384*9e3b08aeSAndroid Build Coastguard Worker * sharing), or above (back links forming cycles).
385*9e3b08aeSAndroid Build Coastguard Worker *
386*9e3b08aeSAndroid Build Coastguard Worker * When an SCC is closed, all same implies deleting all diffs, any not same
387*9e3b08aeSAndroid Build Coastguard Worker * implies updating all to false.
388*9e3b08aeSAndroid Build Coastguard Worker *
389*9e3b08aeSAndroid Build Coastguard Worker * On subsequent visits to a node, there are 2 cases. The node is still open:
390*9e3b08aeSAndroid Build Coastguard Worker * return true and an edge diff. The node is closed, return the stored value
391*9e3b08aeSAndroid Build Coastguard Worker * and an edge diff.
392*9e3b08aeSAndroid Build Coastguard Worker */
operator ()stg::diff::__anon19fbf5d30211::CompareWorker393*9e3b08aeSAndroid Build Coastguard Worker std::pair<bool, Comparison> operator()(Id id1, Id id2) {
394*9e3b08aeSAndroid Build Coastguard Worker const Comparison comparison{{id1}, {id2}};
395*9e3b08aeSAndroid Build Coastguard Worker ++queried;
396*9e3b08aeSAndroid Build Coastguard Worker
397*9e3b08aeSAndroid Build Coastguard Worker // 1. Check if the comparison has an already known result.
398*9e3b08aeSAndroid Build Coastguard Worker const auto already_known = known.find(comparison);
399*9e3b08aeSAndroid Build Coastguard Worker if (already_known != known.end()) {
400*9e3b08aeSAndroid Build Coastguard Worker // Already visited and closed.
401*9e3b08aeSAndroid Build Coastguard Worker ++already_compared;
402*9e3b08aeSAndroid Build Coastguard Worker return already_known->second
403*9e3b08aeSAndroid Build Coastguard Worker ? std::make_pair(true, Comparison{})
404*9e3b08aeSAndroid Build Coastguard Worker : std::make_pair(false, comparison);
405*9e3b08aeSAndroid Build Coastguard Worker }
406*9e3b08aeSAndroid Build Coastguard Worker // Either open or not visited at all
407*9e3b08aeSAndroid Build Coastguard Worker
408*9e3b08aeSAndroid Build Coastguard Worker // 2. Record node with Strongly-Connected Component finder.
409*9e3b08aeSAndroid Build Coastguard Worker const auto handle = scc.Open(comparison);
410*9e3b08aeSAndroid Build Coastguard Worker if (!handle) {
411*9e3b08aeSAndroid Build Coastguard Worker // Already open.
412*9e3b08aeSAndroid Build Coastguard Worker //
413*9e3b08aeSAndroid Build Coastguard Worker // Return a dummy true outcome and some tentative diffs. The diffs may end
414*9e3b08aeSAndroid Build Coastguard Worker // up not being used and, while it would be nice to be lazier, they encode
415*9e3b08aeSAndroid Build Coastguard Worker // all the cycling-breaking edges needed to recreate a full diff
416*9e3b08aeSAndroid Build Coastguard Worker // structure.
417*9e3b08aeSAndroid Build Coastguard Worker ++being_compared;
418*9e3b08aeSAndroid Build Coastguard Worker return {true, comparison};
419*9e3b08aeSAndroid Build Coastguard Worker }
420*9e3b08aeSAndroid Build Coastguard Worker // Comparison opened, need to close it before returning.
421*9e3b08aeSAndroid Build Coastguard Worker ++really_compared;
422*9e3b08aeSAndroid Build Coastguard Worker
423*9e3b08aeSAndroid Build Coastguard Worker Result result;
424*9e3b08aeSAndroid Build Coastguard Worker
425*9e3b08aeSAndroid Build Coastguard Worker const auto [unqualified1, qualifiers1] = ResolveQualifiers(graph, id1);
426*9e3b08aeSAndroid Build Coastguard Worker const auto [unqualified2, qualifiers2] = ResolveQualifiers(graph, id2);
427*9e3b08aeSAndroid Build Coastguard Worker if (!qualifiers1.empty() || !qualifiers2.empty()) {
428*9e3b08aeSAndroid Build Coastguard Worker // 3.1 Qualified type difference.
429*9e3b08aeSAndroid Build Coastguard Worker auto it1 = qualifiers1.begin();
430*9e3b08aeSAndroid Build Coastguard Worker auto it2 = qualifiers2.begin();
431*9e3b08aeSAndroid Build Coastguard Worker const auto end1 = qualifiers1.end();
432*9e3b08aeSAndroid Build Coastguard Worker const auto end2 = qualifiers2.end();
433*9e3b08aeSAndroid Build Coastguard Worker while (it1 != end1 || it2 != end2) {
434*9e3b08aeSAndroid Build Coastguard Worker if (it2 == end2 || (it1 != end1 && *it1 < *it2)) {
435*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::QUALIFIER)) {
436*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(QualifiersMessage(*it1, "removed"));
437*9e3b08aeSAndroid Build Coastguard Worker }
438*9e3b08aeSAndroid Build Coastguard Worker ++it1;
439*9e3b08aeSAndroid Build Coastguard Worker } else if (it1 == end1 || (it2 != end2 && *it1 > *it2)) {
440*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::QUALIFIER)) {
441*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(QualifiersMessage(*it2, "added"));
442*9e3b08aeSAndroid Build Coastguard Worker }
443*9e3b08aeSAndroid Build Coastguard Worker ++it2;
444*9e3b08aeSAndroid Build Coastguard Worker } else {
445*9e3b08aeSAndroid Build Coastguard Worker ++it1;
446*9e3b08aeSAndroid Build Coastguard Worker ++it2;
447*9e3b08aeSAndroid Build Coastguard Worker }
448*9e3b08aeSAndroid Build Coastguard Worker }
449*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff = (*this)(unqualified1, unqualified2);
450*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("underlying", type_diff);
451*9e3b08aeSAndroid Build Coastguard Worker } else {
452*9e3b08aeSAndroid Build Coastguard Worker const auto [resolved1, typedefs1] = ResolveTypedefs(graph, unqualified1);
453*9e3b08aeSAndroid Build Coastguard Worker const auto [resolved2, typedefs2] = ResolveTypedefs(graph, unqualified2);
454*9e3b08aeSAndroid Build Coastguard Worker if (unqualified1 != resolved1 || unqualified2 != resolved2) {
455*9e3b08aeSAndroid Build Coastguard Worker // 3.2 Typedef difference.
456*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = !typedefs1.empty() && !typedefs2.empty()
457*9e3b08aeSAndroid Build Coastguard Worker && typedefs1[0] == typedefs2[0];
458*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("resolved", (*this)(resolved1, resolved2));
459*9e3b08aeSAndroid Build Coastguard Worker } else {
460*9e3b08aeSAndroid Build Coastguard Worker // 4. Compare nodes, if possible.
461*9e3b08aeSAndroid Build Coastguard Worker result = graph.Apply2(*this, unqualified1, unqualified2);
462*9e3b08aeSAndroid Build Coastguard Worker }
463*9e3b08aeSAndroid Build Coastguard Worker }
464*9e3b08aeSAndroid Build Coastguard Worker
465*9e3b08aeSAndroid Build Coastguard Worker // 5. Update result and check for a complete Strongly-Connected Component.
466*9e3b08aeSAndroid Build Coastguard Worker const bool same = result.same;
467*9e3b08aeSAndroid Build Coastguard Worker provisional.insert({comparison, result.diff});
468*9e3b08aeSAndroid Build Coastguard Worker const auto comparisons = scc.Close(*handle);
469*9e3b08aeSAndroid Build Coastguard Worker if (comparisons.empty()) {
470*9e3b08aeSAndroid Build Coastguard Worker // Open SCC.
471*9e3b08aeSAndroid Build Coastguard Worker //
472*9e3b08aeSAndroid Build Coastguard Worker // Note that both same and diff are tentative as comparison is still
473*9e3b08aeSAndroid Build Coastguard Worker // open.
474*9e3b08aeSAndroid Build Coastguard Worker return {same, comparison};
475*9e3b08aeSAndroid Build Coastguard Worker }
476*9e3b08aeSAndroid Build Coastguard Worker
477*9e3b08aeSAndroid Build Coastguard Worker // Closed SCC.
478*9e3b08aeSAndroid Build Coastguard Worker //
479*9e3b08aeSAndroid Build Coastguard Worker // Note that result now incorporates every inequality and difference in the
480*9e3b08aeSAndroid Build Coastguard Worker // SCC via the DFS spanning tree.
481*9e3b08aeSAndroid Build Coastguard Worker const auto size = comparisons.size();
482*9e3b08aeSAndroid Build Coastguard Worker scc_size.Add(size);
483*9e3b08aeSAndroid Build Coastguard Worker for (const auto& c : comparisons) {
484*9e3b08aeSAndroid Build Coastguard Worker // Record equality / inequality.
485*9e3b08aeSAndroid Build Coastguard Worker known.insert({c, same});
486*9e3b08aeSAndroid Build Coastguard Worker const auto it = provisional.find(c);
487*9e3b08aeSAndroid Build Coastguard Worker Check(it != provisional.end())
488*9e3b08aeSAndroid Build Coastguard Worker << "internal error: missing provisional diffs";
489*9e3b08aeSAndroid Build Coastguard Worker if (!same) {
490*9e3b08aeSAndroid Build Coastguard Worker // Record differences.
491*9e3b08aeSAndroid Build Coastguard Worker outcomes.insert(*it);
492*9e3b08aeSAndroid Build Coastguard Worker }
493*9e3b08aeSAndroid Build Coastguard Worker provisional.erase(it);
494*9e3b08aeSAndroid Build Coastguard Worker }
495*9e3b08aeSAndroid Build Coastguard Worker (same ? equivalent : inequivalent) += size;
496*9e3b08aeSAndroid Build Coastguard Worker return same
497*9e3b08aeSAndroid Build Coastguard Worker ? std::make_pair(true, Comparison{})
498*9e3b08aeSAndroid Build Coastguard Worker : std::make_pair(false, comparison);
499*9e3b08aeSAndroid Build Coastguard Worker }
500*9e3b08aeSAndroid Build Coastguard Worker
Removedstg::diff::__anon19fbf5d30211::CompareWorker501*9e3b08aeSAndroid Build Coastguard Worker Comparison Removed(Id id) {
502*9e3b08aeSAndroid Build Coastguard Worker Comparison comparison{{id}, {}};
503*9e3b08aeSAndroid Build Coastguard Worker outcomes.insert({comparison, {}});
504*9e3b08aeSAndroid Build Coastguard Worker return comparison;
505*9e3b08aeSAndroid Build Coastguard Worker }
506*9e3b08aeSAndroid Build Coastguard Worker
Addedstg::diff::__anon19fbf5d30211::CompareWorker507*9e3b08aeSAndroid Build Coastguard Worker Comparison Added(Id id) {
508*9e3b08aeSAndroid Build Coastguard Worker Comparison comparison{{}, {id}};
509*9e3b08aeSAndroid Build Coastguard Worker outcomes.insert({comparison, {}});
510*9e3b08aeSAndroid Build Coastguard Worker return comparison;
511*9e3b08aeSAndroid Build Coastguard Worker }
512*9e3b08aeSAndroid Build Coastguard Worker
Definedstg::diff::__anon19fbf5d30211::CompareWorker513*9e3b08aeSAndroid Build Coastguard Worker void Defined(bool defined1, bool defined2, Result& result) {
514*9e3b08aeSAndroid Build Coastguard Worker if (defined1 != defined2) {
515*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::TYPE_DECLARATION_STATUS)
516*9e3b08aeSAndroid Build Coastguard Worker && !(ignore.Test(Ignore::TYPE_DEFINITION_ADDITION) && defined2)) {
517*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
518*9e3b08aeSAndroid Build Coastguard Worker os << "was " << (defined1 ? "fully defined" : "only declared")
519*9e3b08aeSAndroid Build Coastguard Worker << ", is now " << (defined2 ? "fully defined" : "only declared");
520*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(os.str());
521*9e3b08aeSAndroid Build Coastguard Worker }
522*9e3b08aeSAndroid Build Coastguard Worker }
523*9e3b08aeSAndroid Build Coastguard Worker }
524*9e3b08aeSAndroid Build Coastguard Worker
Nodesstg::diff::__anon19fbf5d30211::CompareWorker525*9e3b08aeSAndroid Build Coastguard Worker void Nodes(const std::vector<Id>& ids1, const std::vector<Id>& ids2,
526*9e3b08aeSAndroid Build Coastguard Worker Result& result) {
527*9e3b08aeSAndroid Build Coastguard Worker const auto keys1 = MatchingKeys(graph, ids1);
528*9e3b08aeSAndroid Build Coastguard Worker const auto keys2 = MatchingKeys(graph, ids2);
529*9e3b08aeSAndroid Build Coastguard Worker auto pairs = PairUp(keys1, keys2);
530*9e3b08aeSAndroid Build Coastguard Worker Reorder(pairs);
531*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [index1, index2] : pairs) {
532*9e3b08aeSAndroid Build Coastguard Worker if (index1 && !index2) {
533*9e3b08aeSAndroid Build Coastguard Worker // removed
534*9e3b08aeSAndroid Build Coastguard Worker const auto& x1 = ids1[*index1];
535*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Removed(x1));
536*9e3b08aeSAndroid Build Coastguard Worker } else if (!index1 && index2) {
537*9e3b08aeSAndroid Build Coastguard Worker // added
538*9e3b08aeSAndroid Build Coastguard Worker const auto& x2 = ids2[*index2];
539*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Added(x2));
540*9e3b08aeSAndroid Build Coastguard Worker } else if (index1 && index2) {
541*9e3b08aeSAndroid Build Coastguard Worker // in both
542*9e3b08aeSAndroid Build Coastguard Worker const auto& x1 = ids1[*index1];
543*9e3b08aeSAndroid Build Coastguard Worker const auto& x2 = ids2[*index2];
544*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(x1, x2));
545*9e3b08aeSAndroid Build Coastguard Worker } else {
546*9e3b08aeSAndroid Build Coastguard Worker Die() << "CompareWorker::Nodes: impossible pair";
547*9e3b08aeSAndroid Build Coastguard Worker }
548*9e3b08aeSAndroid Build Coastguard Worker }
549*9e3b08aeSAndroid Build Coastguard Worker }
550*9e3b08aeSAndroid Build Coastguard Worker
Nodesstg::diff::__anon19fbf5d30211::CompareWorker551*9e3b08aeSAndroid Build Coastguard Worker void Nodes(const std::map<std::string, Id>& x1,
552*9e3b08aeSAndroid Build Coastguard Worker const std::map<std::string, Id>& x2,
553*9e3b08aeSAndroid Build Coastguard Worker bool ignore_added, Result& result) {
554*9e3b08aeSAndroid Build Coastguard Worker // Group diffs into removed, added and changed symbols for readability.
555*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> removed;
556*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> added;
557*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::pair<Id, Id>> in_both;
558*9e3b08aeSAndroid Build Coastguard Worker
559*9e3b08aeSAndroid Build Coastguard Worker auto it1 = x1.begin();
560*9e3b08aeSAndroid Build Coastguard Worker auto it2 = x2.begin();
561*9e3b08aeSAndroid Build Coastguard Worker const auto end1 = x1.end();
562*9e3b08aeSAndroid Build Coastguard Worker const auto end2 = x2.end();
563*9e3b08aeSAndroid Build Coastguard Worker while (it1 != end1 || it2 != end2) {
564*9e3b08aeSAndroid Build Coastguard Worker if (it2 == end2 || (it1 != end1 && it1->first < it2->first)) {
565*9e3b08aeSAndroid Build Coastguard Worker // removed
566*9e3b08aeSAndroid Build Coastguard Worker removed.push_back(it1->second);
567*9e3b08aeSAndroid Build Coastguard Worker ++it1;
568*9e3b08aeSAndroid Build Coastguard Worker } else if (it1 == end1 || (it2 != end2 && it1->first > it2->first)) {
569*9e3b08aeSAndroid Build Coastguard Worker // added
570*9e3b08aeSAndroid Build Coastguard Worker if (!ignore_added) {
571*9e3b08aeSAndroid Build Coastguard Worker added.push_back(it2->second);
572*9e3b08aeSAndroid Build Coastguard Worker }
573*9e3b08aeSAndroid Build Coastguard Worker ++it2;
574*9e3b08aeSAndroid Build Coastguard Worker } else {
575*9e3b08aeSAndroid Build Coastguard Worker // in both
576*9e3b08aeSAndroid Build Coastguard Worker in_both.emplace_back(it1->second, it2->second);
577*9e3b08aeSAndroid Build Coastguard Worker ++it1;
578*9e3b08aeSAndroid Build Coastguard Worker ++it2;
579*9e3b08aeSAndroid Build Coastguard Worker }
580*9e3b08aeSAndroid Build Coastguard Worker }
581*9e3b08aeSAndroid Build Coastguard Worker
582*9e3b08aeSAndroid Build Coastguard Worker for (const auto symbol1 : removed) {
583*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Removed(symbol1));
584*9e3b08aeSAndroid Build Coastguard Worker }
585*9e3b08aeSAndroid Build Coastguard Worker for (const auto symbol2 : added) {
586*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Added(symbol2));
587*9e3b08aeSAndroid Build Coastguard Worker }
588*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [symbol1, symbol2] : in_both) {
589*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(symbol1, symbol2));
590*9e3b08aeSAndroid Build Coastguard Worker }
591*9e3b08aeSAndroid Build Coastguard Worker }
592*9e3b08aeSAndroid Build Coastguard Worker
Mismatchstg::diff::__anon19fbf5d30211::CompareWorker593*9e3b08aeSAndroid Build Coastguard Worker Result Mismatch() {
594*9e3b08aeSAndroid Build Coastguard Worker return Result().MarkIncomparable();
595*9e3b08aeSAndroid Build Coastguard Worker }
596*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker597*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Special& x1, const Special& x2) {
598*9e3b08aeSAndroid Build Coastguard Worker Result result;
599*9e3b08aeSAndroid Build Coastguard Worker if (x1.kind != x2.kind) {
600*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
601*9e3b08aeSAndroid Build Coastguard Worker }
602*9e3b08aeSAndroid Build Coastguard Worker return result;
603*9e3b08aeSAndroid Build Coastguard Worker }
604*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker605*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const PointerReference& x1, const PointerReference& x2) {
606*9e3b08aeSAndroid Build Coastguard Worker Result result;
607*9e3b08aeSAndroid Build Coastguard Worker if (x1.kind != x2.kind) {
608*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
609*9e3b08aeSAndroid Build Coastguard Worker }
610*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff = (*this)(x1.pointee_type_id, x2.pointee_type_id);
611*9e3b08aeSAndroid Build Coastguard Worker const char* text = x1.kind == PointerReference::Kind::POINTER
612*9e3b08aeSAndroid Build Coastguard Worker ? "pointed-to" : "referred-to";
613*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff(text, type_diff);
614*9e3b08aeSAndroid Build Coastguard Worker return result;
615*9e3b08aeSAndroid Build Coastguard Worker }
616*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker617*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const PointerToMember& x1, const PointerToMember& x2) {
618*9e3b08aeSAndroid Build Coastguard Worker Result result;
619*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff(
620*9e3b08aeSAndroid Build Coastguard Worker "containing", (*this)(x1.containing_type_id, x2.containing_type_id));
621*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff(
622*9e3b08aeSAndroid Build Coastguard Worker "", (*this)(x1.pointee_type_id, x2.pointee_type_id));
623*9e3b08aeSAndroid Build Coastguard Worker return result;
624*9e3b08aeSAndroid Build Coastguard Worker }
625*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker626*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Typedef&, const Typedef&) {
627*9e3b08aeSAndroid Build Coastguard Worker // Compare will never attempt to directly compare Typedefs.
628*9e3b08aeSAndroid Build Coastguard Worker Die() << "internal error: CompareWorker(Typedef)";
629*9e3b08aeSAndroid Build Coastguard Worker }
630*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker631*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Qualified&, const Qualified&) {
632*9e3b08aeSAndroid Build Coastguard Worker // Compare will never attempt to directly compare Qualifiers.
633*9e3b08aeSAndroid Build Coastguard Worker Die() << "internal error: CompareWorker(Qualified)";
634*9e3b08aeSAndroid Build Coastguard Worker }
635*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker636*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Primitive& x1, const Primitive& x2) {
637*9e3b08aeSAndroid Build Coastguard Worker Result result;
638*9e3b08aeSAndroid Build Coastguard Worker if (x1.name != x2.name) {
639*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
640*9e3b08aeSAndroid Build Coastguard Worker }
641*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = !x1.name.empty();
642*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::PRIMITIVE_TYPE_ENCODING)) {
643*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("encoding", x1.encoding, x2.encoding);
644*9e3b08aeSAndroid Build Coastguard Worker }
645*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("byte size", x1.bytesize, x2.bytesize);
646*9e3b08aeSAndroid Build Coastguard Worker return result;
647*9e3b08aeSAndroid Build Coastguard Worker }
648*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker649*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Array& x1, const Array& x2) {
650*9e3b08aeSAndroid Build Coastguard Worker Result result;
651*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("number of elements",
652*9e3b08aeSAndroid Build Coastguard Worker x1.number_of_elements, x2.number_of_elements);
653*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff = (*this)(x1.element_type_id, x2.element_type_id);
654*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("element", type_diff);
655*9e3b08aeSAndroid Build Coastguard Worker return result;
656*9e3b08aeSAndroid Build Coastguard Worker }
657*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker658*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const BaseClass& x1, const BaseClass& x2) {
659*9e3b08aeSAndroid Build Coastguard Worker Result result;
660*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("inheritance", x1.inheritance, x2.inheritance);
661*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("offset", x1.offset, x2.offset);
662*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
663*9e3b08aeSAndroid Build Coastguard Worker return result;
664*9e3b08aeSAndroid Build Coastguard Worker }
665*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker666*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Method& x1, const Method& x2) {
667*9e3b08aeSAndroid Build Coastguard Worker Result result;
668*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff(
669*9e3b08aeSAndroid Build Coastguard Worker "vtable offset", x1.vtable_offset, x2.vtable_offset);
670*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
671*9e3b08aeSAndroid Build Coastguard Worker return result;
672*9e3b08aeSAndroid Build Coastguard Worker }
673*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker674*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Member& x1, const Member& x2) {
675*9e3b08aeSAndroid Build Coastguard Worker Result result;
676*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("offset", x1.offset, x2.offset);
677*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::MEMBER_SIZE)) {
678*9e3b08aeSAndroid Build Coastguard Worker const bool bitfield1 = x1.bitsize > 0;
679*9e3b08aeSAndroid Build Coastguard Worker const bool bitfield2 = x2.bitsize > 0;
680*9e3b08aeSAndroid Build Coastguard Worker if (bitfield1 != bitfield2) {
681*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
682*9e3b08aeSAndroid Build Coastguard Worker os << "was " << (bitfield1 ? "a bit-field" : "not a bit-field")
683*9e3b08aeSAndroid Build Coastguard Worker << ", is now " << (bitfield2 ? "a bit-field" : "not a bit-field");
684*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(os.str());
685*9e3b08aeSAndroid Build Coastguard Worker } else {
686*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("bit-field size", x1.bitsize, x2.bitsize);
687*9e3b08aeSAndroid Build Coastguard Worker }
688*9e3b08aeSAndroid Build Coastguard Worker }
689*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
690*9e3b08aeSAndroid Build Coastguard Worker return result;
691*9e3b08aeSAndroid Build Coastguard Worker }
692*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker693*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const VariantMember& x1, const VariantMember& x2) {
694*9e3b08aeSAndroid Build Coastguard Worker Result result;
695*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("discriminant", x1.discriminant_value,
696*9e3b08aeSAndroid Build Coastguard Worker x2.discriminant_value);
697*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
698*9e3b08aeSAndroid Build Coastguard Worker return result;
699*9e3b08aeSAndroid Build Coastguard Worker }
700*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker701*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const StructUnion& x1, const StructUnion& x2) {
702*9e3b08aeSAndroid Build Coastguard Worker Result result;
703*9e3b08aeSAndroid Build Coastguard Worker // Compare two anonymous types recursively, not holding diffs.
704*9e3b08aeSAndroid Build Coastguard Worker // Compare two identically named types recursively, holding diffs.
705*9e3b08aeSAndroid Build Coastguard Worker // Everything else treated as distinct. No recursion.
706*9e3b08aeSAndroid Build Coastguard Worker if (x1.kind != x2.kind || x1.name != x2.name) {
707*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
708*9e3b08aeSAndroid Build Coastguard Worker }
709*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = !x1.name.empty();
710*9e3b08aeSAndroid Build Coastguard Worker
711*9e3b08aeSAndroid Build Coastguard Worker const auto& definition1 = x1.definition;
712*9e3b08aeSAndroid Build Coastguard Worker const auto& definition2 = x2.definition;
713*9e3b08aeSAndroid Build Coastguard Worker Defined(definition1.has_value(), definition2.has_value(), result);
714*9e3b08aeSAndroid Build Coastguard Worker
715*9e3b08aeSAndroid Build Coastguard Worker if (definition1.has_value() && definition2.has_value()) {
716*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff(
717*9e3b08aeSAndroid Build Coastguard Worker "byte size", definition1->bytesize, definition2->bytesize);
718*9e3b08aeSAndroid Build Coastguard Worker Nodes(definition1->base_classes, definition2->base_classes, result);
719*9e3b08aeSAndroid Build Coastguard Worker Nodes(definition1->methods, definition2->methods, result);
720*9e3b08aeSAndroid Build Coastguard Worker Nodes(definition1->members, definition2->members, result);
721*9e3b08aeSAndroid Build Coastguard Worker }
722*9e3b08aeSAndroid Build Coastguard Worker
723*9e3b08aeSAndroid Build Coastguard Worker return result;
724*9e3b08aeSAndroid Build Coastguard Worker }
725*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker726*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Enumeration& x1, const Enumeration& x2) {
727*9e3b08aeSAndroid Build Coastguard Worker Result result;
728*9e3b08aeSAndroid Build Coastguard Worker // Compare two anonymous types recursively, not holding diffs.
729*9e3b08aeSAndroid Build Coastguard Worker // Compare two identically named types recursively, holding diffs.
730*9e3b08aeSAndroid Build Coastguard Worker // Everything else treated as distinct. No recursion.
731*9e3b08aeSAndroid Build Coastguard Worker if (x1.name != x2.name) {
732*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
733*9e3b08aeSAndroid Build Coastguard Worker }
734*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = !x1.name.empty();
735*9e3b08aeSAndroid Build Coastguard Worker
736*9e3b08aeSAndroid Build Coastguard Worker const auto& definition1 = x1.definition;
737*9e3b08aeSAndroid Build Coastguard Worker const auto& definition2 = x2.definition;
738*9e3b08aeSAndroid Build Coastguard Worker Defined(definition1.has_value(), definition2.has_value(), result);
739*9e3b08aeSAndroid Build Coastguard Worker
740*9e3b08aeSAndroid Build Coastguard Worker if (definition1.has_value() && definition2.has_value()) {
741*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::ENUM_UNDERLYING_TYPE)) {
742*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff = (*this)(definition1->underlying_type_id,
743*9e3b08aeSAndroid Build Coastguard Worker definition2->underlying_type_id);
744*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("underlying", type_diff);
745*9e3b08aeSAndroid Build Coastguard Worker }
746*9e3b08aeSAndroid Build Coastguard Worker
747*9e3b08aeSAndroid Build Coastguard Worker const auto enums1 = definition1->enumerators;
748*9e3b08aeSAndroid Build Coastguard Worker const auto enums2 = definition2->enumerators;
749*9e3b08aeSAndroid Build Coastguard Worker const auto keys1 = MatchingKeys(enums1);
750*9e3b08aeSAndroid Build Coastguard Worker const auto keys2 = MatchingKeys(enums2);
751*9e3b08aeSAndroid Build Coastguard Worker auto pairs = PairUp(keys1, keys2);
752*9e3b08aeSAndroid Build Coastguard Worker Reorder(pairs);
753*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [index1, index2] : pairs) {
754*9e3b08aeSAndroid Build Coastguard Worker if (index1 && !index2) {
755*9e3b08aeSAndroid Build Coastguard Worker // removed
756*9e3b08aeSAndroid Build Coastguard Worker const auto& enum1 = enums1[*index1];
757*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
758*9e3b08aeSAndroid Build Coastguard Worker os << "enumerator '" << enum1.first
759*9e3b08aeSAndroid Build Coastguard Worker << "' (" << enum1.second << ") was removed";
760*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(os.str());
761*9e3b08aeSAndroid Build Coastguard Worker } else if (!index1 && index2) {
762*9e3b08aeSAndroid Build Coastguard Worker // added
763*9e3b08aeSAndroid Build Coastguard Worker const auto& enum2 = enums2[*index2];
764*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
765*9e3b08aeSAndroid Build Coastguard Worker os << "enumerator '" << enum2.first
766*9e3b08aeSAndroid Build Coastguard Worker << "' (" << enum2.second << ") was added";
767*9e3b08aeSAndroid Build Coastguard Worker result.AddNodeDiff(os.str());
768*9e3b08aeSAndroid Build Coastguard Worker } else if (index1 && index2) {
769*9e3b08aeSAndroid Build Coastguard Worker // in both
770*9e3b08aeSAndroid Build Coastguard Worker const auto& enum1 = enums1[*index1];
771*9e3b08aeSAndroid Build Coastguard Worker const auto& enum2 = enums2[*index2];
772*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff(
773*9e3b08aeSAndroid Build Coastguard Worker [&](std::ostream& os) {
774*9e3b08aeSAndroid Build Coastguard Worker os << "enumerator '" << enum1.first << "' value";
775*9e3b08aeSAndroid Build Coastguard Worker },
776*9e3b08aeSAndroid Build Coastguard Worker enum1.second, enum2.second);
777*9e3b08aeSAndroid Build Coastguard Worker } else {
778*9e3b08aeSAndroid Build Coastguard Worker Die() << "CompareWorker(Enumeration): impossible pair";
779*9e3b08aeSAndroid Build Coastguard Worker }
780*9e3b08aeSAndroid Build Coastguard Worker }
781*9e3b08aeSAndroid Build Coastguard Worker }
782*9e3b08aeSAndroid Build Coastguard Worker
783*9e3b08aeSAndroid Build Coastguard Worker return result;
784*9e3b08aeSAndroid Build Coastguard Worker }
785*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker786*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Variant& x1, const Variant& x2) {
787*9e3b08aeSAndroid Build Coastguard Worker Result result;
788*9e3b08aeSAndroid Build Coastguard Worker // Compare two identically named variants recursively, holding diffs.
789*9e3b08aeSAndroid Build Coastguard Worker // Everything else treated as distinct. No recursion.
790*9e3b08aeSAndroid Build Coastguard Worker if (x1.name != x2.name) {
791*9e3b08aeSAndroid Build Coastguard Worker return result.MarkIncomparable();
792*9e3b08aeSAndroid Build Coastguard Worker }
793*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = true; // Anonymous variants are not allowed.
794*9e3b08aeSAndroid Build Coastguard Worker
795*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("bytesize", x1.bytesize, x2.bytesize);
796*9e3b08aeSAndroid Build Coastguard Worker if (x1.discriminant.has_value() && x2.discriminant.has_value()) {
797*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff =
798*9e3b08aeSAndroid Build Coastguard Worker (*this)(x1.discriminant.value(), x2.discriminant.value());
799*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("discriminant", type_diff);
800*9e3b08aeSAndroid Build Coastguard Worker } else if (x1.discriminant.has_value()) {
801*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Removed(x1.discriminant.value()));
802*9e3b08aeSAndroid Build Coastguard Worker } else if (x2.discriminant.has_value()) {
803*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Added(x2.discriminant.value()));
804*9e3b08aeSAndroid Build Coastguard Worker }
805*9e3b08aeSAndroid Build Coastguard Worker Nodes(x1.members, x2.members, result);
806*9e3b08aeSAndroid Build Coastguard Worker return result;
807*9e3b08aeSAndroid Build Coastguard Worker }
808*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker809*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Function& x1, const Function& x2) {
810*9e3b08aeSAndroid Build Coastguard Worker Result result;
811*9e3b08aeSAndroid Build Coastguard Worker const auto type_diff = (*this)(x1.return_type_id, x2.return_type_id);
812*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("return", type_diff);
813*9e3b08aeSAndroid Build Coastguard Worker
814*9e3b08aeSAndroid Build Coastguard Worker const auto& parameters1 = x1.parameters;
815*9e3b08aeSAndroid Build Coastguard Worker const auto& parameters2 = x2.parameters;
816*9e3b08aeSAndroid Build Coastguard Worker const size_t min = std::min(parameters1.size(), parameters2.size());
817*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < min; ++i) {
818*9e3b08aeSAndroid Build Coastguard Worker const Id p1 = parameters1.at(i);
819*9e3b08aeSAndroid Build Coastguard Worker const Id p2 = parameters2.at(i);
820*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff(
821*9e3b08aeSAndroid Build Coastguard Worker [&](std::ostream& os) {
822*9e3b08aeSAndroid Build Coastguard Worker os << "parameter " << i + 1;
823*9e3b08aeSAndroid Build Coastguard Worker },
824*9e3b08aeSAndroid Build Coastguard Worker (*this)(p1, p2));
825*9e3b08aeSAndroid Build Coastguard Worker }
826*9e3b08aeSAndroid Build Coastguard Worker
827*9e3b08aeSAndroid Build Coastguard Worker const bool added = parameters1.size() < parameters2.size();
828*9e3b08aeSAndroid Build Coastguard Worker const auto& which = added ? x2 : x1;
829*9e3b08aeSAndroid Build Coastguard Worker const auto& parameters = which.parameters;
830*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = min; i < parameters.size(); ++i) {
831*9e3b08aeSAndroid Build Coastguard Worker const Id parameter = parameters.at(i);
832*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
833*9e3b08aeSAndroid Build Coastguard Worker os << "parameter " << i + 1 << " of";
834*9e3b08aeSAndroid Build Coastguard Worker auto diff = added ? Added(parameter) : Removed(parameter);
835*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff(os.str(), diff);
836*9e3b08aeSAndroid Build Coastguard Worker }
837*9e3b08aeSAndroid Build Coastguard Worker
838*9e3b08aeSAndroid Build Coastguard Worker return result;
839*9e3b08aeSAndroid Build Coastguard Worker }
840*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker841*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const ElfSymbol& x1, const ElfSymbol& x2) {
842*9e3b08aeSAndroid Build Coastguard Worker // ELF symbols have a lot of different attributes that can impact ABI
843*9e3b08aeSAndroid Build Coastguard Worker // compatibility and others that either cannot or are subsumed by
844*9e3b08aeSAndroid Build Coastguard Worker // information elsewhere.
845*9e3b08aeSAndroid Build Coastguard Worker //
846*9e3b08aeSAndroid Build Coastguard Worker // Not all attributes are exposed by elf_symbol and fewer still in ABI XML.
847*9e3b08aeSAndroid Build Coastguard Worker //
848*9e3b08aeSAndroid Build Coastguard Worker // name - definitely part of the key
849*9e3b08aeSAndroid Build Coastguard Worker //
850*9e3b08aeSAndroid Build Coastguard Worker // type - (ELF symbol type, not C type) one important distinction here would
851*9e3b08aeSAndroid Build Coastguard Worker // be global vs thread-local variables
852*9e3b08aeSAndroid Build Coastguard Worker //
853*9e3b08aeSAndroid Build Coastguard Worker // section - not exposed (modulo aliasing information) and don't care
854*9e3b08aeSAndroid Build Coastguard Worker //
855*9e3b08aeSAndroid Build Coastguard Worker // value (address, usually) - not exposed (modulo aliasing information) and
856*9e3b08aeSAndroid Build Coastguard Worker // don't care
857*9e3b08aeSAndroid Build Coastguard Worker //
858*9e3b08aeSAndroid Build Coastguard Worker // size - don't care (for variables, subsumed by type information)
859*9e3b08aeSAndroid Build Coastguard Worker //
860*9e3b08aeSAndroid Build Coastguard Worker // binding - global vs weak vs unique vs local
861*9e3b08aeSAndroid Build Coastguard Worker //
862*9e3b08aeSAndroid Build Coastguard Worker // visibility - default > protected > hidden > internal
863*9e3b08aeSAndroid Build Coastguard Worker //
864*9e3b08aeSAndroid Build Coastguard Worker // version / is-default-version - in theory the "hidden" bit (separate from
865*9e3b08aeSAndroid Build Coastguard Worker // hidden and local above) can be set independently of the version, but in
866*9e3b08aeSAndroid Build Coastguard Worker // practice at most one version of given name is non-hidden; version
867*9e3b08aeSAndroid Build Coastguard Worker // (including its presence or absence) is definitely part of the key; we
868*9e3b08aeSAndroid Build Coastguard Worker // should probably treat is-default-version as a non-key attribute
869*9e3b08aeSAndroid Build Coastguard Worker //
870*9e3b08aeSAndroid Build Coastguard Worker // defined - rather fundamental; libabigail currently doesn't track
871*9e3b08aeSAndroid Build Coastguard Worker // undefined symbols but we should obviously be prepared in case it does
872*9e3b08aeSAndroid Build Coastguard Worker
873*9e3b08aeSAndroid Build Coastguard Worker // There are also some externalities which libabigail cares about, which may
874*9e3b08aeSAndroid Build Coastguard Worker // or may not be exposed in the XML
875*9e3b08aeSAndroid Build Coastguard Worker //
876*9e3b08aeSAndroid Build Coastguard Worker // index - don't care
877*9e3b08aeSAndroid Build Coastguard Worker //
878*9e3b08aeSAndroid Build Coastguard Worker // is-common and friends - don't care
879*9e3b08aeSAndroid Build Coastguard Worker //
880*9e3b08aeSAndroid Build Coastguard Worker // aliases - exposed, but we don't really care; however we should see what
881*9e3b08aeSAndroid Build Coastguard Worker // compilers do, if anything, in terms of propagating type information to
882*9e3b08aeSAndroid Build Coastguard Worker // aliases
883*9e3b08aeSAndroid Build Coastguard Worker
884*9e3b08aeSAndroid Build Coastguard Worker // Linux kernel things.
885*9e3b08aeSAndroid Build Coastguard Worker //
886*9e3b08aeSAndroid Build Coastguard Worker // MODVERSIONS CRC - fundamental to ABI compatibility, if present
887*9e3b08aeSAndroid Build Coastguard Worker //
888*9e3b08aeSAndroid Build Coastguard Worker // Symbol namespace - fundamental to ABI compatibility, if present
889*9e3b08aeSAndroid Build Coastguard Worker
890*9e3b08aeSAndroid Build Coastguard Worker Result result;
891*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("name", x1.symbol_name, x2.symbol_name);
892*9e3b08aeSAndroid Build Coastguard Worker
893*9e3b08aeSAndroid Build Coastguard Worker if (x1.version_info && x2.version_info) {
894*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("version", x1.version_info->name,
895*9e3b08aeSAndroid Build Coastguard Worker x2.version_info->name);
896*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("default version", x1.version_info->is_default,
897*9e3b08aeSAndroid Build Coastguard Worker x2.version_info->is_default);
898*9e3b08aeSAndroid Build Coastguard Worker } else {
899*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("has version", x1.version_info.has_value(),
900*9e3b08aeSAndroid Build Coastguard Worker x2.version_info.has_value());
901*9e3b08aeSAndroid Build Coastguard Worker }
902*9e3b08aeSAndroid Build Coastguard Worker
903*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("defined", x1.is_defined, x2.is_defined);
904*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("symbol type", x1.symbol_type, x2.symbol_type);
905*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("binding", x1.binding, x2.binding);
906*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("visibility", x1.visibility, x2.visibility);
907*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::SYMBOL_CRC)) {
908*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("CRC", x1.crc, x2.crc);
909*9e3b08aeSAndroid Build Coastguard Worker }
910*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddNodeDiff("namespace", x1.ns, x2.ns);
911*9e3b08aeSAndroid Build Coastguard Worker
912*9e3b08aeSAndroid Build Coastguard Worker if (x1.type_id && x2.type_id) {
913*9e3b08aeSAndroid Build Coastguard Worker result.MaybeAddEdgeDiff("", (*this)(*x1.type_id, *x2.type_id));
914*9e3b08aeSAndroid Build Coastguard Worker } else if (x1.type_id) {
915*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::SYMBOL_TYPE_PRESENCE)) {
916*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Removed(*x1.type_id));
917*9e3b08aeSAndroid Build Coastguard Worker }
918*9e3b08aeSAndroid Build Coastguard Worker } else if (x2.type_id) {
919*9e3b08aeSAndroid Build Coastguard Worker if (!ignore.Test(Ignore::SYMBOL_TYPE_PRESENCE)) {
920*9e3b08aeSAndroid Build Coastguard Worker result.AddEdgeDiff("", Added(*x2.type_id));
921*9e3b08aeSAndroid Build Coastguard Worker }
922*9e3b08aeSAndroid Build Coastguard Worker } else {
923*9e3b08aeSAndroid Build Coastguard Worker // both types missing, we have nothing to say
924*9e3b08aeSAndroid Build Coastguard Worker }
925*9e3b08aeSAndroid Build Coastguard Worker
926*9e3b08aeSAndroid Build Coastguard Worker return result;
927*9e3b08aeSAndroid Build Coastguard Worker }
928*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::diff::__anon19fbf5d30211::CompareWorker929*9e3b08aeSAndroid Build Coastguard Worker Result operator()(const Interface& x1, const Interface& x2) {
930*9e3b08aeSAndroid Build Coastguard Worker Result result;
931*9e3b08aeSAndroid Build Coastguard Worker result.diff.holds_changes = true;
932*9e3b08aeSAndroid Build Coastguard Worker const bool ignore_added = ignore.Test(Ignore::INTERFACE_ADDITION);
933*9e3b08aeSAndroid Build Coastguard Worker Nodes(x1.symbols, x2.symbols, ignore_added, result);
934*9e3b08aeSAndroid Build Coastguard Worker Nodes(x1.types, x2.types, ignore_added, result);
935*9e3b08aeSAndroid Build Coastguard Worker return result;
936*9e3b08aeSAndroid Build Coastguard Worker }
937*9e3b08aeSAndroid Build Coastguard Worker
938*9e3b08aeSAndroid Build Coastguard Worker const Ignore ignore;
939*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
940*9e3b08aeSAndroid Build Coastguard Worker Outcomes& outcomes;
941*9e3b08aeSAndroid Build Coastguard Worker Outcomes provisional;
942*9e3b08aeSAndroid Build Coastguard Worker std::unordered_map<Comparison, bool, HashComparison> known;
943*9e3b08aeSAndroid Build Coastguard Worker SCC<Comparison, HashComparison> scc;
944*9e3b08aeSAndroid Build Coastguard Worker Counter queried;
945*9e3b08aeSAndroid Build Coastguard Worker Counter already_compared;
946*9e3b08aeSAndroid Build Coastguard Worker Counter being_compared;
947*9e3b08aeSAndroid Build Coastguard Worker Counter really_compared;
948*9e3b08aeSAndroid Build Coastguard Worker Counter equivalent;
949*9e3b08aeSAndroid Build Coastguard Worker Counter inequivalent;
950*9e3b08aeSAndroid Build Coastguard Worker Histogram scc_size;
951*9e3b08aeSAndroid Build Coastguard Worker };
952*9e3b08aeSAndroid Build Coastguard Worker
953*9e3b08aeSAndroid Build Coastguard Worker } // namespace
954*9e3b08aeSAndroid Build Coastguard Worker
ResolveTypedefs(const Graph & graph,Id id)955*9e3b08aeSAndroid Build Coastguard Worker std::pair<Id, std::vector<std::string>> ResolveTypedefs(
956*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph, Id id) {
957*9e3b08aeSAndroid Build Coastguard Worker std::pair<Id, std::vector<std::string>> result = {id, {}};
958*9e3b08aeSAndroid Build Coastguard Worker ResolveTypedef resolve(graph, result.first, result.second);
959*9e3b08aeSAndroid Build Coastguard Worker while (graph.Apply(resolve, result.first)) {}
960*9e3b08aeSAndroid Build Coastguard Worker return result;
961*9e3b08aeSAndroid Build Coastguard Worker }
962*9e3b08aeSAndroid Build Coastguard Worker
Compare(Runtime & runtime,Ignore ignore,const Graph & graph,Id root1,Id root2,Outcomes & outcomes)963*9e3b08aeSAndroid Build Coastguard Worker Comparison Compare(Runtime& runtime, Ignore ignore, const Graph& graph,
964*9e3b08aeSAndroid Build Coastguard Worker Id root1, Id root2, Outcomes& outcomes) {
965*9e3b08aeSAndroid Build Coastguard Worker // The root node (Comparison{{id1}, {id2}}) must be the last node to be
966*9e3b08aeSAndroid Build Coastguard Worker // completely visited by the SCC finder and the SCC finder state must be empty
967*9e3b08aeSAndroid Build Coastguard Worker // on return from this function call. In particular, the returns where the SCC
968*9e3b08aeSAndroid Build Coastguard Worker // is "open" are impossible. The remaining cases (of which one is impossible
969*9e3b08aeSAndroid Build Coastguard Worker // for the root node) both have the same two possible return values:
970*9e3b08aeSAndroid Build Coastguard Worker //
971*9e3b08aeSAndroid Build Coastguard Worker // * (true, Comparison{})
972*9e3b08aeSAndroid Build Coastguard Worker // * (false, Comparison{{id1}, {id2}}
973*9e3b08aeSAndroid Build Coastguard Worker //
974*9e3b08aeSAndroid Build Coastguard Worker // So the invariant value.first == (value.second == Comparison{}) holds and we
975*9e3b08aeSAndroid Build Coastguard Worker // can unambiguously return value.second.
976*9e3b08aeSAndroid Build Coastguard Worker return CompareWorker(runtime, ignore, graph, outcomes)(root1, root2).second;
977*9e3b08aeSAndroid Build Coastguard Worker }
978*9e3b08aeSAndroid Build Coastguard Worker
979*9e3b08aeSAndroid Build Coastguard Worker } // namespace diff
980*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg
981