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-2025 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>
15 ABG_BEGIN_EXPORT_DECLARATIONS
16 
17 #include "abg-hash.h"
18 #include "abg-ir.h"
19 
21 // </headers defining libabigail's API>
22 
23 namespace abigail
24 {
25 
26 namespace 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.
43 static bool
44 char_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.
70 static bool
71 int_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.
98 bool
99 deserialize_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.
137 bool
138 serialize_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.
171 hash_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.
195 hash_t
196 hash(uint64_t v, uint64_t seed)
197 {
198  // THe XXH hashing functions take an array of bytes representing the
199  // value to hash. So let's represent 'v' as a big endian input and
200  // pass it to XXH3_64bits_withSeed.
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 = XXH3_64bits_withSeed(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.
218 hash_t
219 hash(const std::string& str)
220 {
221  hash_t h = XXH3_64bits(str.c_str(), str.size());
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.
240 uint32_t
241 fnv_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  {
266  d = look_through_decl_only(d);
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.
279 void
282 {
283  const type_or_decl_base* todp = &tod;
284  if (decl_base* d = is_decl(todp))
285  {
286  d = look_through_decl_only(d);
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.
301 bool
303 {
304  bool result = false;
305  const type_or_decl_base* tp = &t;
306  if (decl_base* d = is_decl(tp))
307  {
308  d = look_through_decl_only(d);
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.
326 void
328 {
329  const type_or_decl_base* tp = &t;
330  if (decl_base* d = is_decl(tp))
331  {
332  d = look_through_decl_only(d);
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 
340 using std::list;
341 using std::vector;
342 
343 using 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  || hashing::get_hashing_state(type) == hashing::HASHING_SUBTYPE_STATE) \
354  { \
355  hashing::set_hashing_state(t, hashing::HASHING_CYCLED_TYPE_STATE); \
356  hashing::is_recursive_artefact(type, true); \
357  return hash_t(); \
358  } \
359  else if (hashing::get_hashing_state(type) == hashing::HASHING_CYCLED_TYPE_STATE) \
360  return hash_t(); \
361  else if (hashing::get_hashing_state(type) == hashing::HASHING_FINISHED_STATE) \
362  return peek_hash_value(type); \
363  } \
364  while(false)
365 
366 #define MAYBE_FLAG_TYPE_AS_RECURSIVE(type, underlying, h) \
367  do \
368  { \
369  if (!h || hashing::is_recursive_artefact(*underlying)) \
370  hashing::is_recursive_artefact(type, true); \
371  } \
372  while(false)
373 
374 #define MAYBE_RETURN_EARLY_IF_HASH_EXISTS(type) \
375  do \
376  { \
377  if (hashing::get_hashing_state(type) == hashing::HASHING_FINISHED_STATE) \
378  return peek_hash_value(type); \
379  } \
380  while(false)
381 
382 /// The hashing functor for using instances of @ref type_or_decl_base
383 /// as values in a hash map or set.
384 
385 /// Hash function for an instance of @ref type_base.
386 ///
387 /// @param t the type to hash.
388 ///
389 /// @return the type value.
390 hash_t
391 type_base::hash::operator()(const type_base& t) const
392 {
395  return v;
396 }
397 
398 /// Hash function for an instance of @ref type_base.
399 ///
400 /// @param t the type to hash.
401 ///
402 /// @return the type value.
403 hash_t
404 type_base::hash::operator()(const type_base* t) const
405 {return operator()(*t);}
406 
407 /// Hash function for an instance of @ref type_base.
408 ///
409 /// @param t the type to hash.
410 ///
411 /// @return the hash value.
412 hash_t
413 type_base::hash::operator()(const type_base_sptr t) const
414 {return operator()(*t);}
415 
416 /// Hash function for an instance of @ref decl_base.
417 ///
418 /// @param d the decl to hash.
419 ///
420 /// @return the hash value.
421 hash_t
422 decl_base::hash::operator()(const decl_base& d) const
423 {
424  hash_t v = 0;
425 
426  if (!d.get_is_anonymous())
427  {
428  interned_string ln = d.get_name();
429  v = hashing::hash((string) ln);
430  }
431 
432  if (is_member_decl(d))
433  {
436  }
437 
438  return v;
439 }
440 
441 /// Hash function for an instance of @ref decl_base.
442 ///
443 /// @param d the decl to hash.
444 ///
445 /// @return the hash value.
446 hash_t
447 decl_base::hash::operator()(const decl_base* d) const
448 {
449  if (!d)
450  return 0;
451  return operator()(*d);
452 }
453 
454 /// Hashing function for a @ref type_decl IR node.
455 ///
456 /// @param t the @ref type_decl IR node t hash.
457 ///
458 /// @return the resulting hash value.
459 hash_t
460 type_decl::hash::operator()(const type_decl& t) const
461 {
462  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
463 
464  decl_base::hash decl_hash;
465  type_base::hash type_hash;
466 
468 
469  hash_t v = decl_hash(t);
470  v = hashing::combine_hashes(v, type_hash(t));
471 
473 
474  t.set_hash_value(v);
475 
476  return v;
477 }
478 
479 /// Hashing function for a @ref type_decl IR node.
480 ///
481 /// @param t the @ref type_decl IR node to hash.
482 ///
483 /// @return the resulting hash value.
484 hash_t
485 type_decl::hash::operator()(const type_decl* t) const
486 {
487  if (!t)
488  return 0;
489  return operator()(*t);
490 }
491 
492 /// Hashing function for a @ref typedef_decl IR node.
493 ///
494 /// @param t the @ref typedef_decl IR node to hash
495 ///
496 /// @return the resulting hash value.
497 hash_t
498 typedef_decl::hash::operator()(const typedef_decl& t) const
499 {
500  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
501 
503 
504  // The hash value of a typedef is the same as the hash value of its
505  // underlying type.
506  type_base_sptr u = look_through_decl_only_type(t.get_underlying_type());
509  hash_t v = u->hash_value();
511  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
512 
514 
515  return v;
516 }
517 
518 /// Hashing function for a @ref typedef_decl IR node.
519 ///
520 /// @param t the @ref typedef_decl IR node to hash
521 ///
522 /// @return the resulting hash value.
523 hash_t
524 typedef_decl::hash::operator()(const typedef_decl* t) const
525 {
526  if (!t)
527  return 0;
528  return operator()(*t);
529 }
530 
531 /// Hashing function for a @ref qualified_type_def IR node.
532 ///
533 /// @param t the @ref qualified_type_def IR node to hash.
534 ///
535 /// @return the resulting hash value.
536 hash_t
537 qualified_type_def::hash::operator()(const qualified_type_def& t) const
538 {
539  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
540 
541  type_base::hash type_hash;
542  decl_base::hash decl_hash;
543 
545 
546  type_base_sptr u = look_through_decl_only_type(t.get_underlying_type());
549  hash_t v = u->hash_value();
551  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
552  v = hashing::combine_hashes(v, type_hash(t));
553  v = hashing::combine_hashes(v, decl_hash(t));
555 
557 
558  return v;
559 }
560 
561 /// Hashing function for a @ref qualified_type_def IR node.
562 ///
563 /// @param t the @ref qualified_type_def IR node to hash.
564 ///
565 /// @return the resulting hash value.
566 hash_t
567 qualified_type_def::hash::operator()(const qualified_type_def* t) const
568 {
569  if (!t)
570  return 0;
571  return operator()(*t);
572 }
573 
574 /// Hashing function for a @ref pointer_type_def IR node.
575 ///
576 /// @param t the @ref pointer_type_def IR node to hash.
577 ///
578 /// @return the resulting hash value.
579 hash_t
580 pointer_type_def::hash::operator()(const pointer_type_def& t) const
581 {
582  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
583 
584  type_base::hash type_base_hash;
585  decl_base::hash decl_hash;
586 
588 
589  type_base_sptr u = look_through_decl_only_type(t.get_pointed_to_type());
592  hash_t v = u->hash_value();
594  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
595  v = hashing::combine_hashes(v, type_base_hash(t));
596  v = hashing::combine_hashes(v, decl_hash(t));
597 
599 
600  return v;
601 }
602 
603 /// Hashing function for a @ref pointer_type_def IR node.
604 ///
605 /// @param t the @ref pointer_type_def IR node to hash.
606 ///
607 /// @return the resulting hash value.
608 hash_t
609 pointer_type_def::hash::operator()(const pointer_type_def* t) const
610 {
611  if (!t)
612  return 0;
613  return operator()(*t);
614 }
615 
616 /// Hashing function for a @ref reference_type_def IR node.
617 ///
618 /// @param t the @ref reference_type_def IR node to hash.
619 ///
620 /// @return the resulting hash value.
621 hash_t
622 reference_type_def::hash::operator()(const reference_type_def& t) const
623 {
624  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
625 
626  type_base::hash hash_type_base;
627  decl_base::hash hash_decl;
628 
630 
631  type_base_sptr u = look_through_decl_only_type(t.get_pointed_to_type());
634  hash_t v = u->hash_value();
636  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
637  v = hashing::combine_hashes(v, hash_type_base(t));
638  v = hashing::combine_hashes(v, hash_decl(t));
639  v = hashing::combine_hashes(v, hashing::hash(t.is_lvalue()));
640 
642 
643  return v;
644 }
645 
646 /// Hashing function for a @ref reference_type_def IR node.
647 ///
648 /// @param t the @ref reference_type_def IR node to hash.
649 ///
650 /// @return the resulting hash value.
651 hash_t
652 reference_type_def::hash::operator()(const reference_type_def* t) const
653 {
654  if (!t)
655  return 0;
656  return operator()(*t);
657 }
658 
659 /// Hashing function for a @ref array_type_def::subrange_type IR node.
660 ///
661 /// @param t the @ref array_type_def::subrange_type IR node to hash.
662 ///
663 /// @return the resulting hash value.
664 hash_t
665 array_type_def::subrange_type::hash::operator()(const array_type_def::subrange_type& t) const
666 {
668 
672 
674 
675  return v;
676 }
677 
678 /// Hashing function for a @ref array_type_def::subrange_type IR node.
679 ///
680 /// @param t the @ref array_type_def::subrange_type IR node to hash.
681 ///
682 /// @return the resulting hash value.
683 hash_t
684 array_type_def::subrange_type::hash::operator()(const array_type_def::subrange_type* s) const
685 {
686  if (!s)
687  return 0;
688  return operator()(*s);
689 }
690 
691 /// Hashing function for a @ref array_type_def IR node.
692 ///
693 /// @param t the @ref array_type_def IR node to hash.
694 ///
695 /// @return the resulting hash value.
696 hash_t
697 array_type_def::hash::operator()(const array_type_def& t) const
698 {
699  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
700 
701  type_base::hash hash_as_type_base;
702  decl_base::hash hash_as_decl_base;
703 
705 
706  hash_t v = hash_as_type_base(t), h = 0;
707  v = hashing::combine_hashes(v, hash_as_decl_base(t));
708 
709  for (vector<array_type_def::subrange_sptr >::const_iterator i =
710  t.get_subranges().begin();
711  i != t.get_subranges().end();
712  ++i)
713  {
716  h = (*i)->hash_value();
718  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, *i, h);
719  v = hashing::combine_hashes(v, h);
720  }
721 
722  type_base_sptr e = t.get_element_type();
725  h = e->hash_value();
727  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, e, h);
728  v = hashing::combine_hashes(v, h);
729 
731 
732  return v;
733 }
734 
735 /// Hashing function for a @ref array_type_def IR node.
736 ///
737 /// @param t the @ref array_type_def IR node to hash.
738 ///
739 /// @return the resulting hash value.
740 hash_t
741 array_type_def::hash::operator()(const array_type_def* t) const
742 {
743  if (!t)
744  return 0;
745  return operator()(*t);
746 }
747 
748 /// Hashing function for a @ref ptr_to_mbr_type IR node.
749 ///
750 /// @param t the @ref ptr_to_mbr_type IR node to hash.
751 ///
752 /// @return the resulting hash value.
753 hash_t
754 ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type& t) const
755 {
756  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
757 
758  type_base::hash hash_as_type_base;
759  decl_base::hash hash_as_decl_base;
760 
762 
763  hash_t v = hash_as_type_base(t);
764  v = hashing::combine_hashes(v, hash_as_decl_base(t));
765  type_base_sptr e = t.get_member_type();
768  hash_t h = e->hash_value();
770  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, e, h);
771  v = hashing::combine_hashes(v, h);
772 
773  e = t.get_containing_type();
776  h = e->hash_value();
778  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_containing_type(), h);
779  v = hashing::combine_hashes(v, h);
780 
782 
783  return v;
784 }
785 
786 /// Hashing function for a @ref ptr_to_mbr_type IR node.
787 ///
788 /// @param t the @ref ptr_to_mbr_type IR node to hash.
789 ///
790 /// @return the resulting hash value.
791 hash_t
792 ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type* t) const
793 {
794  if (!t)
795  return 0;
796  return operator()(*t);
797 }
798 
799 /// Hashing function for a @ref ptr_to_mbr_type IR node.
800 ///
801 /// @param t the @ref ptr_to_mbr_type IR node to hash.
802 ///
803 /// @return the resulting hash value.
804 hash_t
805 ptr_to_mbr_type::hash::operator() (const ptr_to_mbr_type_sptr& t) const
806 {return operator()(t.get());}
807 
808 /// Hashing function for a @ref enum_type_decl IR node.
809 ///
810 /// @param t the @ref enum_type_decl IR node to hash.
811 ///
812 /// @return the resulting hash value.
813 hash_t
814 enum_type_decl::hash::operator()(const enum_type_decl& t) const
815 {
816  MAYBE_RETURN_EARLY_IF_HASH_EXISTS(t);
817 
819  {
823  hash_t v = e->hash_value();
825  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, e, v);
826  return v;
827  }
828 
829  decl_base::hash hash_as_decl;
830  type_base::hash hash_as_type;
831 
833 
834  hash_t v = hash_as_type(t);
835  v = hashing::combine_hashes(v, hash_as_decl(t));
836 
837  type_base_sptr u = t.get_underlying_type();
840  hash_t h = u->hash_value();
842  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, h);
843  v = hashing::combine_hashes(v, h);
844 
845  for (enum_type_decl::enumerators::const_iterator i =
846  t.get_enumerators().begin();
847  i != t.get_enumerators().end();
848  ++i)
849  {
850  v = hashing::combine_hashes(v, hashing::hash(i->get_name()));
851  v = hashing::combine_hashes(v, hashing::hash(i->get_value()));
852  }
853 
855 
856  return v;
857 }
858 
859 /// Hashing function for a @ref enum_type_decl IR node.
860 ///
861 /// @param t the @ref enum_type_decl IR node to hash.
862 ///
863 /// @return the resulting hash value.
864 hash_t
865 enum_type_decl::hash::operator()(const enum_type_decl* t) const
866 {
867  if (!t)
868  return 0;
869  return operator()(*t);
870 }
871 
872 /// Hashing function for @ref function_type.
873 ///
874 /// @param t the function type to hash.
875 ///
876 /// @return the resulting hash value.
877 hash_t
878 function_type::hash::operator()(const function_type& t) const
879 {
880  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
881 
882  type_base::hash hash_as_type_base;
883 
885 
886  hash_t v = hash_as_type_base(t), h = 0;
887  type_base_sptr r = t.get_return_type();
890  h = r->hash_value();
892  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, r, h);
893  v = hashing::combine_hashes(v, h);
894 
895  for (auto parm = t.get_first_parm();
896  parm != t.get_parameters().end();
897  ++parm)
898  {
899  type_base_sptr parm_type = (*parm)->get_type();
902  h = parm_type->hash_value();
903  hashing::set_hashing_state(*parm_type, s);
904  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, parm_type, h);
905  v = hashing::combine_hashes(v, h);
906  }
907 
909 
910  return v;
911 }
912 
913 /// Hashing function for a pointer to @ref function_type.
914 ///
915 /// @param t the pointer to @ref function_type to hash.
916 ///
917 /// @return the resulting hash value.
918 hash_t
919 function_type::hash::operator()(const function_type* t) const
920 {
921  if (!t)
922  return 0;
923  return operator()(*t);
924 }
925 
926 /// Hashing function for a shared pointer to @ref function_type.
927 ///
928 /// @param t the pointer to @ref function_type to hash.
929 ///
930 /// @return the resulting hash value.
931 hash_t
932 function_type::hash::operator()(const function_type_sptr t) const
933 {return operator()(t.get());}
934 
935 /// Hashing function for a @ref method_type IR node.
936 ///
937 /// @param t the @ref method_type IR node to hash.
938 ///
939 /// @return the resulting hash value.
940 hash_t
941 method_type::hash::operator()(const method_type& t) const
942 {
943  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
944 
945  type_base::hash hash_as_type_base;
946 
948 
949  hash_t v = hash_as_type_base(t), h = 0;
950  type_base_sptr r = t.get_return_type();
953  h = r->hash_value();
955  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_return_type(), h);
956  v = hashing::combine_hashes(v, h);
957 
958  for (auto i = t.get_first_non_implicit_parm();
959  i != t.get_parameters().end();
960  ++i)
961  {
963  type_base_sptr ty = parm->get_type();
966  h = ty->hash_value();
968  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, ty, h);
969  v = hashing::combine_hashes(v, h);
970  }
971 
973 
974  return v;
975 }
976 
977 /// Hashing function for a @ref method_type IR node.
978 ///
979 /// @param t the @ref method_type IR node to hash.
980 ///
981 /// @return the resulting hash value.
982 hash_t
983 method_type::hash::operator()(const method_type* t) const
984 {return operator()(*t);}
985 
986 /// Hashing function for a @ref method_type IR node.
987 ///
988 /// @param t the @ref method_type IR node to hash.
989 ///
990 /// @return the resulting hash value.
991 hash_t
992 method_type::hash::operator()(const method_type_sptr t) const
993 {return operator()(t.get());}
994 
995 /// Hashing function for a @ref member_base IR node.
996 ///
997 /// @param t the @ref member_base IR node to hash.
998 ///
999 /// @return the resulting hash value.
1000 hash_t
1002 {
1003  return hashing::hash(m.get_access_specifier());
1004 }
1005 
1006 /// Hashing function for a @ref class_decl::base_spec IR node.
1007 ///
1008 /// @param t the @ref class_decl::base_spec IR node to hash.
1009 ///
1010 /// @return the resulting hash value.
1011 hash_t
1012 class_decl::base_spec::hash::operator()(const base_spec& t) const
1013 {
1014  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
1015 
1017 
1018  member_base::hash hash_member;
1019 
1020  hash_t v = hash_member(t), h = 0;;
1021  v = hashing::combine_hashes(v, hashing::hash(t.get_offset_in_bits()));
1022  v = hashing::combine_hashes(v, hashing::hash(t.get_is_virtual()));
1023  type_base_sptr b = t.get_base_class();
1026  h = b->hash_value();
1028  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_base_class(), h);
1029  v = hashing::combine_hashes(v, h);
1030 
1032 
1033  return v;
1034 }
1035 
1036 /// Hashing function for a @ref class_decl::base_spec IR node.
1037 ///
1038 /// @param t the @ref class_decl::base_spec IR node to hash.
1039 ///
1040 /// @return the resulting hash value.
1041 hash_t
1042 class_decl::base_spec::hash::operator()(const base_spec* t) const
1043 {
1044  if (!t)
1045  return 0;
1046  return operator()(*t);
1047 }
1048 
1049 /// Compute a hash for a @ref class_or_union
1050 ///
1051 /// @param t the class_or_union for which to compute the hash value.
1052 ///
1053 /// @return the computed hash value.
1054 hash_t
1055 class_or_union::hash::operator()(const class_or_union& t) const
1056 {
1057  // If the type is decl-only and now has a definition, then hash its
1058  // definition instead.
1059 
1061  {
1062  class_or_union_sptr cou = is_class_or_union_type(t.get_definition_of_declaration());
1065  hash_t v = cou->hash_value();
1066  hashing::set_hashing_state(*cou, s);
1067  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, t.get_definition_of_declaration(), v);
1068  return v;
1069  }
1070 
1071  type_base::hash hash_as_type_base;
1072  decl_base::hash hash_as_decl_base;
1073 
1074  hash_t v = hash_as_type_base(t);
1075  v = hashing::combine_hashes(v, hash_as_decl_base(t));
1076 
1077  // Hash data members.
1078  type_base_sptr ty;
1079  for (auto d = t.get_non_static_data_members().begin();
1080  d != t.get_non_static_data_members().end();
1081  ++d)
1082  {
1083  ty = (*d)->get_type();
1086  hash_t h = ty->hash_value();
1088  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, ty, h);
1089  v = hashing::combine_hashes(v, h);
1090  v = hashing::combine_hashes(v, hashing::hash((*d)->get_name()));
1091  }
1092 
1093  return v;
1094 };
1095 
1096 /// Compute a hash for a @ref class_or_union
1097 ///
1098 /// @param t the class_or_union for which to compute the hash value.
1099 ///
1100 /// @return the computed hash value.
1101 hash_t
1102 class_or_union::hash::operator()(const class_or_union *t) const
1103 {return t ? operator()(*t) : 0;}
1104 
1105 /// Compute a hash for a @ref class_decl
1106 ///
1107 /// @param t the class_decl for which to compute the hash value.
1108 ///
1109 /// @return the computed hash value.
1110 hash_t
1111 class_decl::hash::operator()(const class_decl& t) const
1112 {
1113  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
1114 
1115  // If the type is decl-only and now has a definition, then hash its
1116  // definition instead.
1117 
1119  {
1123  hash_t v = c->hash_value();
1125  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, c, v);
1126  return v;
1127  }
1128 
1130 
1131  class_or_union::hash hash_as_class_or_union;
1132 
1133  hash_t v = hash_as_class_or_union(t);
1134 
1135  // Hash bases.
1136  for (auto b = t.get_base_specifiers().begin();
1137  b != t.get_base_specifiers().end();
1138  ++b)
1139  {
1142  hash_t h = (*b)->hash_value();
1144  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, *b, h);
1145  v = hashing::combine_hashes(v, h);
1146  }
1147 
1148 #if 0
1149  // Do not hash (virtual) member functions because in C++ at least,
1150  // due to the function cloning used to implement destructors (and
1151  // maybe other functions in the future) comparing two sets of
1152  // virtual destructors is a bit more involved than what we could
1153  // naively do with by just hashing the virtual member functions.
1154  // You can look at the overload of the equals function for
1155  // class_decl, in abg-ir.cc to see the dance involved in comparing
1156  // virtual member functions. Maybe in the future we can come up
1157  // with a clever way to hash these. For now, let's rely on
1158  // structural comparison to tell the virtual member functions part
1159  // of classes appart.
1160 
1161  // If we were to hash virtual member functions naively, please find
1162  // below what it would look like. Note that it doesn't work in
1163  // practise as it creates spurious self-comparison errors. You
1164  // might want to test it on this command and see for yourself:
1165  //
1166  // fedabipkgdiff --self-compare --from fc37 gcc-gnat
1167 
1168  // Hash virtual member functions.
1169 
1170  // TODO: hash the linkage names of the virtual member functions too.
1171  const_cast<class_decl&>(t).sort_virtual_mem_fns();
1172  for (const auto& method : t.get_virtual_mem_fns())
1173  {
1174  ssize_t voffset = get_member_function_vtable_offset(method);
1175  v = hashing::combine_hashes(v, hashing::hash(voffset));
1176  method_type_sptr method_type = method->get_type();
1177  hash_t h = do_hash_value(method_type);
1178  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, method_type, h);
1179  v = hashing::combine_hashes(v, h);
1180  }
1181 #endif
1182 
1184 
1185  return v;
1186 }
1187 
1188 /// Compute a hash for a @ref class_decl
1189 ///
1190 /// @param t the class_decl for which to compute the hash value.
1191 ///
1192 /// @return the computed hash value.
1193 hash_t
1194 class_decl::hash::operator()(const class_decl* t) const
1195 {return t ? operator()(*t) : 0;}
1196 
1197 /// Hashing function for a @ref union_decl IR node.
1198 ///
1199 /// @param t the @ref union_decl IR node to hash.
1200 ///
1201 /// @return the resulting hash value.
1202 hash_t
1203 union_decl::hash::operator()(const union_decl& t) const
1204 {
1205  MAYBE_RETURN_EARLY_FROM_HASHING_TO_AVOID_CYCLES(t);
1206 
1207  // If the type is decl-only and now has a definition, then hash its
1208  // definition instead.
1209 
1211  {
1212  union_decl_sptr u = is_union_type(t.get_definition_of_declaration());
1215  hash_t v = u->hash_value();
1217  MAYBE_FLAG_TYPE_AS_RECURSIVE(t, u, v);
1218  return v;
1219  }
1220 
1222 
1223  class_or_union::hash hash_as_class_or_union;
1224 
1225  hash_t v = hash_as_class_or_union(t);
1226 
1228 
1229  return v;
1230 }
1231 
1232 /// Hashing function for a @ref union_decl IR node.
1233 ///
1234 /// @param t the @ref union_decl IR node to hash.
1235 ///
1236 /// @return the resulting hash value.
1237 hash_t
1238 union_decl::hash::operator()(const union_decl*t) const
1239 {
1240  if (!t)
1241  return 0;
1242  return operator()(*t);
1243 }
1244 }//end namespace abigail
The abstraction of an array type.
Definition: abg-ir.h:2547
The base type of all declarations.
Definition: abg-ir.h:1584
Hashing started but is not yet finished.
Definition: abg-hash.h:34
hash_t operator()(const member_base &m) const
Hashing function for a member_base IR node.
Definition: abg-hash.cc:1001
parameters::const_iterator get_first_parm() const
Get the first parameter of the function.
Definition: abg-ir.cc:22339
hash_t do_hash_value(const T &tod)
Compute the hash value of an IR node and return it.
Definition: abg-ir-priv.h:341
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:208
An abstraction helper for type declarations.
Definition: abg-ir.h:2002
shared_ptr< method_type > method_type_sptr
Convenience typedef for shared pointer to method_type.
Definition: abg-fwd.h:218
The base class of both types and declarations.
Definition: abg-ir.h:1405
Hasher for the class_or_union type.
Definition: abg-hash.h:249
Abstracts a reference type.
Definition: abg-ir.h:2415
The abstraction of a qualified type.
Definition: abg-ir.h:2235
access_specifier get_member_access_specifier(const decl_base &d)
Gets the access specifier for a class member.
Definition: abg-ir.cc:5515
ssize_t get_member_function_vtable_offset(const function_decl &f)
Get the vtable offset of a member function.
Definition: abg-ir.cc:6578
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
parameters::const_iterator get_first_non_implicit_parm() const
Get the first parameter of the function.
Definition: abg-ir.cc:22317
Abstracts the type of a class member function.
Definition: abg-ir.h:3505
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5417
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:18977
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:11396
Abstracts a class declaration.
Definition: abg-ir.h:4173
virtual const interned_string & get_name() const
Getter for the name of the current decl.
Definition: abg-ir.cc:4811
type_base_sptr get_underlying_type() const
Getter of the underlying type.
Definition: abg-ir.cc:17905
const member_functions & get_virtual_mem_fns() const
Get the virtual member functions of this class.
Definition: abg-ir.cc:25280
CV get_cv_quals() const
Getter of the const/volatile qualifier bit field.
Definition: abg-ir.cc:17886
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
const type_base_sptr & get_member_type() const
Getter of the member type of the current ptr_to_mbr_type.
Definition: abg-ir.cc:18968
access_specifier get_access_specifier() const
Getter for the access specifier of this member.
Definition: abg-ir.h:3859
bool is_recursive_artefact(const type_or_decl_base &t)
Test if an artifact is recursive.
Definition: abg-hash.cc:302
const data_members & get_non_static_data_members() const
Get the non-static data members of this class_or_union.
Definition: abg-ir.cc:24324
Abstracts a declaration for an enum type.
Definition: abg-ir.h:2784
bool get_is_declaration_only() const
Test if a decl_base is a declaration-only decl.
Definition: abg-ir.cc:4996
Toplevel namespace for libabigail.
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:237
No hashing has been done/started.
Definition: abg-hash.h:27
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10747
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:11100
uint32_t fnv_hash(const std::string &str)
Compute a stable string hash.
Definition: abg-hash.cc:241
Abstracts a union type declaration.
Definition: abg-ir.h:4421
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3183
virtual size_t get_size_in_bits() const
Getter for the size of the type.
Definition: abg-ir.cc:16492
The abstraction of a pointer-to-member type.
Definition: abg-ir.h:2483
This contains the private implementation of the suppression engine of libabigail. ...
type_base_sptr get_return_type() const
Getter for the return type of the current instance of function_type.
Definition: abg-ir.cc:22034
const parameters & get_parameters() const
Getter for the set of parameters of the current intance of function_type.
Definition: abg-ir.cc:22051
Types of the main internal representation of libabigail.
The base type of class_decl and union_decl.
Definition: abg-ir.h:3976
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:12027
type_base_sptr get_underlying_type() const
Getter of the underlying type of the typedef.
Definition: abg-ir.cc:21276
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:11967
#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:1743
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
Hash functor for instances of type_base.
Definition: abg-hash.h:110
const std::vector< subrange_sptr > & get_subranges() const
Get the array's subranges.
Definition: abg-ir.cc:20229
int64_t get_upper_bound() const
Getter of the upper bound of the subrange type.
Definition: abg-ir.cc:19422
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11445
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
The abstraction of a pointer type.
Definition: abg-ir.h:2349
A basic type declaration that introduces no scope.
Definition: abg-ir.h:2117
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:172
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
const type_base_sptr get_element_type() const
Getter of the type of an array element.
Definition: abg-ir.cc:20070
Hashing a sub-type while hashing another type.
Definition: abg-hash.h:55
The base class for member types, data members and member functions. Its purpose is mainly to carry th...
Definition: abg-ir.h:3838
const enumerators & get_enumerators() const
Definition: abg-ir.cc:20315
type_base_sptr get_underlying_type() const
Return the underlying type of the enum.
Definition: abg-ir.cc:20310
friend class_decl * is_class_type(const type_or_decl_base *)
Test whether a type is a class.
Definition: abg-ir.cc:11174
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:5575
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4668
Abstraction for an array range type, like in Ada, or just for an array dimension like in C or C++...
Definition: abg-ir.h:2573
The hashing functor for member_base.
Definition: abg-hash.h:242
The abstraction of a typedef declaration.
Definition: abg-ir.h:2934
const type_base_sptr get_pointed_to_type() const
Getter of the pointed-to type.
Definition: abg-ir.cc:18250
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
virtual size_t get_alignment_in_bits() const
Getter for the alignment of the type.
Definition: abg-ir.cc:16506
int64_t get_lower_bound() const
Getter of the lower bound of the subrange type.
Definition: abg-ir.cc:19429
The namespace of the internal representation of ABI artifacts like types and decls.
hashing_state
Enumeration of the different hashing states of an IR node being hashed.
Definition: abg-hash.h:24
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:4973
Abstraction of a function type.
Definition: abg-ir.h:3419
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
const base_specs & get_base_specifiers() const
Get the base specifiers for this class.
Definition: abg-ir.cc:25254