From 14b6f11dc3f4319f2910a9b108eae722cc44d1d0 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Fri, 20 Oct 2017 17:07:34 +0200
Subject: [PATCH] Added warning when function with 'out' or 'inout' parameters
 is started on PTC (bug 515512)

Change-Id: I83d28c7445cb1f429bf689ea907400484c22f089
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/Type.hh                             |  2 +-
 compiler2/Type_chk.cc                         |  6 ++--
 compiler2/ttcn3/AST_ttcn3.cc                  | 28 +++++++++++++------
 compiler2/ttcn3/AST_ttcn3.hh                  |  5 ++--
 compiler2/ttcn3/Statement.cc                  |  4 +--
 compiler2/ttcn3_makefilegen.1                 |  2 +-
 .../Semantic_Analyser/param/param_SE.ttcn     | 27 ++++++++++++++++++
 7 files changed, 56 insertions(+), 18 deletions(-)

diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index 4b0011328..d9b5543f6 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -873,7 +873,7 @@ namespace Common {
      * with the name of its definition.
      */
     void chk_constructor_name(const Identifier& p_id);
-    bool chk_startability();
+    bool chk_startability(Location* caller_location);
     /** Checks if it can be a return type */
     void chk_as_return_type(bool as_value, const char* what);
   private:
diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index b23380e4d..5ed4470fe 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -3687,16 +3687,16 @@ void Type::chk_constructor_name(const Identifier& p_id)
   }
 }
 
-bool Type::chk_startability()
+bool Type::chk_startability(Location* caller_location)
 {
   if(typetype != T_FUNCTION) FATAL_ERROR("Type::chk_startable()");
   if(!checked) chk_Fat();
+  u.fatref.fp_list->chk_startability("Functions of type",
+    get_typename().c_str(), caller_location);
   if(u.fatref.is_startable) return true;
   if (!u.fatref.runs_on.ref) error("Functions of type `%s' cannot be started "
     "on a parallel test component because the type does not have `runs on' "
     "clause", get_typename().c_str());
-  u.fatref.fp_list->chk_startability("Functions of type",
-    get_typename().c_str());
   if (u.fatref.return_type && u.fatref.return_type->is_component_internal()) {
     map<Type*,void> type_chain;
     char* err_str = mprintf("the return type or embedded in the return type "
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 2f77de996..c1ba185d8 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -6528,14 +6528,14 @@ namespace Ttcn {
     }
   }
     
-  bool Def_Function::chk_startable()
+  bool Def_Function::chk_startable(Location* caller_location)
   {
     if (!checked) chk();
+    fp_list->chk_startability("Function", get_fullname().c_str(), caller_location);
     if (is_startable) return true;
     if (!runs_on_ref) error("Function `%s' cannot be started on a parallel "
       "test component because it does not have `runs on' clause",
       get_fullname().c_str());
-    fp_list->chk_startability("Function", get_fullname().c_str());
     if (return_type && return_type->is_component_internal()) {
       map<Type*,void> type_chain;
       char* err_str = mprintf("the return type or embedded in the return type "
@@ -9478,20 +9478,23 @@ namespace Ttcn {
     }
   }
 
-  void FormalParList::chk_startability(const char *p_what, const char *p_name)
+  void FormalParList::chk_startability(const char *p_what, const char *p_name,
+                                       Location* caller_location)
   {
     if(!checked) FATAL_ERROR("FormalParList::chk_startability()");
-    if (is_startable) return;
+    bool has_out_or_inout = false;
     for (size_t i = 0; i < pars_v.size(); i++) {
       FormalPar *par = pars_v[i];
       switch (par->get_asstype()) {
-      case Common::Assignment::A_PAR_VAL_IN:
-      case Common::Assignment::A_PAR_TEMPL_IN:
       case Common::Assignment::A_PAR_VAL_INOUT:
       case Common::Assignment::A_PAR_TEMPL_INOUT:
       case Common::Assignment::A_PAR_VAL_OUT:
       case Common::Assignment::A_PAR_TEMPL_OUT:
-        if (par->get_Type()->is_component_internal()) {
+        has_out_or_inout = true;
+        // no break
+      case Common::Assignment::A_PAR_VAL_IN:
+      case Common::Assignment::A_PAR_TEMPL_IN:
+        if (!is_startable && par->get_Type()->is_component_internal()) {
           map<Type*,void> type_chain;
           char* err_str = mprintf("a parameter or embedded in a parameter of "
             "a function used in a start operation. "
@@ -9502,10 +9505,17 @@ namespace Ttcn {
         }
         break;
       default:
-        par->error("%s `%s' cannot be started on a parallel test component "
-          "because it has %s", p_what, p_name, par->get_description().c_str());
+        if (!is_startable) {
+          par->error("%s `%s' cannot be started on a parallel test component "
+            "because it has %s", p_what, p_name, par->get_description().c_str());
+        }
       }
     }
+    if (has_out_or_inout) {
+      caller_location->warning("The `out' and `inout' parameters of functions "
+        "started on parallel test components will remain unchanged at the end "
+        "of the operation.");
+    }
   }
 
   void FormalParList::chk_compatibility(FormalParList* p_fp_list,
diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh
index 4ef74952e..7b78a3f70 100644
--- a/compiler2/ttcn3/AST_ttcn3.hh
+++ b/compiler2/ttcn3/AST_ttcn3.hh
@@ -1483,7 +1483,7 @@ namespace Ttcn {
     virtual void chk();
     /** Checks and returns whether the function is startable.
      * Reports the appropriate error message(s) if not. */
-    bool chk_startable();
+    bool chk_startable(Location* caller_location);
 
     bool is_transparent() const { return transparent; }
 
@@ -1883,7 +1883,8 @@ namespace Ttcn {
      * function cannot be started on a PTC. Used by functions and function
      * types. Parameter \a p_what shall contain "Function" or "Function type",
      * \a p_name shall contain the name of the function or function type. */
-    void chk_startability(const char *p_what, const char *p_name);
+    void chk_startability(const char *p_what, const char *p_name,
+      Location* caller_location);
     /** Checks the compatibility of two formal parameter list.
      *  They are compatible if every parameter is compatible, has the same
      *    attribute, and name */
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 64f7d35b2..1ddf88d11 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -4610,7 +4610,7 @@ error:
     Def_Function *t_func = dynamic_cast<Def_Function*>(t_ass);
     if (!t_func) FATAL_ERROR("Statement::chk_start_comp()");
     // checking startability
-    if (!t_func->chk_startable()) return;
+    if (!t_func->chk_startable(this)) return;
     // checking the 'runs on' clause against the type of component reference
     Type *runs_on_type = t_func->get_RunsOnType();
     if (!comp_type || !runs_on_type) return;
@@ -4683,7 +4683,7 @@ error:
         "'runs on self' clause");
       return;
     }
-    if(!f_type->chk_startability()) return;
+    if(!f_type->chk_startability(this)) return;
     Type *runs_on_type = f_type->get_fat_runs_on_type();
     if (!comp_type || !runs_on_type) return;
     if (!runs_on_type->is_compatible(comp_type, NULL, NULL))
diff --git a/compiler2/ttcn3_makefilegen.1 b/compiler2/ttcn3_makefilegen.1
index 49f2879bb..aaa26dfc7 100644
--- a/compiler2/ttcn3_makefilegen.1
+++ b/compiler2/ttcn3_makefilegen.1
@@ -147,7 +147,7 @@ version of the base library. If this switch is omitted the executable is
 built for parallel mode by default.
 .TP
 .B \-S
-Supresses all 
+Suppresses all 
 .I makefilegen
 warning messages.
 .TP
diff --git a/function_test/Semantic_Analyser/param/param_SE.ttcn b/function_test/Semantic_Analyser/param/param_SE.ttcn
index f79c515d7..86e719268 100644
--- a/function_test/Semantic_Analyser/param/param_SE.ttcn
+++ b/function_test/Semantic_Analyser/param/param_SE.ttcn
@@ -22,4 +22,31 @@ function f_in(in integer x) //^In function definition// //^warning: Passing an \
   f_out(x); //^In function instance// //^In actual parameter list of function// //^In parameter #1 for//
 }
 
+
+type component CT {}
+
+function f_start(in integer p1, out integer p2, inout integer p3) runs on CT {
+  p2 := p1;
+  p3 := p1;
+}
+
+type function FT_start(in integer p1, out integer p2, inout integer p3) runs on CT;
+
+testcase tc() runs on CT { //^In testcase definition//
+  var CT ct1 := CT.create;
+  var CT ct2 := CT.create;
+  var CT ct3 := CT.create;
+  var integer x1 := 10;
+  var integer x2 := 20;
+  var integer x3 := 30;
+  var integer y1 := 15;
+  var integer y2 := 30;
+  var integer y3 := 45;
+  var FT_start ft := refers(f_start); 
+  ct1.start(f_start(3, x1, y1)); //^In start test component statement// //The `out' and `inout' parameters of functions started on parallel test components will remain unchanged at the end of the operation//
+  ct2.start(f_start(6, x2, y2)); //^In start test component statement// //The `out' and `inout' parameters of functions started on parallel test components will remain unchanged at the end of the operation//
+  ct3.start(derefers(ft)(9, x3, y3)); //^In start test component statement// //The `out' and `inout' parameters of functions started on parallel test components will remain unchanged at the end of the operation//
+  all component.done;
+}
+
 }
-- 
GitLab