diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc index 4ecad25e239b7fc84f76dd4cbbe4921396a3aaa9..79561dfe2556fa2f90c6cff938f26771e5b11466 100644 --- a/compiler2/Setting.cc +++ b/compiler2/Setting.cc @@ -855,6 +855,11 @@ namespace Common { void Reference::set_code_section(GovernedSimple::code_section_t) { } + + Assignment* Reference::get_refd_assignment_last(bool check_parlist) + { + return this->get_refd_assignment(check_parlist); + } Ttcn::FieldOrArrayRefs *Reference::get_subrefs() { diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh index ca310331636b5c5e25839936edbd5e3afcf574df..2fd37243d61e81fae7de784a3b97acd74452e52c 100644 --- a/compiler2/Setting.hh +++ b/compiler2/Setting.hh @@ -700,6 +700,12 @@ public: * parameter list of the referred definition. The parameter checking is * done by default, but it can be disabled in certain cases. */ virtual Assignment* get_refd_assignment(bool check_parlist = true) = 0; + /** Returns the referred TTCN-3 definition or ASN.1 assignment. + * If there are references to class members or methods (in the subreferences), + * then the assignment at the end of the subreferences may differ from the + * referred assignment without subreferences. + * This function returns the assignment at the end of the subreferences. */ + virtual Assignment* get_refd_assignment_last(bool check_parlist = true); /** Returns the field or array subreferences of TTCN-3 references or NULL * otherwise. */ virtual Ttcn::FieldOrArrayRefs *get_subrefs(); diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index dda0e6eb1813175f77f6145266600543dc428220..942b4e2da079c1d1ecde0f729a0ab523b0713100 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -6145,41 +6145,7 @@ void Type::chk_this_template_ref(Template *t) // Do not check the actual parameter list of the reference yet to avoid // endless recursion in case of embedded circular references. // The parameter lists will be verified later. - Assignment *ass = v->get_reference()->get_refd_assignment(false); - if (ass != NULL && ass->get_asstype() == Assignment::A_VAR) { - // there could be class objects in the subreferences, which would change - // the type of the assignment (e.g. to a var template); - // use the assignment after the last class object in the subreference chain - Ttcn::FieldOrArrayRefs* subrefs = v->get_reference()->get_subrefs(); - if (subrefs != NULL) { - Type* type = ass->get_Type(); - if (type->get_field_type(subrefs, EXPECTED_DYNAMIC_VALUE) != NULL) { - // subrefs are valid - for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) { - type = type->get_type_refd_last(); - Ttcn::FieldOrArrayRef* subref = subrefs->get_ref(i); - switch (subref->get_type()) { - case Ttcn::FieldOrArrayRef::FIELD_REF: - case Ttcn::FieldOrArrayRef::FUNCTION_REF: - if (type->typetype == T_CLASS) { - ass = type->get_class_type_body()-> - get_local_ass_byId(*subref->get_id()); - type = ass->get_Type(); - } - else { - type = type->get_comp_byName(*subref->get_id())->get_type(); - } - break; - case Ttcn::FieldOrArrayRef::ARRAY_REF: - if (type->is_structured_type()) { - type = type->get_ofType(); - } - break; - } - } - } - } - } + Assignment *ass = v->get_reference()->get_refd_assignment_last(false); if (ass) { switch (ass->get_asstype()) { case Assignment::A_VAR_TEMPLATE: { diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 4ea2bde4f99fa552baf3480f56f93aab0143a3ed..9a5f9628fa8b60d5f23d373a1041a6bb6e29f013 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -875,6 +875,44 @@ namespace Ttcn { } return ass; } + + Common::Assignment* Reference::get_refd_assignment_last(bool check_parlist) + { + Common::Assignment* ass = get_refd_assignment(check_parlist); + if (ass != NULL && ass->get_asstype() == Common::Assignment::A_VAR && + subrefs.get_nof_refs() != 0) { + // there could be class objects in the subreferences, which would change + // the type of the last assignment + Type* type = ass->get_Type(); + if (type->get_field_type(&subrefs, Common::Type::EXPECTED_DYNAMIC_VALUE) != NULL) { + // subrefs are valid + // TODO: EXPECTED_DYNAMIC_VALUE in all cases? + for (size_t i = 0; i < subrefs.get_nof_refs(); ++i) { + type = type->get_type_refd_last(); + FieldOrArrayRef* subref = subrefs.get_ref(i); + switch (subref->get_type()) { + case FieldOrArrayRef::FIELD_REF: + case FieldOrArrayRef::FUNCTION_REF: + if (type->get_typetype() == Common::Type::T_CLASS) { + ass = type->get_class_type_body()-> + get_local_ass_byId(*subref->get_id()); + type = ass->get_Type(); + } + else { + type = type->get_comp_byName(*subref->get_id())->get_type(); + } + break; + case FieldOrArrayRef::ARRAY_REF: + if (type->is_structured_type()) { + type = type->get_ofType(); + } + break; + } + } + } + } + return ass; + } const Identifier* Reference::get_modid() { @@ -1228,16 +1266,9 @@ namespace Ttcn { expression_struct isbound_expr; Code::init_expr(&isbound_expr); - if (ass->get_Type()->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) { - isbound_expr.preamble = mputprintf(isbound_expr.preamble, - "boolean %s = %s != NULL_VALUE;\n", tmp_generalid_str, - ass_id_str); - } - else { - isbound_expr.preamble = mputprintf(isbound_expr.preamble, - "boolean %s = %s.is_bound();\n", tmp_generalid_str, - ass_id_str); - } + isbound_expr.preamble = mputprintf(isbound_expr.preamble, + "boolean %s = %s.is_bound();\n", tmp_generalid_str, + ass_id_str); namedbool p_optype; if (optype == Value::OPTYPE_ISBOUND) { p_optype = ISBOUND; diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index c7e856fe38fbf6495490f88eb91f0a9a15d330e5..75306d24c6507bfcf930a379c024051d5294fecc 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -367,6 +367,7 @@ namespace Ttcn { virtual void set_my_scope(Scope* p_scope); virtual string get_dispname(); virtual Common::Assignment *get_refd_assignment(bool check_parlist = true); + virtual Common::Assignment *get_refd_assignment_last(bool check_parlist = true); virtual reftype_t get_reftype() const { return reftype; } virtual void set_reftype(reftype_t p_reftype) { reftype = p_reftype; } virtual const Identifier* get_modid(); diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 4cc52b8e13bc7d60ef15e824b52d86b7602ab466..a7ffea6a497ceb9bb12b2686686905355abea7c1 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -8863,7 +8863,7 @@ error: void Assignment::chk_unknown_ass() { - Common::Assignment *t_ass = ref->get_refd_assignment(); + Common::Assignment *t_ass = ref->get_refd_assignment_last(); if (!t_ass) goto error; switch (t_ass->get_asstype()) { case Common::Assignment::A_ERROR: diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index 4770a8adc632fd5bcbe4ea78a824a746d9799db4..a1c734238f80e97f595fcdbd1d6bed37b197713a 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -2164,41 +2164,7 @@ namespace Ttcn { return true; } case TEMPLATE_REFD: { - Common::Assignment *ass = u.ref.ref->get_refd_assignment(); - if (ass->get_asstype() == Common::Assignment::A_VAR) { - // there could be class objects in the subreferences, which would change - // the type of the assignment (e.g. to a var template); - // use the assignment after the last class object in the subreference chain - FieldOrArrayRefs* subrefs = u.ref.ref->get_subrefs(); - if (subrefs != NULL) { - Type* type = ass->get_Type(); - if (type->get_field_type(subrefs, Common::Type::EXPECTED_DYNAMIC_VALUE) != NULL) { - // subrefs are valid - for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) { - type = type->get_type_refd_last(); - FieldOrArrayRef* subref = subrefs->get_ref(i); - switch (subref->get_type()) { - case FieldOrArrayRef::FIELD_REF: - case FieldOrArrayRef::FUNCTION_REF: - if (type->get_typetype() == Common::Type::T_CLASS) { - ass = type->get_class_type_body()-> - get_local_ass_byId(*subref->get_id()); - type = ass->get_Type(); - } - else { - type = type->get_comp_byName(*subref->get_id())->get_type(); - } - break; - case FieldOrArrayRef::ARRAY_REF: - if (type->is_structured_type()) { - type = type->get_ofType(); - } - break; - } - } - } - } - } + Common::Assignment *ass = u.ref.ref->get_refd_assignment_last(); switch (ass->get_asstype()) { case Common::Assignment::A_EXT_CONST: case Common::Assignment::A_PAR_VAL: diff --git a/core/OOP.hh b/core/OOP.hh index f5a03e74c26133c57f5ae736de0eb4be295fc9ce..52f2c223bfc05be35d7beede289f650c0ec70007 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -145,6 +145,18 @@ public: ptr->log(); } } + + boolean is_bound() const { + return ptr != NULL; + } + + boolean is_value() const { + return ptr != NULL; + } + + boolean is_present() const { + return ptr != NULL; + } }; template<typename T> diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index caea0ac18accd844afc4a0815db2d994c585ff74..c12cc587f68ba83705557a60eb5a68e4c3bfb104 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -382,6 +382,24 @@ type class C34 extends C25 { //^In type definition// } +type class C35 { + public const integer c := 3; + public template charstring t := ""; + public function f1() return Rec { return { 2, "a" }; } + public function f2() return template charstring { return ?; } + create() {} +} + +function f_left_hand_side() { //^In function definition// + var C35 x := C35.create; + x.c := 2; //^In variable assignment// //Reference to a variable or template variable was expected instead of constant `@oop_SE.C35.c'// + x.t := *; //^In variable assignment// //Reference to a variable or template variable was expected instead of template `@oop_SE.C35.t'// + x.f1() := { 3, "b" }; //^In variable assignment// //Reference to a variable or template variable was expected instead of function `@oop_SE.C35.f1'// + x.f1().num := 3; //^In variable assignment// //Reference to a variable or template variable was expected instead of function `@oop_SE.C35.f1'// + x.f2() := "x"; //^In variable assignment// //Reference to a variable or template variable was expected instead of function `@oop_SE.C35.f2'// +} + + 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.// } diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index 047ceadb4c1943d864e86aba03e88db72ceecc29..d16a79e01271207a359d84e672b2b472815680d7 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -315,6 +315,7 @@ testcase tc_references() runs on CT { var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0); var FinalClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *); + var BaseClass v_null := null; var BaseClass v_ref1; if (v_ref1 != null) { @@ -353,6 +354,24 @@ testcase tc_references() runs on CT { if (match(v_final.get_uni(), v_final.get_uni_temp())) { setverdict(fail, "#11, ", match(v_final.get_uni(), v_final.get_uni_temp())); } + if (not isbound(v_sub)) { + setverdict(fail, "#12"); + } + if (isbound(v_null)) { + setverdict(fail, "#13"); + } + if (not isvalue(v_final)) { + setverdict(fail, "#14"); + } + if (isvalue(v_null)) { + setverdict(fail, "#15"); + } + if (not ispresent(v_base)) { + setverdict(fail, "#16"); + } + if (ispresent(v_null)) { + setverdict(fail, "#17"); + } setverdict(pass); }