libabigail
abg-hash.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- mode: C++ -*-
3//
4// Copyright (C) 2013-2024 Red Hat, Inc.
5
6/// @file
7
8#include <functional>
9#include <cstring>
10#include <xxhash.h>
11#include "abg-internal.h"
12#include "abg-ir-priv.h"
13
14// <headers defining libabigail's API go under here>
15ABG_BEGIN_EXPORT_DECLARATIONS
16
17#include "abg-hash.h"
18#include "abg-ir.h"
19
20ABG_END_EXPORT_DECLARATIONS
21// </headers defining libabigail's API>
22
23namespace abigail
24{
25
26namespace hashing
27{
28
29/// Read a character representing an hexadecimal digit (from '0' to
30/// 'f' or to 'F'), and return an integer representing the value of
31/// that digit. For instance, for the character '0', the function
32/// returns the integer 0. For the character 'A' (or 'a'), the
33/// function returns the integer 10; for the character 'b' (or 'B')
34/// the function returns the integer 11.
35///
36/// @param c the input character to transform into an integer.
37///
38/// @param integer output value. This is set by the function to the
39/// integer representing the character @p c.
40///
41/// @return true iff @p c is a character representing an hexadecimal
42/// number which value could be set to @p integer.
43static bool
44char_to_int(char c, unsigned char& integer)
45{
46 if (c >= '0' && c <= '9')
47 integer = c - '0';
48 else if (c >= 'a' && c <= 'z')
49 integer = 10 + c - 'a';
50 else if (c >= 'A' && c <= 'Z')
51 integer = 10 + c - 'A';
52 else
53 return false;
54
55 return true;
56}
57
58/// Given an integer value representing an hexadecimal digit (from 0
59/// to F), emit the character value which prints that digit. For the
60/// integer 11, the function returns the character 'b'. For the
61/// integer 10, it returns the character 'a'.
62///
63/// @param integer the input hexadecimal integer digit to take into
64/// account.
65///
66/// @param c the output character representing the digit @p integer.
67///
68/// @return true iff @p integer is a valid hexadecimal digit that
69/// could could be represented by a character @p c.
70static bool
71int_to_char(unsigned char integer, unsigned char& c)
72{
73 if (integer <= 9)
74 c = integer + '0';
75 else if (integer >= 0xA && integer <= 0xF)
76 c = 'a' + (integer - 0xA);
77 else
78 return false;
79
80 return true;
81}
82
83/// Read a string of characters representing a string of hexadecimal
84/// digits which itself represents a hash value that was computed
85/// using the XH64 algorithm from the xxhash project.
86///
87/// That string of digit (characters) is laid out in the "canonical
88/// form" requested by the xxhash project. That form is basically the
89/// hash number, represented in big endian.
90///
91/// @param input the input string of characters to consider.
92///
93/// @param hash the resulting hash value de-serialized from @p input.
94/// This is set by the function iff it returns true.
95///
96/// @return true iff the function could de-serialize the characters
97/// string @p input into the hash value @p hash.
98bool
99deserialize_hash(const string& input, uint64_t& hash)
100{
101 unsigned char byte = 0;
102 string xxh64_canonical_form;
103 for (size_t i = 0; i + 1 < input.size(); i += 2)
104 {
105 unsigned char first_nibble = 0, second_nibble = 0;
106 ABG_ASSERT(char_to_int(input[i], first_nibble));
107 ABG_ASSERT(char_to_int(input[i+1], second_nibble));
108 byte = (first_nibble << 4) | second_nibble;
109 xxh64_canonical_form.push_back(byte);
110 }
111
112 XXH64_canonical_t canonical_hash = {};
113 size_t size = sizeof(canonical_hash.digest);
114 memcpy(canonical_hash.digest,
115 xxh64_canonical_form.c_str(),
116 size);
117 hash = XXH64_hashFromCanonical(&canonical_hash);
118
119 return true;
120}
121
122/// Serialiaze a hash value computed using the XH64 algorithm (from the
123/// xxhash project) into a string of characters representing the
124/// digits of the hash in the canonical form requested by the xxhash
125/// project. That canonical form is basically a big endian
126/// representation of the hexadecimal hash number.
127///
128/// @param hash the hash number to serialize.
129///
130/// @param output the resulting string of characters representing the
131/// hash value @p hash in its serialized form. This is set iff the
132/// function return true.
133///
134/// @return true iff the function could serialize the hash value @p
135/// hash into a serialized form that is set into the output parameter
136/// @p output.
137bool
138serialize_hash(uint64_t hash, string& output)
139{
140 XXH64_canonical_t canonical_output = {};
141 XXH64_canonicalFromHash(&canonical_output, hash);
142 for (unsigned i = 0; i < sizeof(canonical_output.digest); ++i)
143 {
144 unsigned char first_nibble = 0, second_nibble = 0;
145 unsigned char byte = canonical_output.digest[i];
146 first_nibble = (0xf0 & byte) >> 4;
147 second_nibble = 0xf & byte;
148 unsigned char c = 0;
149 int_to_char(first_nibble, c);
150 output.push_back(c);
151 int_to_char(second_nibble, c);
152 output.push_back(c);
153 }
154
155 return true;
156}
157
158// </serialized_hash_type definitions>
159
160/// Combine two hash values to produce a third hash value.
161///
162/// If one of the hash values is empty then the other one is returned,
163/// intact. If the two hash values are empty then an empty hash value
164/// is returned as a result.
165///
166/// @param val1 the first hash value.
167///
168/// @param val2 the second hash value.
169///
170/// @return a combination of the hash values @p val1 and @p val2.
171hash_t
173{
174 hash_t result;
175 if (val1.has_value() && val2.has_value())
176 result = hash(*val2, *val1);
177 else if (val1.has_value())
178 result = *val1;
179 else if (val2.has_value())
180 result = *val2;
181
182 return result;
183}
184
185/// Hash an integer value and combine it with a hash previously
186/// computed.
187///
188/// @param v the value to hash.
189///
190/// @param seed a previous hash value that is to be combined with the
191/// result of hashing @p v. This is can be zero if no previous hash
192/// value is available.
193///
194/// @return the resulting hash value.
195hash_t
196hash(uint64_t v, uint64_t seed)
197{
198 // THe XXH64 function takes an array of bytes representing the value
199 // to hash. So let's represent 'v' as a big endian input and pass
200 // it to XXH64.
201 unsigned char data[sizeof(uint64_t)] = {};
202 uint64_t t = v;
203 size_t data_size = sizeof(data);
204 for (unsigned i = 0; i < data_size; ++i)
205 {
206 data[data_size - i - 1] = t & 0xff;
207 t = t >> 8;
208 }
209 hash_t h = XXH64(data, data_size, seed);
210 return h;
211}
212
213/// Hash a string.
214///
215/// @param str the string to hash.
216///
217/// @return the resulting hash value.
218hash_t
219hash(const std::string& str)
220{
221 hash_t h = XXH64(str.c_str(), str.size(), 0);
222 return h;
223}
224
225/// Compute a stable string hash.
226///
227/// std::hash has no portability or stability guarantees so is
228/// unsuitable where reproducibility is a requirement such as in XML
229/// output.
230///
231/// This is the 32-bit FNV-1a algorithm. The algorithm, reference code
232/// and constants are all unencumbered. It is fast and has reasonable
233/// distribution properties.
234///
235/// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function
236///
237/// @param str the string to hash.
238///
239/// @return an unsigned 32 bit hash value.
241fnv_hash(const std::string& str)
242{
243 const uint32_t prime = 0x01000193;
244 const uint32_t offset_basis = 0x811c9dc5;
245 uint32_t hash = offset_basis;
246 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
247 {
248 uint8_t byte = *i;
249 hash = hash ^ byte;
250 hash = hash * prime;
251 }
252 return hash;
253}
254
255/// Get the hashing state of an IR node.
256///
257/// @param tod the type or decl IR node to get the hashing state for.
258///
259/// @return the hashing state of @p tod.
262{
263 const type_or_decl_base* todp = &tod;
264 if (decl_base *d = is_decl(todp))
265 {
267 return d->type_or_decl_base::priv_->get_hashing_state();
268 }
269 else
270 return tod.priv_->get_hashing_state();
271}
272
273/// Set the hashing state of an IR node.
274///
275/// @param tod the type or decl IR node to set the hashing state for.
276///
277///
278/// @param s the new hashing state to set.
279void
282{
283 const type_or_decl_base* todp = &tod;
284 if (decl_base* d = is_decl(todp))
285 {
287 d->type_or_decl_base::priv_->set_hashing_state(s);
288 }
289 else
290 tod.priv_->set_hashing_state(s);
291}
292
293/// Test if an artifact is recursive.
294///
295/// For now, a recursive artifact is a type that contains a sub-type
296/// that refers to itself.
297///
298/// @param t the artifact to consider.
299///
300/// @return truf iff @p t is recursive.
301bool
303{
304 bool result = false;
305 const type_or_decl_base* tp = &t;
306 if (decl_base* d = is_decl(tp))
307 {
309 result = d->type_or_decl_base::priv_->is_recursive_artefact();
310 }
311 else
312 result = t.type_or_decl_base::priv_->is_recursive_artefact();
313
314 return result;
315}
316
317/// Set the property that flags an artifact as recursive.
318///
319/// For now, a recursive artifact is a type that contains a sub-type
320/// that refers to itself.
321///
322/// @param t the artifact to consider.
323///
324/// @param f the new value of the flag. If true, then the artefact @p
325/// t is considered recursive.
326void
328{
329 const type_or_decl_base* tp = &t;
330 if (decl_base* d = is_decl(tp))
331 {
333 d->type_or_decl_base::priv_->is_recursive_artefact(f);
334 }
335 else
336 t.priv_->is_recursive_artefact(f);
337}
338}//end namespace hashing
339
340using std::list;
341using std::vector;
342
343using namespace abigail::ir;
344
345// See forward declarations in abg-ir.h.
346
347// Definitions.
348
349#define MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(type) \
350 do \
351 { \
352 if (hashing::get_hashing_state(type) == hashing::HASHING_STARTED_STATE) \
353 { \
354 hashing::set_hashing_state(t, hashing::HASHING_CYCLED_TYPE_STATE); \
355 hashing::is_recursive_artefact(type, true); \
356 return hash_t(); \
357 } \
358 else if (hashing::get_hashing_state(type) == hashing::HASHING_CYCLED_TYPE_STATE) \
359 return hash_t(); \
360 else if (hashing::get_hashing_state(type) == hashing::HASHING_FINISHED_STATE) \
361 return peek_hash_value(type); \
362 } \
363 while(false)
364
365#define MAYBE_FLAG_TYPE_AS_RECURSIVE(type, underlying, h) \
366 do \
367 { \
368 if (!h || hashing::is_recursive_artefact(*underlying)) \
369 hashing::is_recursive_artefact(type, true); \
370 } \
371 while(false)
372
373#define MAYBE_RETURN_EARLY_IF_HASH_EXISTS(type) \
374 do \
375 { \
376 if (hashing::get_hashing_state(type) == hashing::HASHING_FINISHED_STATE) \
377 return peek_hash_value(type); \
378 } \
379 while(false)
380
381/// The hashing functor for using instances of @ref type_or_decl_base
382/// as values in a hash map or set.
383
384/// Hash function for an instance of @ref type_base.
385///
386/// @param t the type to hash.
387///
388/// @return the type value.
389hash_t
390type_base::hash::operator()(const type_base& t) const
391{
394 return v;
395}
396
397/// Hash function for an instance of @ref type_base.
398///
399/// @param t the type to hash.
400///
401/// @return the type value.
402hash_t
403type_base::hash::operator()(const type_base* t) const
404{return operator()(*t);}
405
406/// Hash function for an instance of @ref type_base.
407///
408/// @param t the type to hash.
409///
410/// @return the hash value.
411hash_t
412type_base::hash::operator()(const type_base_sptr t) const
413{return operator()(*t);}
414
415/// Hash function for an instance of @ref decl_base.
416///
417/// @param d the decl to hash.
418///
419/// @return the hash value.
420hash_t
421decl_base::hash::operator()(const decl_base& d) const
422{
423 hash_t v = 0;
424
425 if (!d.get_is_anonymous())
426 {
427 interned_string ln = d.get_name();
428 v = hashing::hash((string) ln);
429 }
430
431 if (is_member_decl(d))
432 {
435 }
436
437 return v;
438}
439
440/// Hash function for an instance of @ref decl_base.
441///
442/// @param d the decl to hash.
443///
444/// @return the hash value.
445hash_t
446decl_base::hash::operator()(const decl_base* d) const
447{
448 if (!d)
449 return 0;
450 return operator()(*d);
451}
452
453/// Hashing function for a @ref type_decl IR node.
454///
455/// @param t the @ref type_decl IR node t hash.
456///
457/// @return the resulting hash value.
458hash_t
459type_decl::hash::operator()(const type_decl& t) const
460{
461 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
462
463 decl_base::hash decl_hash;
464 type_base::hash type_hash;
465
467
468 hash_t v = decl_hash(t);
469 v = hashing::combine_hashes(v, type_hash(t));
470
472
473 t.set_hash_value(v);
474
475 return v;
476}
477
478/// Hashing function for a @ref type_decl IR node.
479///
480/// @param t the @ref type_decl IR node to hash.
481///
482/// @return the resulting hash value.
483hash_t
484type_decl::hash::operator()(const type_decl* t) const
485{
486 if (!t)
487 return 0;
488 return operator()(*t);
489}
490
491/// Hashing function for a @ref typedef_decl IR node.
492///
493/// @param t the @ref typedef_decl IR node to hash
494///
495/// @return the resulting hash value.
496hash_t
497typedef_decl::hash::operator()(const typedef_decl& t) const
498{
499 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
500
502
503 // The hash value of a typedef is the same as the hash value of its
504 // underlying type.
505 type_base_sptr u = look_through_decl_only_type(t.get_underlying_type());
506 hash_t v = do_hash_value(u);
507 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
508
510
511 return v;
512}
513
514/// Hashing function for a @ref typedef_decl IR node.
515///
516/// @param t the @ref typedef_decl IR node to hash
517///
518/// @return the resulting hash value.
519hash_t
520typedef_decl::hash::operator()(const typedef_decl* t) const
521{
522 if (!t)
523 return 0;
524 return operator()(*t);
525}
526
527/// Hashing function for a @ref qualified_type_def IR node.
528///
529/// @param t the @ref qualified_type_def IR node to hash.
530///
531/// @return the resulting hash value.
532hash_t
533qualified_type_def::hash::operator()(const qualified_type_def& t) const
534{
535 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
536
537 type_base::hash type_hash;
538 decl_base::hash decl_hash;
539
541
542 type_base_sptr u = look_through_decl_only_type(t.get_underlying_type());
543 hash_t v = do_hash_value(u);
544 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
545 v = hashing::combine_hashes(v, type_hash(t));
546 v = hashing::combine_hashes(v, decl_hash(t));
548
550
551 return v;
552}
553
554/// Hashing function for a @ref qualified_type_def IR node.
555///
556/// @param t the @ref qualified_type_def IR node to hash.
557///
558/// @return the resulting hash value.
559hash_t
560qualified_type_def::hash::operator()(const qualified_type_def* t) const
561{
562 if (!t)
563 return 0;
564 return operator()(*t);
565}
566
567/// Hashing function for a @ref pointer_type_def IR node.
568///
569/// @param t the @ref pointer_type_def IR node to hash.
570///
571/// @return the resulting hash value.
572hash_t
573pointer_type_def::hash::operator()(const pointer_type_def& t) const
574{
575 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
576
577 type_base::hash type_base_hash;
578 decl_base::hash decl_hash;
579
581
582 type_base_sptr u = look_through_decl_only_type(t.get_pointed_to_type());
583 hash_t v = do_hash_value(u);
584 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
585 v = hashing::combine_hashes(v, type_base_hash(t));
586 v = hashing::combine_hashes(v, decl_hash(t));
587
589
590 return v;
591}
592
593/// Hashing function for a @ref pointer_type_def IR node.
594///
595/// @param t the @ref pointer_type_def IR node to hash.
596///
597/// @return the resulting hash value.
598hash_t
599pointer_type_def::hash::operator()(const pointer_type_def* t) const
600{
601 if (!t)
602 return 0;
603 return operator()(*t);
604}
605
606/// Hashing function for a @ref reference_type_def IR node.
607///
608/// @param t the @ref reference_type_def IR node to hash.
609///
610/// @return the resulting hash value.
611hash_t
612reference_type_def::hash::operator()(const reference_type_def& t) const
613{
614 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
615
616 type_base::hash hash_type_base;
617 decl_base::hash hash_decl;
618
620
621 type_base_sptr u = look_through_decl_only_type(t.get_pointed_to_type());
622 hash_t v = do_hash_value(u);
623 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
624 v = hashing::combine_hashes(v, hash_type_base(t));
625 v = hashing::combine_hashes(v, hash_decl(t));
626 v = hashing::combine_hashes(v, hashing::hash(t.is_lvalue()));
627
629
630 return v;
631}
632
633/// Hashing function for a @ref reference_type_def IR node.
634///
635/// @param t the @ref reference_type_def IR node to hash.
636///
637/// @return the resulting hash value.
638hash_t
639reference_type_def::hash::operator()(const reference_type_def* t) const
640{
641 if (!t)
642 return 0;
643 return operator()(*t);
644}
645
646/// Hashing function for a @ref array_type_def::subrange_type IR node.
647///
648/// @param t the @ref array_type_def::subrange_type IR node to hash.
649///
650/// @return the resulting hash value.
651hash_t
652array_type_def::subrange_type::hash::operator()(const array_type_def::subrange_type& t) const
653{
655
659
661
662 return v;
663}
664
665/// Hashing function for a @ref array_type_def::subrange_type IR node.
666///
667/// @param t the @ref array_type_def::subrange_type IR node to hash.
668///
669/// @return the resulting hash value.
670hash_t
671array_type_def::subrange_type::hash::operator()(const array_type_def::subrange_type* s) const
672{
673 if (!s)
674 return 0;
675 return operator()(*s);
676}
677
678/// Hashing function for a @ref array_type_def IR node.
679///
680/// @param t the @ref array_type_def IR node to hash.
681///
682/// @return the resulting hash value.
683hash_t
684array_type_def::hash::operator()(const array_type_def& t) const
685{
686 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
687
688 type_base::hash hash_as_type_base;
689 decl_base::hash hash_as_decl_base;
690
692
693 hash_t v = hash_as_type_base(t), h = 0;
694 v = hashing::combine_hashes(v, hash_as_decl_base(t));
695
696 for (vector<array_type_def::subrange_sptr >::const_iterator i =
697 t.get_subranges().begin();
698 i != t.get_subranges().end();
699 ++i)
700 {
701 h = do_hash_value(*i);
702 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, *i, h);
703 v = hashing::combine_hashes(v, h);
704 }
705
707 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_element_type(), h);
708 v = hashing::combine_hashes(v, h);
709
711
712 return v;
713}
714
715/// Hashing function for a @ref array_type_def IR node.
716///
717/// @param t the @ref array_type_def IR node to hash.
718///
719/// @return the resulting hash value.
720hash_t
721array_type_def::hash::operator()(const array_type_def* t) const
722{
723 if (!t)
724 return 0;
725 return operator()(*t);
726}
727
728/// Hashing function for a @ref ptr_to_mbr_type IR node.
729///
730/// @param t the @ref ptr_to_mbr_type IR node to hash.
731///
732/// @return the resulting hash value.
733hash_t
734ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type& t) const
735{
736 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
737
738 type_base::hash hash_as_type_base;
739 decl_base::hash hash_as_decl_base;
740
742
743 hash_t v = hash_as_type_base(t);
744 v = hashing::combine_hashes(v, hash_as_decl_base(t));
746 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_member_type(), h);
747 v = hashing::combine_hashes(v, h);
749 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_containing_type(), h);
750 v = hashing::combine_hashes(v, h);
751
753
754 return v;
755}
756
757/// Hashing function for a @ref ptr_to_mbr_type IR node.
758///
759/// @param t the @ref ptr_to_mbr_type IR node to hash.
760///
761/// @return the resulting hash value.
762hash_t
763ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type* t) const
764{
765 if (!t)
766 return 0;
767 return operator()(*t);
768}
769
770/// Hashing function for a @ref ptr_to_mbr_type IR node.
771///
772/// @param t the @ref ptr_to_mbr_type IR node to hash.
773///
774/// @return the resulting hash value.
775hash_t
776ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type_sptr& t) const
777{return operator()(t.get());}
778
779/// Hashing function for a @ref enum_type_decl IR node.
780///
781/// @param t the @ref enum_type_decl IR node to hash.
782///
783/// @return the resulting hash value.
784hash_t
785enum_type_decl::hash::operator()(const enum_type_decl& t) const
786{
787 MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
788
790 {
792 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_definition_of_declaration(), v);
793 return v;
794 }
795
796 decl_base::hash hash_as_decl;
797 type_base::hash hash_as_type;
798
800
801 hash_t v = hash_as_type(t);
802 v = hashing::combine_hashes(v, hash_as_decl(t));
803
805 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_underlying_type(), h);
806 v = hashing::combine_hashes(v, h);
807
808 for (enum_type_decl::enumerators::const_iterator i =
809 t.get_enumerators().begin();
810 i != t.get_enumerators().end();
811 ++i)
812 {
813 v = hashing::combine_hashes(v, hashing::hash(i->get_name()));
814 v = hashing::combine_hashes(v, hashing::hash(i->get_value()));
815 }
816
818
819 return v;
820}
821
822/// Hashing function for a @ref enum_type_decl IR node.
823///
824/// @param t the @ref enum_type_decl IR node to hash.
825///
826/// @return the resulting hash value.
827hash_t
828enum_type_decl::hash::operator()(const enum_type_decl* t) const
829{
830 if (!t)
831 return 0;
832 return operator()(*t);
833}
834
835/// Hashing function for @ref function_type.
836///
837/// @param t the function type to hash.
838///
839/// @return the resulting hash value.
840hash_t
841function_type::hash::operator()(const function_type& t) const
842{
843 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
844
845 type_base::hash hash_as_type_base;
846
848
849 hash_t v = hash_as_type_base(t), h = 0;
851 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_return_type(), h);
852 v = hashing::combine_hashes(v, h);
853
854 for (auto parm = t.get_first_parm();
855 parm != t.get_parameters().end();
856 ++parm)
857 {
858 type_base_sptr parm_type = (*parm)->get_type();
859 h = do_hash_value(parm_type);
860 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, parm_type, h);
861 v = hashing::combine_hashes(v, h);
862 }
863
865
866 return v;
867}
868
869/// Hashing function for a pointer to @ref function_type.
870///
871/// @param t the pointer to @ref function_type to hash.
872///
873/// @return the resulting hash value.
874hash_t
875function_type::hash::operator()(const function_type* t) const
876{
877 if (!t)
878 return 0;
879 return operator()(*t);
880}
881
882/// Hashing function for a shared pointer to @ref function_type.
883///
884/// @param t the pointer to @ref function_type to hash.
885///
886/// @return the resulting hash value.
887hash_t
888function_type::hash::operator()(const function_type_sptr t) const
889{return operator()(t.get());}
890
891/// Hashing function for a @ref method_type IR node.
892///
893/// @param t the @ref method_type IR node to hash.
894///
895/// @return the resulting hash value.
896hash_t
897method_type::hash::operator()(const method_type& t) const
898{
899 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
900
901 type_base::hash hash_as_type_base;
902
904
905 hash_t v = hash_as_type_base(t), h = 0;
907 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_return_type(), h);
908 v = hashing::combine_hashes(v, h);
909
910 for (auto i = t.get_first_non_implicit_parm();
911 i != t.get_parameters().end();
912 ++i)
913 {
915 h = do_hash_value(parm->get_type());
916 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, parm->get_type(), h);
917 v = hashing::combine_hashes(v, h);
918 }
919
921
922 return v;
923}
924
925/// Hashing function for a @ref method_type IR node.
926///
927/// @param t the @ref method_type IR node to hash.
928///
929/// @return the resulting hash value.
930hash_t
931method_type::hash::operator()(const method_type* t) const
932{return operator()(*t);}
933
934/// Hashing function for a @ref method_type IR node.
935///
936/// @param t the @ref method_type IR node to hash.
937///
938/// @return the resulting hash value.
939hash_t
940method_type::hash::operator()(const method_type_sptr t) const
941{return operator()(t.get());}
942
943/// Hashing function for a @ref member_base IR node.
944///
945/// @param t the @ref member_base IR node to hash.
946///
947/// @return the resulting hash value.
948hash_t
949member_base::hash::operator()(const member_base& m) const
950{
952}
953
954/// Hashing function for a @ref class_decl::base_spec IR node.
955///
956/// @param t the @ref class_decl::base_spec IR node to hash.
957///
958/// @return the resulting hash value.
959hash_t
960class_decl::base_spec::hash::operator()(const base_spec& t) const
961{
962 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
963
965
966 member_base::hash hash_member;
967
968 hash_t v = hash_member(t), h = 0;;
972 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_base_class(), h);
973 v = hashing::combine_hashes(v, h);
974
976
977 return v;
978}
979
980/// Hashing function for a @ref class_decl::base_spec IR node.
981///
982/// @param t the @ref class_decl::base_spec IR node to hash.
983///
984/// @return the resulting hash value.
985hash_t
986class_decl::base_spec::hash::operator()(const base_spec* t) const
987{
988 if (!t)
989 return 0;
990 return operator()(*t);
991}
992
993/// Compute a hash for a @ref class_or_union
994///
995/// @param t the class_or_union for which to compute the hash value.
996///
997/// @return the computed hash value.
998hash_t
999class_or_union::hash::operator()(const class_or_union& t) const
1000{
1001 // If the type is decl-only and now has a definition, then hash its
1002 // definition instead.
1003
1005 {
1007 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_definition_of_declaration(), v);
1008 return v;
1009 }
1010
1011 type_base::hash hash_as_type_base;
1012 decl_base::hash hash_as_decl_base;
1013
1014 hash_t v = hash_as_type_base(t);
1015 v = hashing::combine_hashes(v, hash_as_decl_base(t));
1016
1017 // Hash data members.
1018 for (auto d = t.get_non_static_data_members().begin();
1019 d != t.get_non_static_data_members().end();
1020 ++d)
1021 {
1022 hash_t h = do_hash_value((*d)->get_type());
1023 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, (*d)->get_type(), h);
1024 v = hashing::combine_hashes(v, h);
1025 v = hashing::combine_hashes(v, hashing::hash((*d)->get_name()));
1026 }
1027
1028 return v;
1029};
1030
1031/// Compute a hash for a @ref class_or_union
1032///
1033/// @param t the class_or_union for which to compute the hash value.
1034///
1035/// @return the computed hash value.
1036hash_t
1037class_or_union::hash::operator()(const class_or_union *t) const
1038{return t ? operator()(*t) : 0;}
1039
1040/// Compute a hash for a @ref class_decl
1041///
1042/// @param t the class_decl for which to compute the hash value.
1043///
1044/// @return the computed hash value.
1045hash_t
1046class_decl::hash::operator()(const class_decl& t) const
1047{
1048 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
1049
1050 // If the type is decl-only and now has a definition, then hash its
1051 // definition instead.
1052
1054 {
1056 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_definition_of_declaration(), v);
1057 return v;
1058 }
1059
1061
1062 class_or_union::hash hash_as_class_or_union;
1063
1064 hash_t v = hash_as_class_or_union(t);
1065
1066 // Hash bases.
1067 for (auto b = t.get_base_specifiers().begin();
1068 b != t.get_base_specifiers().end();
1069 ++b)
1070 {
1071 hash_t h = do_hash_value((*b));
1072 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, *b, h);
1073 v = hashing::combine_hashes(v, h);
1074 }
1075
1076#if 0
1077 // Do not hash (virtual) member functions because in C++ at least,
1078 // due to the function cloning used to implement destructors (and
1079 // maybe other functions in the future) comparing two sets of
1080 // virtual destructors is a bit more involved than what we could
1081 // naively do with by just hashing the virtual member functions.
1082 // You can look at the overload of the equals function for
1083 // class_decl, in abg-ir.cc to see the dance involved in comparing
1084 // virtual member functions. Maybe in the future we can come up
1085 // with a clever way to hash these. For now, let's rely on
1086 // structural comparison to tell the virtual member functions part
1087 // of classes appart.
1088
1089 // If we were to hash virtual member functions naively, please find
1090 // below what it would look like. Note that it doesn't work in
1091 // practise as it creates spurious self-comparison errors. You
1092 // might want to test it on this command and see for yourself:
1093 //
1094 // fedabipkgdiff --self-compare --from fc37 gcc-gnat
1095
1096 // Hash virtual member functions.
1097
1098 // TODO: hash the linkage names of the virtual member functions too.
1099 const_cast<class_decl&>(t).sort_virtual_mem_fns();
1100 for (const auto& method : t.get_virtual_mem_fns())
1101 {
1102 ssize_t voffset = get_member_function_vtable_offset(method);
1103 v = hashing::combine_hashes(v, hashing::hash(voffset));
1104 method_type_sptr method_type = method->get_type();
1106 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, method_type, h);
1107 v = hashing::combine_hashes(v, h);
1108 }
1109#endif
1110
1112
1113 return v;
1114}
1115
1116/// Compute a hash for a @ref class_decl
1117///
1118/// @param t the class_decl for which to compute the hash value.
1119///
1120/// @return the computed hash value.
1121hash_t
1122class_decl::hash::operator()(const class_decl* t) const
1123{return t ? operator()(*t) : 0;}
1124
1125/// Hashing function for a @ref union_decl IR node.
1126///
1127/// @param t the @ref union_decl IR node to hash.
1128///
1129/// @return the resulting hash value.
1130hash_t
1131union_decl::hash::operator()(const union_decl& t) const
1132{
1133 MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
1134
1135 // If the type is decl-only and now has a definition, then hash its
1136 // definition instead.
1137
1139 {
1141 MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_definition_of_declaration(), v);
1142 return v;
1143 }
1144
1146
1147 class_or_union::hash hash_as_class_or_union;
1148
1149 hash_t v = hash_as_class_or_union(t);
1150
1152
1153 return v;
1154}
1155
1156/// Hashing function for a @ref union_decl IR node.
1157///
1158/// @param t the @ref union_decl IR node to hash.
1159///
1160/// @return the resulting hash value.
1161hash_t
1162union_decl::hash::operator()(const union_decl*t) const
1163{
1164 if (!t)
1165 return 0;
1166 return operator()(*t);
1167}
1168}//end namespace abigail
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition: abg-fwd.h:1718
This contains the private implementation of the suppression engine of libabigail.
Types of the main internal representation of libabigail.
The abstraction of an interned string.
Abstraction for an array range type, like in Ada, or just for an array dimension like in C or C++.
Definition: abg-ir.h:2545
int64_t get_upper_bound() const
Getter of the upper bound of the subrange type.
Definition: abg-ir.cc:19020
int64_t get_lower_bound() const
Getter of the lower bound of the subrange type.
Definition: abg-ir.cc:19027
The abstraction of an array type.
Definition: abg-ir.h:2519
const type_base_sptr get_element_type() const
Getter of the type of an array element.
Definition: abg-ir.cc:19602
const std::vector< subrange_sptr > & get_subranges() const
Get the array's subranges.
Definition: abg-ir.cc:19761
Abstraction of a base specifier in a class declaration.
Definition: abg-ir.h:4314
class_decl_sptr get_base_class() const
Get the base class referred to by the current base class specifier.
Definition: abg-ir.cc:24855
bool get_is_virtual() const
Getter of the "is-virtual" proprerty of the base class specifier.
Definition: abg-ir.cc:24862
long get_offset_in_bits() const
Getter of the offset of the base.
Definition: abg-ir.cc:24869
Abstracts a class declaration.
Definition: abg-ir.h:4127
const base_specs & get_base_specifiers() const
Get the base specifiers for this class.
Definition: abg-ir.cc:24676
const member_functions & get_virtual_mem_fns() const
Get the virtual member functions of this class.
Definition: abg-ir.cc:24702
The base type of class_decl and union_decl.
Definition: abg-ir.h:3929
const data_members & get_non_static_data_members() const
Get the non-static data members of this class_or_union.
Definition: abg-ir.cc:23810
The base type of all declarations.
Definition: abg-ir.h:1556
virtual const interned_string & get_name() const
Getter for the name of the current decl.
Definition: abg-ir.cc:4635
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4492
const decl_base_sptr get_definition_of_declaration() const
If this decl_base is declaration-only, get its definition, if any.
Definition: abg-ir.cc:4797
bool get_is_declaration_only() const
Test if a decl_base is a declaration-only decl.
Definition: abg-ir.cc:4820
Abstracts a declaration for an enum type.
Definition: abg-ir.h:2756
const enumerators & get_enumerators() const
Definition: abg-ir.cc:19847
type_base_sptr get_underlying_type() const
Return the underlying type of the enum.
Definition: abg-ir.cc:19842
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3139
Abstraction of a function type.
Definition: abg-ir.h:3372
parameters::const_iterator get_first_parm() const
Get the first parameter of the function.
Definition: abg-ir.cc:21825
type_base_sptr get_return_type() const
Getter for the return type of the current instance of function_type.
Definition: abg-ir.cc:21520
parameters::const_iterator get_first_non_implicit_parm() const
Get the first parameter of the function.
Definition: abg-ir.cc:21803
const parameters & get_parameters() const
Getter for the set of parameters of the current intance of function_type.
Definition: abg-ir.cc:21537
The base class for member types, data members and member functions. Its purpose is mainly to carry th...
Definition: abg-ir.h:3791
access_specifier get_access_specifier() const
Getter for the access specifier of this member.
Definition: abg-ir.h:3811
Abstracts the type of a class member function.
Definition: abg-ir.h:3458
The abstraction of a pointer type.
Definition: abg-ir.h:2321
const type_base_sptr get_pointed_to_type() const
Getter of the pointed-to type.
Definition: abg-ir.cc:17842
The abstraction of a pointer-to-member type.
Definition: abg-ir.h:2456
const type_base_sptr & get_containing_type() const
Getter of the type containing the member pointed-to by the current ptr_to_mbr_type.
Definition: abg-ir.cc:18575
const type_base_sptr & get_member_type() const
Getter of the member type of the current ptr_to_mbr_type.
Definition: abg-ir.cc:18566
The abstraction of a qualified type.
Definition: abg-ir.h:2207
CV get_cv_quals() const
Getter of the const/volatile qualifier bit field.
Definition: abg-ir.cc:17473
type_base_sptr get_underlying_type() const
Getter of the underlying type.
Definition: abg-ir.cc:17492
Abstracts a reference type.
Definition: abg-ir.h:2387
An abstraction helper for type declarations.
Definition: abg-ir.h:1974
virtual size_t get_size_in_bits() const
Getter for the size of the type.
Definition: abg-ir.cc:16079
virtual size_t get_alignment_in_bits() const
Getter for the alignment of the type.
Definition: abg-ir.cc:16093
A basic type declaration that introduces no scope.
Definition: abg-ir.h:2089
The base class of both types and declarations.
Definition: abg-ir.h:1377
The abstraction of a typedef declaration.
Definition: abg-ir.h:2898
type_base_sptr get_underlying_type() const
Getter of the underlying type of the typedef.
Definition: abg-ir.cc:20760
Abstracts a union type declaration.
Definition: abg-ir.h:4372
hash_t combine_hashes(hash_t val1, hash_t val2)
Combine two hash values to produce a third hash value.
Definition: abg-hash.cc:172
hashing::hashing_state get_hashing_state(const type_or_decl_base &tod)
Get the hashing state of an IR node.
Definition: abg-hash.cc:261
void set_hashing_state(const type_or_decl_base &tod, hashing::hashing_state s)
Set the hashing state of an IR node.
Definition: abg-hash.cc:280
hash_t hash(uint64_t v, uint64_t seed)
Hash an integer value and combine it with a hash previously computed.
Definition: abg-hash.cc:196
hashing_state
Enumeration of the different hashing states of an IR node being hashed.
Definition: abg-hash.h:25
@ HASHING_STARTED_STATE
Hashing started but is not yet finished.
Definition: abg-hash.h:30
@ HASHING_NOT_DONE_STATE
No hashing has been done/started.
Definition: abg-hash.h:27
bool deserialize_hash(const string &input, uint64_t &hash)
Read a string of characters representing a string of hexadecimal digits which itself represents a has...
Definition: abg-hash.cc:99
bool serialize_hash(uint64_t hash, string &output)
Serialiaze a hash value computed using the XH64 algorithm (from the xxhash project) into a string of ...
Definition: abg-hash.cc:138
uint32_t fnv_hash(const std::string &str)
Compute a stable string hash.
Definition: abg-hash.cc:241
bool is_recursive_artefact(const type_or_decl_base &t)
Test if an artifact is recursive.
Definition: abg-hash.cc:302
The namespace of the internal representation of ABI artifacts like types and decls.
shared_ptr< method_type > method_type_sptr
Convenience typedef for shared pointer to method_type.
Definition: abg-fwd.h:221
bool get_member_is_static(const decl_base &d)
Gets a flag saying if a class member is static or not.
Definition: abg-ir.cc:5399
ssize_t get_member_function_vtable_offset(const function_decl &f)
Get the vtable offset of a member function.
Definition: abg-ir.cc:6402
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10760
class_or_union * is_class_or_union_type(const type_or_decl_base *t)
Test if a type is a class_or_union.
Definition: abg-ir.cc:10991
type_base * look_through_decl_only_type(type_base *t)
If a type is is decl-only, then get its definition. Otherwise, just return the initial type.
Definition: abg-ir.cc:11622
decl_base_sptr look_through_decl_only(const decl_base &d)
If a decl is decl-only get its definition. Otherwise, just return nil.
Definition: abg-ir.cc:11562
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:210
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition: abg-ir.cc:10710
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition: abg-fwd.h:239
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10374
access_specifier get_member_access_specifier(const decl_base &d)
Gets the access specifier for a class member.
Definition: abg-ir.cc:5339
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11040
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5241
hash_t do_hash_value(const T &tod)
Compute the hash value of an IR node and return it.
Definition: abg-ir-priv.h:339
Toplevel namespace for libabigail.
Hasher for the class_or_union type.
Definition: abg-hash.h:230
The hashing functor for member_base.
Definition: abg-hash.h:223
Hash functor for instances of type_base.
Definition: abg-hash.h:91