1039 lines
29 KiB
C++
1039 lines
29 KiB
C++
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
// -*- mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2013-2020 Red Hat, Inc.
|
|
|
|
/// @file
|
|
|
|
#include <functional>
|
|
#include "abg-internal.h"
|
|
// <headers defining libabigail's API go under here>
|
|
ABG_BEGIN_EXPORT_DECLARATIONS
|
|
|
|
#include "abg-hash.h"
|
|
#include "abg-ir.h"
|
|
|
|
ABG_END_EXPORT_DECLARATIONS
|
|
// </headers defining libabigail's API>
|
|
|
|
namespace abigail
|
|
{
|
|
|
|
namespace hashing
|
|
{
|
|
|
|
// Mix 3 32 bits values reversibly. Borrowed from hashtab.c in gcc tree.
|
|
#define abigail_hash_mix(a, b, c) \
|
|
{ \
|
|
a -= b; a -= c; a ^= (c>>13); \
|
|
b -= c; b -= a; b ^= (a<< 8); \
|
|
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
|
|
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
|
|
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
|
|
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
|
|
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
|
|
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
|
|
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
|
|
}
|
|
|
|
size_t
|
|
combine_hashes(size_t val1, size_t val2)
|
|
{
|
|
/* the golden ratio; an arbitrary value. */
|
|
size_t a = 0x9e3779b9;
|
|
abigail_hash_mix(a, val1, val2);
|
|
return val2;
|
|
}
|
|
|
|
/// Compute a stable string hash.
|
|
///
|
|
/// std::hash has no portability or stability guarantees so is
|
|
/// unsuitable where reproducibility is a requirement such as in XML
|
|
/// output.
|
|
///
|
|
/// This is the 32-bit FNV-1a algorithm. The algorithm, reference code
|
|
/// and constants are all unencumbered. It is fast and has reasonable
|
|
/// distribution properties.
|
|
///
|
|
/// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function
|
|
///
|
|
/// @param str the string to hash.
|
|
///
|
|
/// @return an unsigned 32 bit hash value.
|
|
uint32_t
|
|
fnv_hash(const std::string& str)
|
|
{
|
|
const uint32_t prime = 0x01000193;
|
|
const uint32_t offset_basis = 0x811c9dc5;
|
|
uint32_t hash = offset_basis;
|
|
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
|
{
|
|
uint8_t byte = *i;
|
|
hash = hash ^ byte;
|
|
hash = hash * prime;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
}//end namespace hashing
|
|
|
|
using std::list;
|
|
using std::vector;
|
|
|
|
using namespace abigail::ir;
|
|
|
|
// See forward declarations in abg-ir.h.
|
|
|
|
// Definitions.
|
|
|
|
/// Hash function for an instance of @ref type_base.
|
|
///
|
|
/// @param t the type to hash.
|
|
///
|
|
/// @return the type value.
|
|
size_t
|
|
type_base::hash::operator()(const type_base& t) const
|
|
{
|
|
std::hash<size_t> size_t_hash;
|
|
std::hash<string> str_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, size_t_hash(t.get_size_in_bits()));
|
|
v = hashing::combine_hashes(v, size_t_hash(t.get_alignment_in_bits()));
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Hash function for an instance of @ref type_base.
|
|
///
|
|
/// @param t the type to hash.
|
|
///
|
|
/// @return the type value.
|
|
size_t
|
|
type_base::hash::operator()(const type_base* t) const
|
|
{return operator()(*t);}
|
|
|
|
/// Hash function for an instance of @ref type_base.
|
|
///
|
|
/// @param t the type to hash.
|
|
///
|
|
/// @return the type value.
|
|
size_t
|
|
type_base::hash::operator()(const type_base_sptr t) const
|
|
{return operator()(*t);}
|
|
|
|
struct decl_base::hash
|
|
{
|
|
size_t
|
|
operator()(const decl_base& d) const
|
|
{
|
|
std::hash<string> str_hash;
|
|
|
|
size_t v = str_hash(typeid(d).name());
|
|
if (!d.get_linkage_name().empty())
|
|
v = hashing::combine_hashes(v, str_hash(d.get_linkage_name()));
|
|
if (!d.get_name().empty())
|
|
v = hashing::combine_hashes(v, str_hash(d.get_qualified_name()));
|
|
if (is_member_decl(d))
|
|
{
|
|
v = hashing::combine_hashes(v, get_member_access_specifier(d));
|
|
v = hashing::combine_hashes(v, get_member_is_static(d));
|
|
}
|
|
return v;
|
|
}
|
|
}; // end struct decl_base::hash
|
|
|
|
struct type_decl::hash
|
|
{
|
|
size_t
|
|
operator()(const type_decl& t) const
|
|
{
|
|
decl_base::hash decl_hash;
|
|
type_base::hash type_hash;
|
|
std::hash<string> str_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, type_hash(t));
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
/// Hashing operator for the @ref scope_decl type.
|
|
///
|
|
/// @param d the scope_decl to hash.
|
|
///
|
|
/// @return the hash value.
|
|
size_t
|
|
scope_decl::hash::operator()(const scope_decl& d) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
size_t v = hash_string(typeid(d).name());
|
|
for (scope_decl::declarations::const_iterator i =
|
|
d.get_member_decls().begin();
|
|
i != d.get_member_decls().end();
|
|
++i)
|
|
v = hashing::combine_hashes(v, (*i)->get_hash());
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Hashing operator for the @ref scope_decl type.
|
|
///
|
|
/// @param d the scope_decl to hash.
|
|
///
|
|
/// @return the hash value.
|
|
size_t
|
|
scope_decl::hash::operator()(const scope_decl* d) const
|
|
{return d? operator()(*d) : 0;}
|
|
|
|
struct scope_type_decl::hash
|
|
{
|
|
size_t
|
|
operator()(const scope_type_decl& t) const
|
|
{
|
|
decl_base::hash decl_hash;
|
|
type_base::hash type_hash;
|
|
std::hash<string> str_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, type_hash(t));
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct qualified_type_def::hash
|
|
{
|
|
size_t
|
|
operator()(const qualified_type_def& t) const
|
|
{
|
|
type_base::hash type_hash;
|
|
decl_base::hash decl_hash;
|
|
std::hash<string> str_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, type_hash(t));
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, t.get_cv_quals());
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct pointer_type_def::hash
|
|
{
|
|
size_t
|
|
operator()(const pointer_type_def& t) const
|
|
{
|
|
std::hash<string> str_hash;
|
|
type_base::hash type_base_hash;
|
|
decl_base::hash decl_hash;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, type_base_hash(t));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_pointed_to_type()));
|
|
return v ;
|
|
}
|
|
};
|
|
|
|
struct reference_type_def::hash
|
|
{
|
|
size_t
|
|
operator()(const reference_type_def& t)
|
|
{
|
|
std::hash<string> hash_str;
|
|
type_base::hash hash_type_base;
|
|
decl_base::hash hash_decl;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
|
|
size_t v = hash_str(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_str(t.is_lvalue()
|
|
? "lvalue"
|
|
: "rvalue"));
|
|
v = hashing::combine_hashes(v, hash_type_base(t));
|
|
v = hashing::combine_hashes(v, hash_decl(t));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_pointed_to_type()));
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct array_type_def::subrange_type::hash
|
|
{
|
|
size_t
|
|
operator()(const array_type_def::subrange_type& s) const
|
|
{
|
|
std::hash<int> hash_size_t;
|
|
size_t v = hash_size_t(hash_size_t(s.get_lower_bound()));
|
|
v = hashing::combine_hashes(v, hash_size_t(s.get_upper_bound()));
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct array_type_def::hash
|
|
{
|
|
size_t
|
|
operator()(const array_type_def& t)
|
|
{
|
|
std::hash<string> hash_str;
|
|
type_base::hash hash_type_base;
|
|
decl_base::hash hash_decl;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
array_type_def::subrange_type::hash hash_subrange;
|
|
|
|
size_t v = hash_str(typeid(t).name());
|
|
|
|
v = hashing::combine_hashes(v, hash_type_base(t));
|
|
v = hashing::combine_hashes(v, hash_decl(t));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_element_type()));
|
|
|
|
for (vector<array_type_def::subrange_sptr >::const_iterator i =
|
|
t.get_subranges().begin();
|
|
i != t.get_subranges().end();
|
|
++i)
|
|
v = hashing::combine_hashes(v, hash_subrange(**i));
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct enum_type_decl::hash
|
|
{
|
|
size_t
|
|
operator()(const enum_type_decl& t) const
|
|
{
|
|
std::hash<string> str_hash;
|
|
decl_base::hash decl_hash;
|
|
type_base::shared_ptr_hash type_ptr_hash;
|
|
std::hash<size_t> size_t_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, type_ptr_hash(t.get_underlying_type()));
|
|
for (enum_type_decl::enumerators::const_iterator i =
|
|
t.get_enumerators().begin();
|
|
i != t.get_enumerators().end();
|
|
++i)
|
|
{
|
|
v = hashing::combine_hashes(v, str_hash(i->get_name()));
|
|
v = hashing::combine_hashes(v, size_t_hash(i->get_value()));
|
|
}
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct typedef_decl::hash
|
|
{
|
|
size_t
|
|
operator()(const typedef_decl& t) const
|
|
{
|
|
std::hash<string> str_hash;
|
|
type_base::hash hash_type;
|
|
decl_base::hash decl_hash;
|
|
type_base::shared_ptr_hash type_ptr_hash;
|
|
|
|
size_t v = str_hash(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_type(t));
|
|
v = hashing::combine_hashes(v, decl_hash(t));
|
|
v = hashing::combine_hashes(v, type_ptr_hash(t.get_underlying_type()));
|
|
return v;
|
|
}
|
|
};
|
|
|
|
/// Compute a hash for an instance @ref var_decl.
|
|
///
|
|
/// Note that this function caches the hashing value the
|
|
/// decl_base::hash_ data member of the input instance and re-uses it
|
|
/// when it is already calculated.
|
|
///
|
|
/// @param t the instance of @ref var_decl to compute the hash for.
|
|
///
|
|
/// @return the calculated hash value, or the one that was previously
|
|
/// calculated.
|
|
size_t
|
|
var_decl::hash::operator()(const var_decl& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
decl_base::hash hash_decl;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
std::hash<size_t> hash_size_t;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_decl(t));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_type()));
|
|
|
|
if (is_data_member(t) && get_data_member_is_laid_out(t))
|
|
{
|
|
v = hashing::combine_hashes(v, hash_decl(*t.get_scope()));
|
|
v = hashing::combine_hashes(v, hash_size_t(get_data_member_offset(t)));
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash for a pointer to @ref var_decl.
|
|
///
|
|
/// @param t the pointer to @ref var_decl to compute the hash for.
|
|
///
|
|
/// @return the calculated hash value
|
|
size_t
|
|
var_decl::hash::operator()(const var_decl* t) const
|
|
{return operator()(*t);}
|
|
|
|
/// Compute a hash value for an instance of @ref function_decl.
|
|
///
|
|
/// Note that this function caches the resulting hash in the
|
|
/// decl_base::hash_ data member of the instance of @ref
|
|
/// function_decl, and just returns if it is already calculated.
|
|
///
|
|
/// @param t the function to calculate the hash for.
|
|
///
|
|
/// @return the hash value.
|
|
size_t
|
|
function_decl::hash::operator()(const function_decl& t) const
|
|
{
|
|
std::hash<int> hash_int;
|
|
std::hash<size_t> hash_size_t;
|
|
std::hash<bool> hash_bool;
|
|
std::hash<string> hash_string;
|
|
decl_base::hash hash_decl_base;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_decl_base(t));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_type()));
|
|
v = hashing::combine_hashes(v, hash_bool(t.is_declared_inline()));
|
|
v = hashing::combine_hashes(v, hash_int(t.get_binding()));
|
|
if (is_member_function(t))
|
|
{
|
|
bool is_ctor = get_member_function_is_ctor(t),
|
|
is_dtor = get_member_function_is_dtor(t),
|
|
is_static = get_member_is_static(t),
|
|
is_const = get_member_function_is_const(t);
|
|
size_t voffset = get_member_function_vtable_offset(t);
|
|
|
|
v = hashing::combine_hashes(v, hash_bool(is_ctor));
|
|
v = hashing::combine_hashes(v, hash_bool(is_dtor));
|
|
v = hashing::combine_hashes(v, hash_bool(is_static));
|
|
v = hashing::combine_hashes(v, hash_bool(is_const));
|
|
if (!is_static && !is_ctor)
|
|
v = hashing::combine_hashes(v, hash_size_t(voffset));
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash for a pointer to @ref function_decl.
|
|
///
|
|
/// @param t the pointer to @ref function_decl to compute the hash for.
|
|
///
|
|
/// @return the calculated hash value
|
|
size_t
|
|
function_decl::hash::operator()(const function_decl* t) const
|
|
{return operator()(*t);}
|
|
|
|
size_t
|
|
function_decl::parameter::hash::operator()
|
|
(const function_decl::parameter& p) const
|
|
{
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
std::hash<bool> hash_bool;
|
|
std::hash<unsigned> hash_unsigned;
|
|
size_t v = hash_type_ptr(p.get_type());
|
|
v = hashing::combine_hashes(v, hash_unsigned(p.get_index()));
|
|
v = hashing::combine_hashes(v, hash_bool(p.get_variadic_marker()));
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
function_decl::parameter::hash::operator()
|
|
(const function_decl::parameter* p) const
|
|
{return operator()(*p);}
|
|
|
|
size_t
|
|
function_decl::parameter::hash::operator()
|
|
(const function_decl::parameter_sptr p) const
|
|
{return operator()(p.get());}
|
|
|
|
/// Hashing functor for the @ref method_type type.
|
|
struct method_type::hash
|
|
{
|
|
size_t
|
|
operator()(const method_type& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
function_decl::parameter::hash hash_parameter;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
string class_name = t.get_class_type()->get_qualified_name();
|
|
v = hashing::combine_hashes(v, hash_string(class_name));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_return_type()));
|
|
vector<shared_ptr<function_decl::parameter> >::const_iterator i =
|
|
t.get_first_non_implicit_parm();
|
|
|
|
for (; i != t.get_parameters().end(); ++i)
|
|
v = hashing::combine_hashes(v, hash_parameter(**i));
|
|
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
operator()(const method_type* t)
|
|
{return operator()(*t);}
|
|
|
|
size_t
|
|
operator()(const method_type_sptr t)
|
|
{return operator()(t.get());}
|
|
}; // end struct method_type::hash
|
|
|
|
// <struct function_type::hash stuff>
|
|
|
|
/// Hashing function for @ref function_type.
|
|
///
|
|
/// @param t the function type to hash.
|
|
///
|
|
/// @return the resulting hash value.
|
|
size_t
|
|
function_type::hash::operator()(const function_type& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
function_decl::parameter::hash hash_parameter;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_return_type()));
|
|
for (vector<shared_ptr<function_decl::parameter> >::const_iterator i =
|
|
t.get_first_non_implicit_parm();
|
|
i != t.get_parameters().end();
|
|
++i)
|
|
v = hashing::combine_hashes(v, hash_parameter(**i));
|
|
return v;
|
|
}
|
|
|
|
/// Hashing function for a pointer to @ref function_type.
|
|
///
|
|
/// @param t the pointer to @ref function_type to hash.
|
|
///
|
|
/// @return the resulting hash value.
|
|
size_t
|
|
function_type::hash::operator()(const function_type* t) const
|
|
{
|
|
if (const method_type* m = dynamic_cast<const method_type*>(t))
|
|
{
|
|
method_type::hash h;
|
|
return h(m);
|
|
}
|
|
return operator()(*t);
|
|
}
|
|
|
|
/// Hashing function for a shared pointer to @ref function_type.
|
|
///
|
|
/// @param t the pointer to @ref function_type to hash.
|
|
///
|
|
/// @return the resulting hash value.
|
|
size_t
|
|
function_type::hash::operator()(const function_type_sptr t) const
|
|
{return operator()(t.get());}
|
|
|
|
// </struct function_type::hash stuff>
|
|
|
|
size_t
|
|
member_base::hash::operator()(const member_base& m) const
|
|
{
|
|
std::hash<int> hash_int;
|
|
return hash_int(m.get_access_specifier());
|
|
}
|
|
|
|
size_t
|
|
class_decl::base_spec::hash::operator()(const base_spec& t) const
|
|
{
|
|
member_base::hash hash_member;
|
|
type_base::shared_ptr_hash hash_type_ptr;
|
|
std::hash<size_t> hash_size;
|
|
std::hash<bool> hash_bool;
|
|
std::hash<string> hash_string;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_member(t));
|
|
v = hashing::combine_hashes(v, hash_size(t.get_offset_in_bits()));
|
|
v = hashing::combine_hashes(v, hash_bool(t.get_is_virtual()));
|
|
v = hashing::combine_hashes(v, hash_type_ptr(t.get_base_class()));
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
member_function_template::hash::operator()
|
|
(const member_function_template& t) const
|
|
{
|
|
std::hash<bool> hash_bool;
|
|
function_tdecl::hash hash_function_tdecl;
|
|
member_base::hash hash_member;
|
|
std::hash<string> hash_string;
|
|
|
|
size_t v = hash_member(t);
|
|
string n = t.get_qualified_name();
|
|
v = hashing::combine_hashes(v, hash_string(n));
|
|
v = hashing::combine_hashes(v, hash_function_tdecl(t));
|
|
v = hashing::combine_hashes(v, hash_bool(t.is_constructor()));
|
|
v = hashing::combine_hashes(v, hash_bool(t.is_const()));
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
member_class_template::hash::operator()
|
|
(const member_class_template& t) const
|
|
{
|
|
member_base::hash hash_member;
|
|
class_tdecl::hash hash_class_tdecl;
|
|
std::hash<string> hash_string;
|
|
|
|
size_t v = hash_member(t);
|
|
string n = t.get_qualified_name();
|
|
v = hashing::combine_hashes(v, hash_string(n));
|
|
v = hashing::combine_hashes(v, hash_class_tdecl(t));
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash for a @ref class_or_union
|
|
///
|
|
/// @param t the class_or_union for which to compute the hash value.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
class_or_union::hash::operator()(const class_or_union& t) const
|
|
{
|
|
if (t.hashing_started()
|
|
|| (t.get_is_declaration_only() && !t.get_definition_of_declaration()))
|
|
// All non-resolved decl-only types have a hash of zero. Their hash
|
|
// will differ from the resolved hash, but then at least, having
|
|
// it be zero will give a hint that we couldn't actually compute
|
|
// the hash.
|
|
return 0;
|
|
|
|
// If the type is decl-only and now has a definition, then hash its
|
|
// definition instead.
|
|
|
|
if (t.get_is_declaration_only())
|
|
{
|
|
ABG_ASSERT(t.get_definition_of_declaration());
|
|
size_t v = operator()
|
|
(*is_class_or_union_type(t.get_definition_of_declaration()));
|
|
return v;
|
|
}
|
|
|
|
ABG_ASSERT(!t.get_is_declaration_only());
|
|
|
|
std::hash<string> hash_string;
|
|
scope_type_decl::hash hash_scope_type;
|
|
var_decl::hash hash_data_member;
|
|
member_function_template::hash hash_member_fn_tmpl;
|
|
member_class_template::hash hash_member_class_tmpl;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_scope_type(t));
|
|
|
|
t.hashing_started(true);
|
|
|
|
// Hash data members.
|
|
for (class_decl::data_members::const_iterator d =
|
|
t.get_non_static_data_members().begin();
|
|
d != t.get_non_static_data_members().end();
|
|
++d)
|
|
v = hashing::combine_hashes(v, hash_data_member(**d));
|
|
|
|
// Do not hash member functions. All of them are not necessarily
|
|
// emitted per class, in a given TU so do not consider them when
|
|
// hashing a class.
|
|
|
|
// Hash member function templates
|
|
for (member_function_templates::const_iterator f =
|
|
t.get_member_function_templates().begin();
|
|
f != t.get_member_function_templates().end();
|
|
++f)
|
|
v = hashing::combine_hashes(v, hash_member_fn_tmpl(**f));
|
|
|
|
// Hash member class templates
|
|
for (member_class_templates::const_iterator c =
|
|
t.get_member_class_templates().begin();
|
|
c != t.get_member_class_templates().end();
|
|
++c)
|
|
v = hashing::combine_hashes(v, hash_member_class_tmpl(**c));
|
|
|
|
t.hashing_started(false);
|
|
|
|
return v;
|
|
};
|
|
|
|
/// Compute a hash for a @ref class_or_union
|
|
///
|
|
/// @param t the class_or_union for which to compute the hash value.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
class_or_union::hash::operator()(const class_or_union *t) const
|
|
{return t ? operator()(*t) : 0;}
|
|
|
|
/// Compute a hash for a @ref class_decl
|
|
///
|
|
/// @param t the class_decl for which to compute the hash value.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
class_decl::hash::operator()(const class_decl& t) const
|
|
{
|
|
if (t.hashing_started()
|
|
|| (t.get_is_declaration_only() && !t.get_definition_of_declaration()))
|
|
// All non-resolved decl-only types have a hash of zero. Their hash
|
|
// will differ from the resolved hash, but then at least, having
|
|
// it be zero will give a hint that we couldn't actually compute
|
|
// the hash.
|
|
return 0;
|
|
|
|
|
|
// If the type is decl-only and now has a definition, then hash its
|
|
// definition instead.
|
|
|
|
if (t.get_is_declaration_only())
|
|
{
|
|
ABG_ASSERT(t.get_definition_of_declaration());
|
|
size_t v = operator()(*is_class_type(t.get_definition_of_declaration()));
|
|
return v;
|
|
}
|
|
|
|
ABG_ASSERT(!t.get_is_declaration_only());
|
|
|
|
std::hash<string> hash_string;
|
|
class_decl::base_spec::hash hash_base;
|
|
class_or_union::hash hash_class_or_union;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
|
|
t.hashing_started(true);
|
|
|
|
// Hash bases.
|
|
for (class_decl::base_specs::const_iterator b =
|
|
t.get_base_specifiers().begin();
|
|
b != t.get_base_specifiers().end();
|
|
++b)
|
|
{
|
|
class_decl_sptr cl = (*b)->get_base_class();
|
|
v = hashing::combine_hashes(v, hash_base(**b));
|
|
}
|
|
|
|
v = hashing::combine_hashes(v, hash_class_or_union(t));
|
|
|
|
t.hashing_started(false);
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash for a @ref class_decl
|
|
///
|
|
/// @param t the class_decl for which to compute the hash value.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
class_decl::hash::operator()(const class_decl* t) const
|
|
{return t ? operator()(*t) : 0;}
|
|
|
|
struct template_parameter::hash
|
|
{
|
|
size_t
|
|
operator()(const template_parameter& t) const
|
|
{
|
|
// Let's avoid infinite recursion triggered from the fact that
|
|
// hashing a template parameter triggers hashing the enclosed
|
|
// template decl, which in turn triggers the hashing of its
|
|
// template parameters; so the initial template parameter that
|
|
// triggered the hashing could be hashed again ...
|
|
if (t.get_hashing_has_started())
|
|
return 0;
|
|
|
|
t.set_hashing_has_started(true);
|
|
|
|
std::hash<unsigned> hash_unsigned;
|
|
std::hash<std::string> hash_string;
|
|
template_decl::hash hash_template_decl;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_unsigned(t.get_index()));
|
|
v = hashing::combine_hashes(v, hash_template_decl
|
|
(*t.get_enclosing_template_decl()));
|
|
|
|
t.set_hashing_has_started(false);
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct template_parameter::dynamic_hash
|
|
{
|
|
size_t
|
|
operator()(const template_parameter* t) const;
|
|
};
|
|
|
|
struct template_parameter::shared_ptr_hash
|
|
{
|
|
size_t
|
|
operator()(const shared_ptr<template_parameter> t) const
|
|
{return template_parameter::dynamic_hash()(t.get());}
|
|
};
|
|
|
|
size_t
|
|
template_decl::hash::operator()(const template_decl& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
template_parameter::shared_ptr_hash hash_template_parameter;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_string(t.get_qualified_name()));
|
|
|
|
for (list<template_parameter_sptr>::const_iterator p =
|
|
t.get_template_parameters().begin();
|
|
p != t.get_template_parameters().end();
|
|
++p)
|
|
if (!(*p)->get_hashing_has_started())
|
|
v = hashing::combine_hashes(v, hash_template_parameter(*p));
|
|
|
|
return v;
|
|
}
|
|
|
|
struct type_tparameter::hash
|
|
{
|
|
size_t
|
|
operator()(const type_tparameter& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
template_parameter::hash hash_template_parameter;
|
|
type_decl::hash hash_type;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_template_parameter(t));
|
|
v = hashing::combine_hashes(v, hash_type(t));
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
/// Compute a hash value for a @ref non_type_tparameter
|
|
///
|
|
/// @param t the non_type_tparameter for which to compute the value.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
non_type_tparameter::hash::operator()(const non_type_tparameter& t) const
|
|
{
|
|
template_parameter::hash hash_template_parameter;
|
|
std::hash<string> hash_string;
|
|
type_base::shared_ptr_hash hash_type;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_template_parameter(t));
|
|
v = hashing::combine_hashes(v, hash_string(t.get_name()));
|
|
v = hashing::combine_hashes(v, hash_type(t.get_type()));
|
|
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash value for a @ref non_type_tparameter
|
|
///
|
|
/// @param t the non_type_tparameter to compute the hash value for.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
non_type_tparameter::hash::operator()(const non_type_tparameter* t) const
|
|
{return t ? operator()(*t) : 0;}
|
|
|
|
struct template_tparameter::hash
|
|
{
|
|
size_t
|
|
operator()(const template_tparameter& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
type_tparameter::hash hash_template_type_parm;
|
|
template_decl::hash hash_template_decl;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_template_type_parm(t));
|
|
v = hashing::combine_hashes(v, hash_template_decl(t));
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
size_t
|
|
template_parameter::dynamic_hash::
|
|
operator()(const template_parameter* t) const
|
|
{
|
|
if (const template_tparameter* p =
|
|
dynamic_cast<const template_tparameter*>(t))
|
|
return template_tparameter::hash()(*p);
|
|
else if (const type_tparameter* p =
|
|
dynamic_cast<const type_tparameter*>(t))
|
|
return type_tparameter::hash()(*p);
|
|
if (const non_type_tparameter* p =
|
|
dynamic_cast<const non_type_tparameter*>(t))
|
|
return non_type_tparameter::hash()(*p);
|
|
|
|
// Poor man's fallback.
|
|
return template_parameter::hash()(*t);
|
|
}
|
|
|
|
/// Compute a hash value for a @ref type_composition type.
|
|
///
|
|
/// @param t the type_composition to compute the hash value for.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
type_composition::hash::operator()(const type_composition& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
type_base::dynamic_hash hash_type;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_type(t.get_composed_type().get()));
|
|
return v;
|
|
}
|
|
|
|
/// Compute a hash value for a @ref type_composition type.
|
|
///
|
|
/// @param t the type_composition to compute the hash value for.
|
|
///
|
|
/// @return the computed hash value.
|
|
size_t
|
|
type_composition::hash::operator()(const type_composition* t) const
|
|
{return t ? operator()(*t): 0;}
|
|
|
|
size_t
|
|
function_tdecl::hash::
|
|
operator()(const function_tdecl& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
decl_base::hash hash_decl_base;
|
|
template_decl::hash hash_template_decl;
|
|
function_decl::hash hash_function_decl;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
|
|
v = hashing::combine_hashes(v, hash_decl_base(t));
|
|
v = hashing::combine_hashes(v, hash_template_decl(t));
|
|
if (t.get_pattern())
|
|
v = hashing::combine_hashes(v, hash_function_decl(*t.get_pattern()));
|
|
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
function_tdecl::shared_ptr_hash::
|
|
operator()(const shared_ptr<function_tdecl> f) const
|
|
{
|
|
function_tdecl::hash hash_fn_tmpl_decl;
|
|
if (f)
|
|
return hash_fn_tmpl_decl(*f);
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
class_tdecl::hash::
|
|
operator()(const class_tdecl& t) const
|
|
{
|
|
std::hash<string> hash_string;
|
|
decl_base::hash hash_decl_base;
|
|
template_decl::hash hash_template_decl;
|
|
class_decl::hash hash_class_decl;
|
|
|
|
size_t v = hash_string(typeid(t).name());
|
|
v = hashing::combine_hashes(v, hash_decl_base(t));
|
|
v = hashing::combine_hashes(v, hash_template_decl(t));
|
|
if (t.get_pattern())
|
|
v = hashing::combine_hashes(v, hash_class_decl(*t.get_pattern()));
|
|
|
|
return v;
|
|
}
|
|
|
|
size_t
|
|
class_tdecl::shared_ptr_hash::
|
|
operator()(const shared_ptr<class_tdecl> t) const
|
|
{
|
|
class_tdecl::hash hash_class_tmpl_decl;
|
|
|
|
if (t)
|
|
return hash_class_tmpl_decl(*t);
|
|
return 0;
|
|
}
|
|
|
|
/// A hashing function for type declarations.
|
|
///
|
|
/// This function gets the dynamic type of the actual type
|
|
/// declaration and calls the right hashing function for that type.
|
|
///
|
|
/// Note that each time a new type declaration kind is added to the
|
|
/// system, this function needs to be updated. For a given
|
|
/// inheritance hierarchy, make sure to handle the most derived type
|
|
/// first.
|
|
///
|
|
/// FIXME: This hashing function is not maintained and is surely
|
|
/// broken in subtle ways. In pratice, the various *::hash functors
|
|
/// should be audited before they are used here. They should all
|
|
/// match what is done in the 'equals' functions in abg-ir.cc.
|
|
///
|
|
/// @param t a pointer to the type declaration to be hashed
|
|
///
|
|
/// @return the resulting hash
|
|
size_t
|
|
type_base::dynamic_hash::operator()(const type_base* t) const
|
|
{
|
|
if (t == 0)
|
|
return 0;
|
|
|
|
if (const member_function_template* d =
|
|
dynamic_cast<const member_function_template*>(t))
|
|
return member_function_template::hash()(*d);
|
|
if (const member_class_template* d =
|
|
dynamic_cast<const member_class_template*>(t))
|
|
return member_class_template::hash()(*d);
|
|
if (const template_tparameter* d =
|
|
dynamic_cast<const template_tparameter*>(t))
|
|
return template_tparameter::hash()(*d);
|
|
if (const type_tparameter* d =
|
|
dynamic_cast<const type_tparameter*>(t))
|
|
return type_tparameter::hash()(*d);
|
|
if (const type_decl* d = dynamic_cast<const type_decl*> (t))
|
|
return type_decl::hash()(*d);
|
|
if (const qualified_type_def* d = dynamic_cast<const qualified_type_def*>(t))
|
|
return qualified_type_def::hash()(*d);
|
|
if (const pointer_type_def* d = dynamic_cast<const pointer_type_def*>(t))
|
|
return pointer_type_def::hash()(*d);
|
|
if (const reference_type_def* d = dynamic_cast<const reference_type_def*>(t))
|
|
return reference_type_def::hash()(*d);
|
|
if (const array_type_def* d = dynamic_cast<const array_type_def*>(t))
|
|
return array_type_def::hash()(*d);
|
|
if (const enum_type_decl* d = dynamic_cast<const enum_type_decl*>(t))
|
|
return enum_type_decl::hash()(*d);
|
|
if (const typedef_decl* d = dynamic_cast<const typedef_decl*>(t))
|
|
return typedef_decl::hash()(*d);
|
|
if (const class_decl* d = dynamic_cast<const class_decl*>(t))
|
|
return class_decl::hash()(*d);
|
|
if (const union_decl* d = dynamic_cast<const union_decl*>(t))
|
|
return union_decl::hash()(*d);
|
|
if (const scope_type_decl* d = dynamic_cast<const scope_type_decl*>(t))
|
|
return scope_type_decl::hash()(*d);
|
|
if (const method_type* d = dynamic_cast<const method_type*>(t))
|
|
return method_type::hash()(*d);
|
|
if (const function_type* d = dynamic_cast<const function_type*>(t))
|
|
return function_type::hash()(*d);
|
|
|
|
// Poor man's fallback case.
|
|
return type_base::hash()(*t);
|
|
}
|
|
|
|
size_t
|
|
type_base::shared_ptr_hash::operator()(const shared_ptr<type_base> t) const
|
|
{return type_base::dynamic_hash()(t.get());}
|
|
|
|
}//end namespace abigail
|