diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index db942e97c2b597894f458d07257f9f23661fab51..258b87c7bc38eb29a216b4eaef41d002d94d0f4d 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -7168,18 +7168,9 @@ namespace Ttcn { return false; } FormalParList* other_fp_list = p_other->get_FormalParList(); - if (other_fp_list->get_nof_fps() != fp_list->get_nof_fps()) { + if (!fp_list->is_identical(other_fp_list)) { return false; } - for (size_t i = 0; i < fp_list->get_nof_fps(); ++i) { - FormalPar* fp1 = fp_list->get_fp_byIndex(i); - FormalPar* fp2 = other_fp_list->get_fp_byIndex(i); - if (fp1->get_asstype() != fp2->get_asstype() || - !fp1->get_Type()->is_identical(fp2->get_Type()) || - fp1->get_id().get_name() != fp2->get_id().get_name()) { - return false; - } - } if (exceptions != NULL || p_other->exceptions != NULL) { if (exceptions == NULL || p_other->exceptions == NULL) { // one of them has exceptions, the other doesn't @@ -10881,6 +10872,26 @@ namespace Ttcn { || parent_scope->has_ass_withId(p_id); } + bool FormalParList::is_identical(const FormalParList* p_other) + { + if (p_other == NULL) { + FATAL_ERROR("FormalParList::is_identical"); + } + if (p_other->pars_v.size() != pars_v.size()) { + return false; + } + for (size_t i = 0; i < pars_v.size(); ++i) { + FormalPar* fp1 = pars_v[i]; + FormalPar* fp2 = p_other->pars_v[i]; + if (fp1->get_asstype() != fp2->get_asstype() || + !fp1->get_Type()->is_identical(fp2->get_Type()) || + fp1->get_id().get_name() != fp2->get_id().get_name()) { + return false; + } + } + return true; + } + void FormalParList::set_genname(const string& p_prefix) { for (size_t i = 0; i < pars_v.size(); i++) { diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index e0500a1d7e800abb9d19707dc172cdf8c3b49cbd..6a735abe8af65dd14b53211291af82752795d614 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -2022,6 +2022,7 @@ namespace Ttcn { bool get_startability(); virtual Common::Assignment *get_ass_bySRef(Common::Ref_simple *p_ref); virtual bool has_ass_withId(const Identifier& p_id); + bool is_identical(const FormalParList* p_other); /** Checks the parameter list, which belongs to definition of type * \a deftype. */ void chk(Definition::asstype_t deftype); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index cc737ae0ebdc2e27241503d226612bf65cdaa8f2..2899e814d6db78678c0f5f7f5f04b3960ab9dd58 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3832,6 +3832,43 @@ namespace Ttcn { } } + // check overriding/shadowing of 'object' methods + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* def = members->get_ass_byIndex(i, false); + const Common::Identifier& id = def->get_id(); + FormalParList* fp_list = get_object_method_fplist(id.get_name()); + if (fp_list != NULL) { + switch (def->get_asstype()) { + case Common::Assignment::A_FUNCTION_RVAL: + case Common::Assignment::A_EXT_FUNCTION_RVAL: + if (def->get_visibility() == PUBLIC && + fp_list->is_identical(def->get_FormalParList())) { + Def_Function_Base* def_func = dynamic_cast<Def_Function_Base*>(def); + Def_AbsFunction* def_func_abs = dynamic_cast<Def_AbsFunction*>(def_func); + if (def_func_abs == NULL && + def_func->get_return_type()->is_identical(get_object_method_return_type(id.get_name()))) { + break; // everything is in order + } + } + // otherwise fall through and display the prototype error + case Common::Assignment::A_FUNCTION: + case Common::Assignment::A_FUNCTION_RTEMP: + case Common::Assignment::A_EXT_FUNCTION: + case Common::Assignment::A_EXT_FUNCTION_RTEMP: + // currently all 'object' methods return a value, so these are erroneous by default + def->error("The prototype of method `%s' is not identical " + "to that of the method inherited from the 'object' class", + id.get_dispname().c_str()); + break; + default: + def->error("%s shadows a method inherited from the 'object' class", + def->get_description().c_str()); + name_clash = true; + break; + } + } + } + if (constructor != NULL && trait) { constructor->error("Trait class type `%s' cannot have a constructor", my_def->get_Type()->get_typename().c_str()); diff --git a/core/OOP.hh b/core/OOP.hh index 239ea48b333a45d74671e7cdbcbcfc414966c7b9..d8a9724ff7399daed984993f45478e962e43596b 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -126,7 +126,7 @@ public: TTCN_error("Accessing a null reference."); } - const T* operator*() const { // de-referencing operator (for OBJECT::equals + const T* operator*() const { // de-referencing operator (for OBJECT::equals) return ptr; } diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index c48065cd1912b739388315f0b868190f84c5513b..6ea5247b4bcbaca41ed42f7186dfc0d0c241e239 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -811,6 +811,20 @@ type class C65 { //^In type definition// out charstring p2) { } //^In parameter// //A constructor cannot have `out' value parameter// } +type class C66 { //^In type definition// + public function toString(in universal charstring prefix) return universal charstring { //The prototype of method `toString' is not identical to that of the method inherited from the 'object' class// + return prefix & "C66"; + } + public function equals(object obj) return integer { //The prototype of method `equals' is not identical to that of the method inherited from the 'object' class// + return -1; + } +} + +type class @abstract C67 { //^In type definition// + private var boolean equals; //variable `@oop_SE.C67.equals' shadows a method inherited from the 'object' class// + public function @abstract toString() return universal charstring; //The prototype of method `toString' is not identical to that of the method inherited from the 'object' class// +} + control { //^In control part// var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.//