Commit 8abd72b8 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

disallowed the usage of '*' in receive, getreply, catch and done (artf433757)



Change-Id: I9583325c6b0778313b9e90bcb0dd90d9cb4ceb27
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 9e26131c
......@@ -2254,6 +2254,8 @@ void Type::generate_code_done(output_struct *target)
"if (!component_reference.is_bound()) "
"TTCN_error(\"Performing a done operation on an unbound component "
"reference.\");\n"
"if (value_template.get_selection() == ANY_OR_OMIT) "
"TTCN_error(\"Done operation using '*' as matching template\");\n"
"Text_Buf *text_buf;\n"
"alt_status ret_val = TTCN_Runtime::component_done("
"(component)component_reference, \"%s\", text_buf);\n"
......
......@@ -3318,7 +3318,7 @@ error:
msg_type = out_msgs->get_type_byIndex(0);
} else {
// there are more than one outgoing message types
msg_type = get_outgoing_type(port_op.s.sendpar);
msg_type = get_msg_sig_type(port_op.s.sendpar);
if (msg_type) {
size_t nof_comp_types =
out_msgs->get_nof_compatible_types(msg_type);
......@@ -3351,7 +3351,7 @@ error:
}
// determining the message type if it is not done so far
if (!msg_type_determined) {
msg_type = get_outgoing_type(port_op.s.sendpar);
msg_type = get_msg_sig_type(port_op.s.sendpar);
}
if (!msg_type) msg_type = Type::get_pooltype(Type::T_ERROR);
// checking the parameter (template instance)
......@@ -3396,7 +3396,7 @@ error:
signature = out_sigs->get_type_byIndex(0);
} else {
// there are more than one outgoing signatures
signature = get_outgoing_type(port_op.s.sendpar);
signature = get_msg_sig_type(port_op.s.sendpar);
if (signature) {
if (!out_sigs->has_type(signature)) {
port_op.s.sendpar->error("Signature `%s' is not present on the "
......@@ -3421,7 +3421,7 @@ error:
}
}
if (!signature_determined)
signature = get_outgoing_type(port_op.s.sendpar);
signature = get_msg_sig_type(port_op.s.sendpar);
if (!signature) signature = Type::get_pooltype(Type::T_ERROR);
// checking the parameter (template instance)
port_op.s.sendpar->chk(signature);
......@@ -3504,7 +3504,7 @@ error:
signature = in_sigs->get_type_byIndex(0);
} else {
// there are more than one incoming signatures
signature = get_outgoing_type(port_op.s.sendpar);
signature = get_msg_sig_type(port_op.s.sendpar);
if (signature) {
if (!in_sigs->has_type(signature)) {
port_op.s.sendpar->error("Signature `%s' is not present on the "
......@@ -3529,7 +3529,7 @@ error:
}
}
if (!signature_determined)
signature = get_outgoing_type(port_op.s.sendpar);
signature = get_msg_sig_type(port_op.s.sendpar);
if (!signature) signature = Type::get_pooltype(Type::T_ERROR);
// checking the parameter (template instance)
port_op.s.sendpar->chk(signature);
......@@ -3625,7 +3625,7 @@ error:
exc_type = exceptions->get_type_byIndex(0);
} else {
// the signature has more than one exception types
exc_type = get_outgoing_type(port_op.s.sendpar);
exc_type = get_msg_sig_type(port_op.s.sendpar);
if (exc_type) {
size_t nof_comp_types =
exceptions->get_nof_compatible_types(exc_type);
......@@ -3653,7 +3653,7 @@ error:
}
// determining the type of exception if it is not done so far
if (!exc_type_determined) {
exc_type = get_outgoing_type(port_op.s.sendpar);
exc_type = get_msg_sig_type(port_op.s.sendpar);
}
if (!exc_type) exc_type = Type::get_pooltype(Type::T_ERROR);
// checking the exception template
......@@ -3707,7 +3707,7 @@ error:
msg_type = in_msgs->get_type_byIndex(0);
} else {
// there are more than one incoming message types
msg_type = get_incoming_type(port_op.r.rcvpar, port_op.r.redirect.value);
msg_type = get_msg_sig_type(port_op.r.rcvpar);
if (msg_type) {
size_t nof_comp_types =
in_msgs->get_nof_compatible_types(msg_type);
......@@ -3747,11 +3747,16 @@ error:
}
}
if (!msg_type_determined) {
msg_type = get_incoming_type(port_op.r.rcvpar, port_op.r.redirect.value);
msg_type = get_msg_sig_type(port_op.r.rcvpar);
}
if (!msg_type) msg_type = Type::get_pooltype(Type::T_ERROR);
// check the template instance using the message type
port_op.r.rcvpar->chk(msg_type);
if (port_op.r.rcvpar->get_Template()->get_template_refd_last()->
get_templatetype() == Template::ANY_OR_OMIT) {
port_op.r.rcvpar->error("'*' cannot be used as a matching template "
"for a '%s' operation", stmt_name);
}
// check the value redirect if it exists
if (port_op.r.redirect.value != NULL) {
port_op.r.redirect.value->chk(msg_type);
......@@ -3805,7 +3810,7 @@ error:
signature = in_sigs->get_type_byIndex(0);
} else {
// there are more than one incoming signatures
signature = get_outgoing_type(port_op.r.rcvpar);
signature = get_msg_sig_type(port_op.r.rcvpar);
if (signature) {
if (!in_sigs->has_type(signature)) {
port_op.r.rcvpar->error("Signature `%s' is not present on the "
......@@ -3838,7 +3843,7 @@ error:
}
}
if (!signature_determined)
signature = get_outgoing_type(port_op.r.rcvpar);
signature = get_msg_sig_type(port_op.r.rcvpar);
if (!signature) signature = Type::get_pooltype(Type::T_ERROR);
// checking the parameter (template instance)
port_op.r.rcvpar->chk(signature);
......@@ -3909,7 +3914,7 @@ error:
signature = out_sigs->get_type_byIndex(0);
} else {
// there are more than one outgoing signatures
signature = get_outgoing_type(port_op.r.rcvpar);
signature = get_msg_sig_type(port_op.r.rcvpar);
if (signature) {
if (!out_sigs->has_type(signature)) {
port_op.r.rcvpar->error("Signature `%s' is not present on the "
......@@ -3950,7 +3955,7 @@ error:
}
}
if (!signature_determined)
signature = get_outgoing_type(port_op.r.rcvpar);
signature = get_msg_sig_type(port_op.r.rcvpar);
if (!signature) signature = Type::get_pooltype(Type::T_ERROR);
// checking the parameter (template instance)
port_op.r.rcvpar->chk(signature);
......@@ -3995,6 +4000,11 @@ error:
Error_Context cntxt2(port_op.s.replyval, "In value match");
if (!return_type) return_type = Type::get_pooltype(Type::T_ERROR);
port_op.r.getreply_valuematch->chk(return_type);
if (port_op.r.getreply_valuematch->get_Template()->get_template_refd_last()->
get_templatetype() == Template::ANY_OR_OMIT) {
port_op.r.getreply_valuematch->error("'*' cannot be used as a return "
"value matching template for a '%s' operation", stmt_name);
}
}
// checking the value redirect if present
if (port_op.r.redirect.value != NULL) {
......@@ -4098,7 +4108,7 @@ error:
exc_type = exceptions->get_type_byIndex(0);
} else {
// the signature has more than one exception types
exc_type = get_incoming_type(port_op.r.rcvpar, port_op.r.redirect.value);
exc_type = get_msg_sig_type(port_op.r.rcvpar);
if (exc_type) {
size_t nof_comp_types =
exceptions->get_nof_compatible_types(exc_type);
......@@ -4125,11 +4135,16 @@ error:
}
}
if (!exc_type_determined) {
exc_type = get_incoming_type(port_op.r.rcvpar, port_op.r.redirect.value);
exc_type = get_msg_sig_type(port_op.r.rcvpar);
}
if (!exc_type) exc_type = Type::get_pooltype(Type::T_ERROR);
// check the template instance using the exception type
port_op.r.rcvpar->chk(exc_type);
if (port_op.r.rcvpar->get_Template()->get_template_refd_last()->
get_templatetype() == Template::ANY_OR_OMIT) {
port_op.r.rcvpar->error("'*' cannot be used as a matching template for "
"a '%s' operation", stmt_name);
}
// check the value redirect if it exists
if (port_op.r.redirect.value != NULL) {
port_op.r.redirect.value->chk(exc_type);
......@@ -4405,8 +4420,7 @@ error:
// specific component reference
if (comp_op.donereturn.donematch) {
// try to determine the type of the return value
Type *return_type = get_incoming_type(comp_op.donereturn.donematch,
comp_op.donereturn.redirect);
Type *return_type = get_msg_sig_type(comp_op.donereturn.donematch);
if (return_type) {
bool return_type_correct = false;
for (Type *t = return_type; ; t = t->get_type_refd()) {
......@@ -4426,6 +4440,11 @@ error:
return_type = Type::get_pooltype(Type::T_ERROR);
}
comp_op.donereturn.donematch->chk(return_type);
if (comp_op.donereturn.donematch->get_Template()->get_template_refd_last()->
get_templatetype() == Template::ANY_OR_OMIT) {
comp_op.donereturn.donematch->error("'*' cannot be used as a matching "
"template for a 'done' operation");
}
if (comp_op.donereturn.redirect != NULL) {
comp_op.donereturn.redirect->chk(return_type);
}
......@@ -4977,7 +4996,7 @@ error:
"not caught");
}
Type *Statement::get_outgoing_type(TemplateInstance *p_ti)
Type *Statement::get_msg_sig_type(TemplateInstance *p_ti)
{
// first analyze the template instance as is
Type *ret_val = p_ti->get_expr_governor(Type::EXPECTED_TEMPLATE);
......@@ -4990,27 +5009,6 @@ error:
return t_templ->get_expr_governor(Type::EXPECTED_TEMPLATE);
}
Type *Statement::get_incoming_type(TemplateInstance *p_ti,
ValueRedirect *p_val_redir)
{
// first analyze the template instance
Type *ret_val = p_ti->get_expr_governor(Type::EXPECTED_TEMPLATE);
// return if this step was successful
if (ret_val) return ret_val;
// try to convert the undef identifier in the template instance to
// a reference because it cannot be an enum value anymore
Template *t_templ = p_ti->get_Template();
t_templ->set_lowerid_to_ref();
ret_val = t_templ->get_expr_governor(Type::EXPECTED_TEMPLATE);
// return if this step was successful
if (ret_val) return ret_val;
// finally try to determine the type from the value redirect
if (p_val_redir != NULL) {
ret_val = p_val_redir->get_type();
}
return ret_val;
}
Type *Statement::chk_sender_redirect(Type *address_type)
{
if (!port_op.r.redirect.sender) return 0;
......
......@@ -700,13 +700,9 @@ namespace Ttcn {
* operation. Arguments \a port_type \a signature point to the
* port type and signature used in the call operation. */
void chk_call_body(Type *port_type, Type *signature);
/** Determines and returns the type of the outgoing message or
/** Determines and returns the type of the incoming or outgoing message or
* signature based on a template instance \a p_ti. */
static Type *get_outgoing_type(TemplateInstance *p_ti);
/** Determines and returns the type of the incoming message or
* signature based on a template instance \a p_ti and an optional
* value redirect \a p_val_redir. */
Type *get_incoming_type(TemplateInstance *p_ti, ValueRedirect *p_val_redir);
static Type *get_msg_sig_type(TemplateInstance *p_ti);
/** Checks the variable reference of a sender redirect. The type
* of the variable (or NULL in case of non-existent sender clause
* or error) is returned. The type of the variable is also
......
......@@ -1867,6 +1867,7 @@ namespace Ttcn {
signature->is_nonblocking_signature();
pdef.proc_in.elements[i].has_exceptions =
signature->get_signature_exceptions() ? TRUE : FALSE;
pdef.proc_in.elements[i].has_return_value = FALSE;
}
} else {
pdef.proc_in.nElements = 0;
......@@ -1886,6 +1887,8 @@ namespace Ttcn {
signature->is_nonblocking_signature();
pdef.proc_out.elements[i].has_exceptions =
signature->get_signature_exceptions() ? TRUE : FALSE;
pdef.proc_out.elements[i].has_return_value =
signature->get_signature_return_type() != NULL ? TRUE : FALSE;
}
} else {
pdef.proc_out.nElements = 0;
......
......@@ -573,6 +573,8 @@ static void generate_receive(char **def_ptr, char **src_ptr,
"value_template, %s_Redirect_Interface *value_redirect, const %s_template& "
"sender_template, %s *sender_ptr)\n"
"{\n"
"if (value_template.get_selection() == ANY_OR_OMIT) "
"TTCN_error(\"%s operation using '*' as matching template\");\n"
"msg_queue_item *my_head = (msg_queue_item*)msg_queue_head;\n"
"if (msg_queue_head == NULL) {\n"
"if (is_started) return ALT_MAYBE;\n"
......@@ -583,7 +585,7 @@ static void generate_receive(char **def_ptr, char **src_ptr,
"return ALT_NO;\n"
"}\n"
"} else ", class_name, function_name, message_type->name,
message_type->name_w_no_prefix, sender_type, sender_type);
message_type->name_w_no_prefix, sender_type, sender_type, operation_name);
if (is_address) {
src = mputprintf(src, "if (my_head->sender_component != "
"SYSTEM_COMPREF) {\n"
......@@ -1099,16 +1101,23 @@ static void generate_getreply(char **def_ptr, char **src_ptr,
src = mputprintf(src, "alt_status %s::%s(const %s_template& "
"getreply_template, const %s_template& sender_template, "
"const %s_reply_redirect& param_ref, %s *sender_ptr)\n"
"{\n"
"{\n", class_name, function_name, signature->name, sender_type,
signature->name, sender_type);
if (signature->has_return_value) {
src = mputprintf(src,
"if (getreply_template.return_value().get_selection() == ANY_OR_OMIT) "
"TTCN_error(\"%s operation using '*' as return value matching template\");\n",
operation_name);
}
src = mputstr(src,
"if (proc_queue_head == NULL) {\n"
"if (is_started) return ALT_MAYBE;\n"
"else {\n"
"TTCN_Logger::log(TTCN_Logger::MATCHING_PROBLEM, \"Matching on "
"port %%s failed: Port is not started and the queue is empty.\", "
"port %s failed: Port is not started and the queue is empty.\", "
"port_name);\n"
"return ALT_NO;\n"
"}\n", class_name, function_name, signature->name, sender_type,
signature->name, sender_type);
"}\n");
if (is_address) {
src = mputprintf(src,
"} else if (proc_queue_head->sender_component != SYSTEM_COMPREF) "
......@@ -1221,6 +1230,8 @@ static void generate_catch(char **def_ptr, char **src_ptr,
"catch_template, const %s_template& sender_template, "
"%s *sender_ptr)\n"
"{\n"
"if (catch_template.is_any_or_omit()) TTCN_error(\"%s operation using '*' "
"as matching template\");\n"
"if (proc_queue_head == NULL) {\n"
"if (is_started) return ALT_MAYBE;\n"
"else {\n"
......@@ -1229,7 +1240,7 @@ static void generate_catch(char **def_ptr, char **src_ptr,
"port_name);\n"
"return ALT_NO;\n"
"}\n", class_name, function_name, signature->name, sender_type,
sender_type);
sender_type, operation_name);
if (is_address) {
src = mputprintf(src,
"} else if (proc_queue_head->sender_component != SYSTEM_COMPREF) "
......
......@@ -76,6 +76,7 @@ typedef struct port_proc_signature_tag {
const char *dispname;
boolean is_noblock;
boolean has_exceptions;
boolean has_return_value;
} port_proc_signature;
typedef struct port_proc_signature_list_tag {
......
......@@ -689,7 +689,6 @@ void defSignatureClasses(const signature_def *sdef, output_struct *output)
/* value redirect base classes (interfaces) */
for (i = 0; i < sdef->exceptions.nElements; i++) {
def = mputprintf(def,
"public:\n"
"class %s_Redirect_Interface {\n"
"public:\n"
"virtual void set_values(const %s&) = 0;\n"
......@@ -853,6 +852,27 @@ void defSignatureClasses(const signature_def *sdef, output_struct *output)
"value redirect on an exception of signature %s.\");\n"
"}\n\n", dispname);
/* is_any_or_omit function */
def = mputprintf(def, "boolean is_any_or_omit() const;\n");
src = mputprintf(src,
"boolean %s_exception_template::is_any_or_omit() const\n"
"{\n"
"switch (exception_selection) {\n", name);
for (i = 0; i < sdef->exceptions.nElements; i++) {
src = mputprintf(src,
"case %s_%s:\n"
"return field_%s->get_selection() == ANY_OR_OMIT;\n",
selection_prefix, sdef->exceptions.elements[i].altname,
sdef->exceptions.elements[i].altname);
}
src = mputprintf(src,
"default:\n"
"break;\n"
"}\n"
"TTCN_error(\"Internal error: Invalid selector when checking for '*' in "
"an exception template of signature %s.\");\n"
"}\n\n", dispname);
def = mputstr(def, "};\n\n");
/* end of class xxx_exception_template */
......
......@@ -6863,7 +6863,7 @@ module ModuleA {
var MyCompType MyVar2;
}
// others should be covered in 'VariableRef'
altstep MyAltstep41() runs on MyCompType {[] MyPort2.catch(MyProc2, ?) -> value MyVar1 sender Nonexi41 {}}
altstep MyAltstep41() runs on MyCompType {[] MyPort2.catch(MyProc2, MyType1: ?) -> value MyVar1 sender Nonexi41 {}}
}
<END_MODULE>
<RESULT IF_PASS COUNT 1>
......
......@@ -565,14 +565,14 @@ testcase TC() runs on MyComponent {
var float F;
alt {
[]any port.receive(integer:?) -> value I { }
[]any port.check(receive(integer:*) -> value I) { }
[]any port.check(receive(integer:?) -> value I) { }
[]any port.getcall(Sig:{0}) -> param(I) { }
[]any port.getreply(Sig:{0}) -> value J param(I) { }
[]any port.catch(Sig, float:*) -> value F { }
[]any port.catch(Sig, float:?) -> value F { }
[]any port.check(getcall(Sig:{0}) -> param(I)) { }
[]any port.check(getreply(Sig:{0}) -> value J param(I)) { }
[]any port.check(catch(Sig, float:*) -> value F) { }
[]any port.check(catch(Sig, float:?) -> value F) { }
}
}
......@@ -1374,6 +1374,80 @@ testcase TC() runs on MyComponent {
:exmp.
.*---------------------------------------------------------------------*
:h3.Adhoc - port operation: '*' in matching template
.*---------------------------------------------------------------------*
:xmp tab=0.
<TC - Adhoc - port operation: '*' in matching template>
<COMPILE>
<VERDICT_LEAF PASS>
<MODULE TTCN Temp Temp.ttcn>
module Temp {
type port PT message {
inout integer, charstring
}
signature sig() return integer exception (integer, charstring);
type port PT2 procedure {
inout sig
}
type component CT {
port PT pt;
port PT2 pt2;
}
template integer t := *;
testcase TC() runs on CT {
var integer x;
alt {
[] pt.receive(*) { }
[] pt.receive(integer: *) -> value x { }
[] pt.receive(t) { }
[] pt2.getreply(sig: { } value *) -> value x { }
[] pt2.getreply(sig: { } value integer: *) { }
[] pt2.getreply(sig: { } value t) -> value x { }
[] pt2.catch(sig, *) { }
[] pt2.catch(sig, integer: *) -> value x { }
[] pt2.catch(sig, t) { }
[] pt.check(receive(*) -> value x) { }
[] pt.check(receive(integer: *)) { }
[] pt.check(receive(t) -> value x) { }
[] pt2.check(getreply(sig: { } value *)) { }
[] pt2.check(getreply(sig: { } value integer: *) -> value x) { }
[] pt2.check(getreply(sig: { } value t)) { }
[] pt2.check(catch(sig, *) -> value x) { }
[] pt2.check(catch(sig, integer: *)) { }
[] pt2.check(catch(sig, t) -> value x) { }
}
}
}
<END_MODULE>
<RESULT COUNT 2>
(?im)Cannot.+?\bdetermine\b.+?the.+?\btype\b.+?of.+?the\b.+?incoming\b.+?message
<END_RESULT>
<RESULT COUNT 2>
(?im)Cannot.+?\bdetermine\b.+?the.+?\btype\b.+?of.+?the\b.+?exception
<END_RESULT>
<RESULT COUNT 18>
(?im)\'\*\'.+?\bcannot\b.+?be.+?\bused\b.+?as.+?matching\b.+?template\b.+?for\b.+?operation
<END_RESULT>
<RESULT COUNT 22>
(?is)\berror:
<END_RESULT>
<RESULT>
(?im)\bnotify\b.+?\bcode\b.+?\bnot\b.+?\bgenerated\b
<END_RESULT>
<END_TC>
:exmp.
.*---------------------------------------------------------------------*
:h3.Adhoc - component operation in control part
.*---------------------------------------------------------------------*
......
......@@ -1609,6 +1609,46 @@ testcase commMessageDecodedValueRedirect() runs on commMessage_comp_dec {
setverdict(pass);
}
// '*' is not allowed as a matching template in receive operations
testcase commMessageReceiveAnyOrOmit() runs on commMessage_comp1 {
connect(self:Port1, self:Port1);
var template integer vt := *;
// receive
Port1.send(5);
@try {
alt {
[] Port1.receive(vt) { }
}
setverdict(fail, "Receive operation succeeded. Expected error.");
}
@catch (msg) {
if (match(msg, pattern "*Receive operation using '\*' as matching template")) {
setverdict(pass);
}
else {
setverdict(fail, "Incorrect error message received (receive test): ", msg);
}
}
// check-receive
Port1.send(5);
@try {
alt {
[] Port1.check(receive(vt)) { }
}
setverdict(fail, "Check-receive operation succeeded. Expected error.");
}
@catch (msg) {
if (match(msg, pattern "*Check-receive operation using '\*' as matching template")) {
setverdict(pass);
}
else {
setverdict(fail, "Incorrect error message received (check-receive test): ", msg);
}
}
}
control {
execute(commMessageIntegerEncode());
execute(commMessageValue());
......@@ -1650,5 +1690,6 @@ control {
execute(commMessageDualFacedPorts2());
execute(commMessageMultiValueRedirect());
execute(commMessageDecodedValueRedirect());
execute(commMessageReceiveAnyOrOmit());
}
}
......@@ -172,6 +172,11 @@ type port ProcPort4 procedure {
}
with { extension "internal" }
type port ProcPort5 procedure {
inout MyProc;
}
with { extension "internal" }
type component ProcComponent
{
port ProcPort1 Port0;
......@@ -209,6 +214,10 @@ type component ProcComponent4 {
port ProcPort4 Port4;
}
type component ProcComponent5 {
port ProcPort5 Port5;
}
function GetCall_behav1() runs on ProcComponent2 {
while(true) {
alt {
......@@ -1090,6 +1099,82 @@ testcase tc_DecodedRedirect4() runs on ProcComponent4 {
setverdict(pass);
}
// '*' is not allowed as a matching template for the return value
// in getreply operations or for the exception in catch operations
testcase tc_MatchingWithAnyOrOmit() runs on ProcComponent5 {
connect(self:Port5, self:Port5);
var template boolean vt_bool := *;
var template integer vt_int := *;
// getreply
Port5.reply(MyProc: { -, "a", 0.1 } value false);
@try {
alt {
[] Port5.getreply(MyProc: { ?, ?, ? } value vt_bool) { }
}
setverdict(fail, "Getreply operation succeeded. Expected error.");
}
@catch (msg) {
if (match(msg, pattern "*Getreply operation using '\*' as return value matching template")) {
setverdict(pass);
}
else {
setverdict(fail, "Incorrect error message received (getreply test): ", msg);
}
}
// check-getreply
Port5.reply(MyProc: { -, "a", 0.1 } value false);
@try {
alt {
[] Port5.check(getreply(MyProc: { ?, ?, ? } value vt_bool)) { }
}
setverdict(fail, "Check-getreply operation succeeded. Expected error.");
}
@catch (msg) {
if (match(msg, pattern "*Check-getreply operation using '\*' as return value matching template")) {
setverdict(pass);
}
else {
setverdict(fail, "Incorrect error message received (check-getreply test): ", msg);
}
}