Commit 755065ad authored by Botond Baranyi's avatar Botond Baranyi

OOP: catching exceptions of class type is now determined by the dynamic class...

OOP: catching exceptions of class type is now determined by the dynamic class type, instead of the static type raised (issue #533)
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent d0937a26
......@@ -5578,9 +5578,18 @@ namespace Ttcn {
char* Def_Exception::generate_code_str(char *str)
{
return usage_found ? mputprintf(str, "EXCEPTION< %s >& %s = static_cast<EXCEPTION< %s >&>(exc_base);\n",
type->get_genname_value(my_scope).c_str(), id->get_name().c_str(), type->get_genname_value(my_scope).c_str()) :
str;
if (!usage_found) {
return str;
}
Common::Type* type_last = type->get_type_refd_last();
if (type_last->get_typetype() == Common::Type::T_CLASS) {
ClassTypeBody* class_ = type_last->get_class_type_body();
string class_name = class_->is_built_in() ? string("OBJECT") : type_last->get_genname_own(my_scope);
return mputprintf(str, "CLASS_EXCEPTION<%s> %s(exc_base.get_object_ref().cast_to_dyn<%s>());\n",
class_name.c_str(), id->get_name().c_str(), class_name.c_str());
}
return mputprintf(str, "NON_CLASS_EXCEPTION<%s>& %s = static_cast<NON_CLASS_EXCEPTION<%s>&>(exc_base);\n",
type->get_genname_value(my_scope).c_str(), id->get_name().c_str(), type->get_genname_value(my_scope).c_str());
}
// =================================
......
......@@ -594,7 +594,7 @@ namespace Ttcn {
// C++11 version:
string tmp_id = get_scope_mod_gen()->get_temporary_id();
str = mputprintf(str,
"FINALLY %s([&] {\n", tmp_id.c_str());
"FINALLY_CPP11 %s([&] {\n", tmp_id.c_str());
str = finally_block->generate_code(str, def_glob_vars, src_glob_vars);
str = mputstr(str, "});\n");
#endif
......@@ -630,9 +630,18 @@ namespace Ttcn {
"catch (EXCEPTION_BASE& exc_base) {\n");
for (size_t i = 0; i < catch_blocks.size(); ++i) {
Type* exc_type = catch_blocks[i]->get_stmt_byIndex(0)->get_def()->get_Type();
str = mputprintf(str,
"%sif (exc_base.has_type(\"%s\")) {\n",
i > 0 ? "else " : "", exc_type->get_exception_name().c_str());
Type* exc_type_last = exc_type->get_type_refd_last();
if (exc_type_last->get_typetype() == Common::Type::T_CLASS) {
ClassTypeBody* class_ = exc_type_last->get_class_type_body();
str = mputprintf(str,
"%sif (exc_base.is_class() && dynamic_cast<%s*>(exc_base.get_object()) != NULL) {\n",
i > 0 ? "else " : "", class_->is_built_in() ? "OBJECT" : exc_type_last->get_genname_own(this).c_str());
}
else {
str = mputprintf(str,
"%sif (exc_base.is_type(\"%s\")) {\n",
i > 0 ? "else " : "", exc_type->get_exception_name().c_str());
}
str = catch_blocks[i]->generate_code(str, def_glob_vars, src_glob_vars, alt_guards);
str = mputstr(str, "}\n");
}
......@@ -8742,32 +8751,18 @@ error:
str = mputstr(str, expr.preamble);
}
Common::Type* exc_type = raise_op.v->get_expr_governor(Common::Type::EXPECTED_DYNAMIC_VALUE);
Common::Type* exc_type_last = exc_type->get_type_refd_last();
string exc_type_str = exc_type->get_genname_value(my_sb);
string id_str = my_sb->get_scope_mod_gen()->get_temporary_id();
bool is_class = exc_type->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS;
// the EXCEPTION class stores all the superclasses of the class type, too, since those
// can also catch this type of exception
int nof_exc_types = 1;
Type* t;
if (is_class) {
t = exc_type;
while (t != NULL) {
++nof_exc_types;
t = t->get_type_refd_last()->get_class_type_body()->get_base_type();
}
}
str = mputprintf(str, "const char** %s = new const char*[%i];\n",
id_str.c_str(), nof_exc_types);
t = exc_type;
for (int i = 0; i < nof_exc_types; ++i) {
if (i > 0) {
t = t->get_type_refd_last()->get_class_type_body()->get_base_type();
}
str = mputprintf(str, "%s[%i] = \"%s\";\n",
id_str.c_str(), i, t != NULL ? t->get_exception_name().c_str() : "object");
}
str = mputprintf(str, "throw EXCEPTION< %s >(new %s(%s), %s, %i);\n",
exc_type_str.c_str(), exc_type_str.c_str(), expr.expr, id_str.c_str(), nof_exc_types);
if (exc_type_last->get_typetype() == Common::Type::T_CLASS) {
ClassTypeBody* class_ = exc_type_last->get_class_type_body();
str = mputprintf(str, "throw CLASS_EXCEPTION<%s>(new %s(%s));\n",
class_->is_built_in() ? "OBJECT" : exc_type_last->get_genname_own(my_sb).c_str(),
exc_type_str.c_str(), expr.expr);
}
else {
str = mputprintf(str, "throw NON_CLASS_EXCEPTION< %s >(new %s(%s), \"%s\");\n",
exc_type_str.c_str(), exc_type_str.c_str(), expr.expr, exc_type->get_exception_name().c_str());
}
if (expr.postamble != NULL) {
str = mputstr(str, expr.postamble);
}
......
......@@ -208,6 +208,18 @@ public:
}
return OBJECT_REF<T2>(new_ptr);
}
template<typename T2>
OBJECT_REF<T2>* cast_to_dyn() const {
if (ptr == NULL) {
TTCN_error("Internal error: Casting a null reference");
}
T2* new_ptr = dynamic_cast<T2*>(ptr);
if (new_ptr == NULL) {
TTCN_error("Internal error: Invalid casting to class type `%s'", T2::class_name());
}
return new OBJECT_REF<T2>(new_ptr);
}
};
template<typename T>
......@@ -224,73 +236,102 @@ boolean operator!=(null_type, const OBJECT_REF<T>& right_val) { // inequality op
// ---------
class EXCEPTION_BASE {
private:
const char** exc_types;
size_t nof_types;
protected:
CHARSTRING exception_log; // this is set by the EXCEPTION class
public:
EXCEPTION_BASE(const char** p_exc_types, size_t p_nof_types)
: exc_types(p_exc_types), nof_types(p_nof_types) { }
EXCEPTION_BASE(const EXCEPTION_BASE& p)
: exc_types(new const char*[p.nof_types]), nof_types(p.nof_types), exception_log(p.exception_log) {
for (size_t i = 0; i < nof_types; ++i) {
exc_types[i] = p.exc_types[i];
}
EXCEPTION_BASE() { }
EXCEPTION_BASE(const EXCEPTION_BASE& p): exception_log(p.exception_log) { }
virtual ~EXCEPTION_BASE() { }
CHARSTRING get_log() const { return exception_log; }
virtual boolean is_class() const { return FALSE; }
virtual boolean is_type(const char* p_type_name) const { return FALSE; }
virtual OBJECT* get_object() const { return NULL; }
virtual OBJECT_REF<OBJECT> get_object_ref() { return OBJECT_REF<OBJECT>(); }
};
template<typename T>
class NON_CLASS_EXCEPTION : public EXCEPTION_BASE {
public:
struct exception_struct {
T* val_ptr;
size_t ref_count;
};
private:
exception_struct* exc_ptr;
const char* type_name;
NON_CLASS_EXCEPTION operator=(const NON_CLASS_EXCEPTION&); // assignment disabled
public:
NON_CLASS_EXCEPTION(T* p_value, const char* p_type_name)
: EXCEPTION_BASE(), exc_ptr(new exception_struct), type_name(p_type_name) {
exc_ptr->val_ptr = p_value;
exc_ptr->ref_count = 1;
exception_log = (TTCN_Logger::begin_event_log2str(),
p_value->log(), TTCN_Logger::end_event_log2str());
}
~EXCEPTION_BASE() {
delete exc_types;
NON_CLASS_EXCEPTION(const NON_CLASS_EXCEPTION& p)
: EXCEPTION_BASE(p), exc_ptr(p.exc_ptr), type_name(p.type_name) {
++exc_ptr->ref_count;
}
CHARSTRING get_log() const { return exception_log; }
boolean has_type(const char* type_name) const {
for (size_t i = 0; i < nof_types; ++i) {
if (strcmp(exc_types[i], type_name) == 0) {
return TRUE;
}
virtual ~NON_CLASS_EXCEPTION() {
--exc_ptr->ref_count;
if (exc_ptr->ref_count == 0) {
delete exc_ptr->val_ptr;
delete exc_ptr;
}
return FALSE;
}
T& operator()() { return *exc_ptr->val_ptr; }
virtual boolean is_type(const char* p_type_name) const {
return strcmp(p_type_name, type_name) == 0;
}
};
template<typename T>
class EXCEPTION : public EXCEPTION_BASE {
class CLASS_EXCEPTION : public EXCEPTION_BASE {
public:
struct exception_struct {
T* val_ptr;
OBJECT_REF<T>* val_ptr;
size_t ref_count;
};
private:
exception_struct* exc_ptr;
EXCEPTION operator=(const EXCEPTION&); // assignment disabled
CLASS_EXCEPTION operator=(const CLASS_EXCEPTION&); // assignment disabled
public:
EXCEPTION(T* p_value, const char** p_exc_types, size_t p_nof_types)
: EXCEPTION_BASE(p_exc_types, p_nof_types), exc_ptr(new exception_struct) {
CLASS_EXCEPTION(OBJECT_REF<T>* p_value)
: EXCEPTION_BASE(), exc_ptr(new exception_struct) {
exc_ptr->val_ptr = p_value;
exc_ptr->ref_count = 1;
exception_log = (TTCN_Logger::begin_event_log2str(),
p_value->log(), TTCN_Logger::end_event_log2str());
}
EXCEPTION(const EXCEPTION& p)
CLASS_EXCEPTION(const CLASS_EXCEPTION& p)
: EXCEPTION_BASE(p), exc_ptr(p.exc_ptr) {
++exc_ptr->ref_count;
}
~EXCEPTION() {
virtual ~CLASS_EXCEPTION() {
--exc_ptr->ref_count;
if (exc_ptr->ref_count == 0) {
delete exc_ptr->val_ptr;
delete exc_ptr;
}
}
T& operator()() { return *exc_ptr->val_ptr; }
OBJECT_REF<T>& operator()() { return *exc_ptr->val_ptr; }
virtual boolean is_class() const { return TRUE; }
virtual OBJECT* get_object() const {
return **exc_ptr->val_ptr;
}
virtual OBJECT_REF<OBJECT> get_object_ref() {
return exc_ptr->val_ptr->template cast_to<OBJECT>();
}
};
#if __cplusplus >= 201103L
class FINALLY
class FINALLY_CPP11
{
std::function<void(void)> functor;
public:
FINALLY(const std::function<void(void)> &p_functor) : functor(p_functor) {}
~FINALLY()
FINALLY_CPP11(const std::function<void(void)> &p_functor) : functor(p_functor) {}
~FINALLY_CPP11()
{
try {
functor();
......
......@@ -76,6 +76,10 @@ function test_block(in integer p_exception_type, in charstring p_dummy := "a") r
case (8) {
raise Class2.create;
}
case (9) {
var object x := Class.create();
raise x;
}
}
// otherwise don't raise anything
}
......@@ -129,12 +133,12 @@ function test_block(in integer p_exception_type, in charstring p_dummy := "a") r
}
testcase tc_exceptions_block() runs on CT {
for (var integer i := 1; i <= 8; i := i + 1) {
for (var integer i := 1; i <= 9; i := i + 1) {
test_block(i);
}
test_block(200);
if (cv_finally_counter != 9) {
if (cv_finally_counter != 10) {
setverdict(fail, "Invalid 'finally' execution count: ", cv_finally_counter);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment