Fixed type name extraction involving template classes

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@585 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2013-01-20 16:50:37 +00:00
parent b21790be27
commit 4cd3d08e3e
3 changed files with 152 additions and 25 deletions

View file

@ -11,6 +11,7 @@ Not yet released
* Fixed potential conflict with macro max * Fixed potential conflict with macro max
* Fixed missing file name and line number in logs * Fixed missing file name and line number in logs
* Moved mock::exception in its own header so that it can be included without the error policy * Moved mock::exception in its own header so that it can be included without the error policy
* Fixed type name extraction involving template classes
[endsect] [endsect]

View file

@ -19,21 +19,57 @@ namespace
} }
} }
struct my_type_from_default_namespace {}; BOOST_AUTO_TEST_CASE( name_of_base_type_is_extracted )
BOOST_AUTO_TEST_CASE( name_of_type_from_default_namespace_is_extracted )
{ {
BOOST_CHECK_EQUAL( "my_type_from_default_namespace", to_string( my_type_from_default_namespace() ) ); BOOST_CHECK_EQUAL( "char", to_string( 'a' ) );
BOOST_CHECK_EQUAL( "bool", to_string( true ) );
BOOST_CHECK_EQUAL( "int", to_string< int >( 0 ) );
BOOST_CHECK_EQUAL( "short", to_string< short >( 0 ) );
BOOST_CHECK_EQUAL( "long", to_string< long >( 0 ) );
BOOST_CHECK_EQUAL( "unsigned int", to_string< unsigned int >( 0 ) );
BOOST_CHECK_EQUAL( "unsigned short", to_string< unsigned short >( 0 ) );
BOOST_CHECK_EQUAL( "unsigned long", to_string< unsigned long >( 0 ) );
}
struct my_type_in_default_namespace
{
struct inner {};
};
BOOST_AUTO_TEST_CASE( name_of_type_in_default_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "my_type_in_default_namespace", to_string( my_type_in_default_namespace() ) );
}
BOOST_AUTO_TEST_CASE( name_of_inner_type_from_type_in_default_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "inner", to_string( my_type_in_default_namespace::inner() ) );
}
template< typename T >
struct my_template_type_in_default_namespace
{
struct inner {};
};
BOOST_AUTO_TEST_CASE( name_of_template_type_in_default_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "my_template_type_in_default_namespace<int>", to_string( my_template_type_in_default_namespace<int>() ) );
}
BOOST_AUTO_TEST_CASE( name_of_inner_type_from_template_type_in_default_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "inner", to_string( my_template_type_in_default_namespace<int>::inner() ) );
} }
namespace namespace
{ {
struct my_type_from_anonymous_namespace {}; struct my_type_in_anonymous_namespace {};
} }
BOOST_AUTO_TEST_CASE( name_of_type_from_anonymous_namespace_is_extracted ) BOOST_AUTO_TEST_CASE( name_of_type_in_anonymous_namespace_is_extracted )
{ {
BOOST_CHECK_EQUAL( "my_type_from_anonymous_namespace", to_string( my_type_from_anonymous_namespace() ) ); BOOST_CHECK_EQUAL( "my_type_in_anonymous_namespace", to_string( my_type_in_anonymous_namespace() ) );
} }
namespace nm namespace nm
@ -50,26 +86,26 @@ namespace nm
{ {
namespace inner namespace inner
{ {
struct my_type_from_named_inner_namespace {}; struct my_type_in_named_inner_namespace {};
} }
} }
BOOST_AUTO_TEST_CASE( name_of_type_from_named_inner_namespace_is_extracted ) BOOST_AUTO_TEST_CASE( name_of_type_in_named_inner_namespace_is_extracted )
{ {
BOOST_CHECK_EQUAL( "my_type_from_named_inner_namespace", to_string( nm::inner::my_type_from_named_inner_namespace() ) ); BOOST_CHECK_EQUAL( "my_type_in_named_inner_namespace", to_string( nm::inner::my_type_in_named_inner_namespace() ) );
} }
namespace namespace
{ {
namespace inner namespace inner
{ {
struct my_type_from_unnamed_inner_namespace {}; struct my_type_in_unnamed_inner_namespace {};
} }
} }
BOOST_AUTO_TEST_CASE( name_of_type_from_unnamed_inner_namespace_is_extracted ) BOOST_AUTO_TEST_CASE( name_of_type_in_unnamed_inner_namespace_is_extracted )
{ {
BOOST_CHECK_EQUAL( "my_type_from_unnamed_inner_namespace", to_string( inner::my_type_from_unnamed_inner_namespace() ) ); BOOST_CHECK_EQUAL( "my_type_in_unnamed_inner_namespace", to_string( inner::my_type_in_unnamed_inner_namespace() ) );
} }
BOOST_AUTO_TEST_CASE( name_of_local_type_is_extracted ) BOOST_AUTO_TEST_CASE( name_of_local_type_is_extracted )
@ -77,3 +113,61 @@ BOOST_AUTO_TEST_CASE( name_of_local_type_is_extracted )
struct my_local_type {}; struct my_local_type {};
BOOST_CHECK_EQUAL( "my_local_type", boost::lexical_cast< std::string >( mock::detail::type_name( BOOST_SP_TYPEID( my_local_type ) ) ) ); BOOST_CHECK_EQUAL( "my_local_type", boost::lexical_cast< std::string >( mock::detail::type_name( BOOST_SP_TYPEID( my_local_type ) ) ) );
} }
namespace
{
template< typename T >
struct my_template_type
{
struct inner {};
};
}
BOOST_AUTO_TEST_CASE( name_of_template_type_in_anonymous_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "my_template_type<int>", to_string( my_template_type< int >() ) );
BOOST_CHECK_EQUAL( "my_template_type<exception>", to_string( my_template_type< std::exception >() ) );
}
BOOST_AUTO_TEST_CASE( name_of_inner_type_from_template_type_in_anonymous_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "inner", to_string( my_template_type< int >::inner() ) );
BOOST_CHECK_EQUAL( "inner", to_string( my_template_type< std::exception >::inner() ) );
}
namespace nm
{
template< typename T >
struct my_template_type
{
struct inner {};
};
}
BOOST_AUTO_TEST_CASE( name_of_template_type_in_named_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "my_template_type<int>", to_string( nm::my_template_type< int >() ) );
BOOST_CHECK_EQUAL( "my_template_type<exception>", to_string( nm::my_template_type< std::exception >() ) );
}
BOOST_AUTO_TEST_CASE( name_of_inner_type_from_template_type_in_named_namespace_is_extracted )
{
BOOST_CHECK_EQUAL( "inner", to_string( nm::my_template_type< int >::inner() ) );
BOOST_CHECK_EQUAL( "inner", to_string( nm::my_template_type< std::exception >::inner() ) );
}
namespace nm2
{
template< typename T >
struct my_template_type
{
template< typename U >
struct inner {};
};
}
BOOST_AUTO_TEST_CASE( name_of_inner_type_from_template_type_in_named_namespace_is_extracted2 )
{
BOOST_CHECK_EQUAL( "inner<int>", to_string( nm2::my_template_type< int >::inner< int >() ) );
BOOST_CHECK_EQUAL( "inner<int>", to_string( nm2::my_template_type< std::exception >::inner< int >() ) );
}

View file

@ -35,13 +35,16 @@ namespace detail
return s; return s;
} }
private: private:
typedef boost::unit_test::const_string const_string;
typedef const_string::size_type size_type;
void serialize( std::ostream& s, void serialize( std::ostream& s,
const boost::detail::sp_typeinfo& info ) const const boost::detail::sp_typeinfo& info ) const
{ {
const char* name = info.name(); const char* name = info.name();
#ifdef __GNUC__ #ifdef __GNUC__
int status = 0; int status = 0;
char* result = abi::__cxa_demangle( name, NULL, 0, &status ); char* result = abi::__cxa_demangle( name, 0, 0, &status );
struct guard struct guard
{ {
explicit guard( char* p ) explicit guard( char* p )
@ -49,7 +52,7 @@ namespace detail
{} {}
~guard() ~guard()
{ {
free( p_ ); std::free( p_ );
} }
private: private:
char* p_; char* p_;
@ -60,22 +63,51 @@ namespace detail
#endif #endif
serialize( s, name ); serialize( s, name );
} }
void serialize( std::ostream& s, void serialize( std::ostream& s, const_string name ) const
boost::unit_test::const_string name ) const
{ {
boost::unit_test::const_string::size_type p = name.rfind( "::" ); const size_type tpl_end = name.rfind( ">" );
if( p != boost::unit_test::const_string::npos ) const size_type nm = name.rfind( "::" );
if( tpl_end == const_string::npos || tpl_end <= nm )
{ {
s << name.substr( p + 2 ); s << remove_prefix( remove_namespace( name ) );
return; return;
} }
p = name.rfind( " " ); const size_type tpl_start = find_template_start( name );
if( p != boost::unit_test::const_string::npos ) s << remove_namespace( name.substr( 0, tpl_start ) ) << '<';
{ serialize( s, name.substr( tpl_start + 1, tpl_end ) );
s << name.substr( p + 1 ); s << '>';
return;
} }
s << name; const_string remove_prefix( const_string name ) const
{
name = remove_prefix( name, "class " );
name = remove_prefix( name, "struct " );
return name;
}
const_string remove_prefix( const_string name,
const_string prefix ) const
{
if( name.substr( 0, prefix.size() ) == prefix )
return name.substr( prefix.size() );
return name;
}
size_type find_template_start( const_string name ) const
{
size_type count = 0;
for( size_type i = name.size(); i > 0; --i )
{
if( name[ i ] == '>' )
++count;
if( name[ i ] == '<' && --count == 0 )
return i;
}
return static_cast< size_type >( const_string::npos );
}
const_string remove_namespace( const_string name ) const
{
size_type p = name.rfind( "::" );
if( p == const_string::npos )
return name;
return name.substr( p + 2 );
} }
const boost::detail::sp_typeinfo* info_; const boost::detail::sp_typeinfo* info_;