Best effort to print more details about caught UNO exception

Change-Id: Ia8f098e4e441b6aba0d76d7184dc6cec2210f793
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173813
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
This commit is contained in:
Stephan Bergmann 2024-09-23 14:52:40 +02:00
parent a593c27e88
commit 7ccfc0277a
2 changed files with 130 additions and 12 deletions

View file

@ -13,6 +13,7 @@ $(eval $(call gb_Library_Library,unoexceptionprotector))
$(eval $(call gb_Library_use_sdk_api,unoexceptionprotector)) $(eval $(call gb_Library_use_sdk_api,unoexceptionprotector))
$(eval $(call gb_Library_use_libraries,unoexceptionprotector,\ $(eval $(call gb_Library_use_libraries,unoexceptionprotector,\
comphelper \
cppu \ cppu \
cppuhelper \ cppuhelper \
sal \ sal \

View file

@ -17,16 +17,27 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/ */
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <string> #include <iomanip>
#include <string_view> #include <ios>
#include <ostream>
#include <sstream>
#include <com/sun/star/reflection/XIdlReflection.hpp>
#include <com/sun/star/reflection/XIdlClass.hpp>
#include <com/sun/star/reflection/theCoreReflection.hpp>
#include <com/sun/star/uno/Any.hxx> #include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Exception.hpp> #include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/Type.hxx>
#include <com/sun/star/uno/TypeClass.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <comphelper/processfactory.hxx>
#include <cppuhelper/exc_hlp.hxx> #include <cppuhelper/exc_hlp.hxx>
#include <cppunit/Message.h> #include <cppunit/Message.h>
#include <osl/thread.h> #include <o3tl/any.hxx>
#include <rtl/string.hxx> #include <o3tl/unreachable.hxx>
#include <rtl/ustring.hxx> #include <rtl/ustring.hxx>
#include <sal/types.h> #include <sal/types.h>
@ -34,12 +45,106 @@
namespace { namespace {
// Best effort conversion: css::uno::Type translateType(css::uno::Reference<css::reflection::XIdlClass> const & type) {
std::string convert(std::u16string_view s16) { return css::uno::Type(type->getTypeClass(), type->getName());
OString s8(OUStringToOString(s16, osl_getThreadTextEncoding())); }
static_assert(sizeof (sal_Int32) <= sizeof (std::string::size_type), "got to be at least equal");
// ensure following cast is legitimate void printUnoValue(
return std::string(s8); std::ostream & out, css::uno::Reference<css::reflection::XIdlReflection> const & reflections,
css::uno::Type const & type, css::uno::Any const & value)
{
switch (type.getTypeClass()) {
case css::uno::TypeClass_VOID:
out << "void";
break;
case css::uno::TypeClass_BOOLEAN:
out << *o3tl::forceAccess<bool>(value);
break;
case css::uno::TypeClass_BYTE:
out << int(*o3tl::forceAccess<sal_Int8>(value));
break;
case css::uno::TypeClass_SHORT:
out << *o3tl::forceAccess<sal_Int16>(value);
break;
case css::uno::TypeClass_UNSIGNED_SHORT:
out << *o3tl::forceAccess<sal_uInt16>(value);
break;
case css::uno::TypeClass_LONG:
out << *o3tl::forceAccess<sal_Int32>(value);
break;
case css::uno::TypeClass_UNSIGNED_LONG:
out << *o3tl::forceAccess<sal_uInt32>(value);
break;
case css::uno::TypeClass_HYPER:
out << *o3tl::forceAccess<sal_Int64>(value);
break;
case css::uno::TypeClass_UNSIGNED_HYPER:
out << *o3tl::forceAccess<sal_uInt64>(value);
break;
case css::uno::TypeClass_FLOAT:
out << std::uppercase << *o3tl::forceAccess<float>(value);
break;
case css::uno::TypeClass_DOUBLE:
out << std::uppercase << *o3tl::forceAccess<double>(value);
break;
case css::uno::TypeClass_CHAR:
out << "\\u" << std::hex << std::uppercase << std::setw(4) << std::setfill('0')
<< std::uint_least16_t(*o3tl::forceAccess<char16_t>(value)) << std::dec;
break;
case css::uno::TypeClass_STRING:
out << '"' << *o3tl::forceAccess<OUString>(value) << '"'; //TODO: encode content
break;
case css::uno::TypeClass_TYPE:
out << o3tl::forceAccess<css::uno::Type>(value)->getTypeName();
break;
case css::uno::TypeClass_ANY:
out << value.getValueTypeName() << ": ";
printUnoValue(out, reflections, value.getValueType(), value);
break;
case css::uno::TypeClass_SEQUENCE:
{
css::uno::Reference<css::reflection::XIdlClass> const refl(
reflections->forName(type.getTypeName()), css::uno::UNO_SET_THROW);
auto const t = translateType(refl->getComponentType());
auto const array = refl->getArray();
auto const n = array->getLen(value);
out << '[';
for (sal_Int32 i = 0; i != n; ++i) {
if (i != 0) {
out << ", ";
}
printUnoValue(out, reflections, t, array->get(value, i));
}
out << ']';
break;
}
case css::uno::TypeClass_ENUM:
out << value.getValueTypeName() << ' ' << *static_cast<sal_Int32 const *>(value.getValue());
break;
case css::uno::TypeClass_STRUCT:
case css::uno::TypeClass_EXCEPTION:
{
auto first = true;
for (auto const & f: css::uno::Reference<css::reflection::XIdlClass>(
reflections->forName(type.getTypeName()),
css::uno::UNO_SET_THROW)->getFields())
{
if (first) {
first = false;
} else {
out << ", ";
}
out << f->getName() << ": ";
printUnoValue(out, reflections, translateType(f->getType()), f->get(value));
}
break;
}
case css::uno::TypeClass_INTERFACE:
out << '@' << value.getValue();
break;
default:
O3TL_UNREACHABLE;
}
} }
class Prot : public CppUnit::Protector class Prot : public CppUnit::Protector
@ -62,11 +167,23 @@ bool Prot::protect(
return functor(); return functor();
} catch (const css::uno::Exception &e) { } catch (const css::uno::Exception &e) {
css::uno::Any a(cppu::getCaughtException()); css::uno::Any a(cppu::getCaughtException());
std::ostringstream s;
try {
printUnoValue(
s,
css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext()),
cppu::UnoType<css::uno::Any>::get(), a);
} catch (css::uno::Exception &) {
// Best effort to print full details above; if that fails for whatever reason, print as
// much detailed information as possible, followed by at least the exception type and
// message:
s << "... " << a.getValueTypeName() << ": " << e.Message;
}
reportError( reportError(
context, context,
CppUnit::Message( CppUnit::Message(
"An uncaught exception of type " + convert(a.getValueTypeName()), "An uncaught UNO exception",
convert(e.Message))); s.str()));
} }
return false; return false;
} }