From a31e17c0837c1067c0fca7d861bf27d333c0083e Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Tue, 5 May 2020 14:03:44 +0200
Subject: [PATCH] Implemented object-oriented features - stage 6 (bug 552011)

Change-Id: I3d60fb128be24c23c4d1825b80d8896422446f5a
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/Setting.cc                          |   2 +-
 compiler2/Setting.hh                          |   2 +-
 compiler2/Type.cc                             |   8 +
 compiler2/Type_chk.cc                         |   7 +
 compiler2/ttcn3/AST_ttcn3.cc                  |  97 ++++++--
 compiler2/ttcn3/AST_ttcn3.hh                  |   4 +-
 compiler2/ttcn3/Statement.cc                  |   6 +-
 compiler2/ttcn3/TtcnTemplate.cc               |   2 +-
 compiler2/ttcn3/Ttcnstuff.cc                  | 158 +++++++++----
 compiler2/ttcn3/Ttcnstuff.hh                  |  12 +-
 .../Semantic_Analyser/oop/.gitignore          |   2 +
 function_test/Semantic_Analyser/oop/Makefile  |  14 ++
 .../Semantic_Analyser/oop/oop_SE.ttcn         | 217 ++++++++++++++++++
 function_test/Semantic_Analyser/oop/t         |   9 +
 14 files changed, 473 insertions(+), 67 deletions(-)
 create mode 100644 function_test/Semantic_Analyser/oop/.gitignore
 create mode 100644 function_test/Semantic_Analyser/oop/Makefile
 create mode 100644 function_test/Semantic_Analyser/oop/oop_SE.ttcn
 create mode 100755 function_test/Semantic_Analyser/oop/t

diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc
index 1a03a11d8..3e57713fe 100644
--- a/compiler2/Setting.cc
+++ b/compiler2/Setting.cc
@@ -606,7 +606,7 @@ namespace Common {
     return 0;
   }
   
-  const Ttcn::ClassTypeBody* Scope::get_scope_class() const
+  Ttcn::ClassTypeBody* Scope::get_scope_class()
   {
     if (parent_scope != NULL) {
       return parent_scope->get_scope_class();
diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh
index dc5d47af2..0f5ab426d 100644
--- a/compiler2/Setting.hh
+++ b/compiler2/Setting.hh
@@ -615,7 +615,7 @@ public:
     virtual Module* get_scope_mod();
     virtual Module* get_scope_mod_gen();
     virtual bool is_class_scope() const { return false; }
-    virtual const Ttcn::ClassTypeBody* get_scope_class() const;
+    virtual Ttcn::ClassTypeBody* get_scope_class();
     /** Returns the assignment referenced by \a p_ref. If no such
      * node, 0 is returned. */
     virtual Assignment* get_ass_bySRef(Ref_simple *p_ref) =0;
diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 19f5f90d6..928aea26a 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -1728,6 +1728,10 @@ namespace Common {
             return 0;
           }
           Assignment* ass = class_->get_local_ass_byId(id);
+          if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) {
+            // the member is not visible (the error has already been reported)
+            return 0;
+          }
           switch (ass->get_asstype()) {
           case Assignment::A_VAR:
           case Assignment::A_VAR_TEMPLATE:
@@ -1778,6 +1782,10 @@ namespace Common {
           return 0;
         }
         Assignment* ass = class_->get_local_ass_byId(id);
+        if (!class_->chk_visibility(ass, ref, subrefs->get_my_scope())) {
+          // the method is not visible (the error has already been reported)
+          return 0;
+        }
         switch (ass->get_asstype()) {
         case Assignment::A_VAR:
         case Assignment::A_VAR_TEMPLATE:
diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index 80ccc86a3..8b47f46b5 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -3799,6 +3799,10 @@ void Type::chk_embedded(bool default_allowed, const char *error_msg)
   case T_DEFAULT:
     if (!default_allowed) error("Default type cannot be %s", error_msg);
     break;
+  case T_CLASS:
+    error("Class type `%s' cannot be %s", t->get_typename().c_str(),
+      error_msg);
+    break;
   default:
     break;
   }
@@ -3859,6 +3863,9 @@ void Type::chk_recursions(ReferenceChain& refch)
   case T_ARRAY:
     t->get_ofType()->chk_recursions(refch);
     break;
+  case T_CLASS:
+    t->get_class_type_body()->chk_recursions(refch);
+    break;
   default:
     break;
   }
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 544787f23..7363b51d6 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -307,7 +307,7 @@ namespace Ttcn {
   // =================================
 
   FieldOrArrayRefs::FieldOrArrayRefs(const FieldOrArrayRefs& p)
-    : Node(p), refs_str_element(false)
+    : Node(p), refs_str_element(false), my_scope(NULL)
   {
     for (size_t i = 0; i < p.refs.size(); i++) refs.add(p.refs[i]->clone());
   }
@@ -333,6 +333,7 @@ namespace Ttcn {
 
   void FieldOrArrayRefs::set_my_scope(Scope *p_scope)
   {
+    my_scope = p_scope;
     for (size_t i = 0; i < refs.size(); i++) refs[i]->set_my_scope(p_scope);
   }
 
@@ -3666,6 +3667,12 @@ namespace Ttcn {
               delete t;
               continue;
             }
+            else if (t->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
+              ea.error("Class type `%s' cannot be added to the anytype",
+                t->get_typename().c_str());
+              delete t;
+              continue;
+            }
 
             string field_name;
             const char* btn = Type::get_typename_builtin(t->get_typetype());
@@ -3883,6 +3890,10 @@ namespace Ttcn {
       error("Constant cannot be defined for signature `%s'",
         t->get_fullname().c_str());
       break;
+    case Type::T_CLASS:
+      error("Constant cannot be defined for class type `%s'",
+        t->get_fullname().c_str());
+      break;
     default:
       value_under_check = true;
         type->chk_this_value(value, 0, Type::EXPECTED_STATIC_VALUE, WARNING_FOR_INCOMPLETE,
@@ -4069,6 +4080,10 @@ namespace Ttcn {
       error("External constant cannot be defined for signature `%s'",
         t->get_fullname().c_str());
       break;
+    case Type::T_CLASS:
+      error("External constant cannot be defined for class type `%s'",
+        t->get_fullname().c_str());
+      break;
     default:
       break;
     }
@@ -4199,6 +4214,10 @@ namespace Ttcn {
             " `%s' which has runs on self clause", t->get_fullname().c_str());
         break;
       }
+    case Type::T_CLASS:
+      error("Type of module parameter cannot be or embed class type `%s'",
+        t->get_fullname().c_str());
+      break;
     default:
 #if defined(MINGW)
       checked = true;
@@ -4367,6 +4386,10 @@ namespace Ttcn {
             " `%s' which has runs on self clause", t->get_fullname().c_str());
       }
       break;
+    case Type::T_CLASS:
+      error("Type of template module parameter cannot be class type `%s'",
+        t->get_fullname().c_str());
+      break;
     default:
       if (IMPLICIT_OMIT == has_implicit_omit_attr()) {
         error("Implicit omit not supported for template module parameters");
@@ -4584,6 +4607,10 @@ namespace Ttcn {
       error("Template cannot be defined for port type `%s'",
         t->get_fullname().c_str());
     }
+    else if (t->get_typetype() == Type::T_CLASS) {
+      error("Template cannot be defined for class type `%s'",
+        t->get_fullname().c_str());
+    }
     chk_modified();
     chk_recursive_derivation();
     type->chk_this_template_generic(body,
@@ -5371,6 +5398,10 @@ namespace Ttcn {
       error("Template variable cannot be defined for port type `%s'",
         t->get_fullname().c_str());
     }
+    else if (t->get_typetype() == Type::T_CLASS) {
+      error("Template variable cannot be defined for class type `%s'",
+        t->get_fullname().c_str());
+    }
 
     if (initial_value) {
       initial_value->set_my_governor(type);
@@ -6675,29 +6706,53 @@ namespace Ttcn {
     if (runs_on_ref && port_ref) {
       runs_on_ref->error("A `runs on' and a `port' clause cannot be present at the same time.");
     }
-    // checking the `runs on' clause
-    if (runs_on_ref) {
-      Error_Context cntxt2(runs_on_ref, "In `runs on' clause");
-      runs_on_type = runs_on_ref->chk_comptype_ref();
-      // override the scope of the formal parameter list
-      if (runs_on_type) {
-        Scope *runs_on_scope = get_runs_on_scope(runs_on_type);
-        runs_on_scope->set_parent_scope(my_scope);
-        fp_list->set_my_scope(runs_on_scope);
-      }
+    if (my_scope->is_class_scope()) {
+      // class methods inherit `runs on', `mtc' and `system' clauses from the class
+      ClassTypeBody* class_ = my_scope->get_scope_class();
+      runs_on_type = class_->get_RunsOnType();
+      mtc_type = class_->get_MtcType();
+      system_type = class_->get_SystemType();
     }
-    
-    // checking the `mtc' clause
-    if (mtc_ref) {
-      Error_Context cntxt2(mtc_ref, "In `mtc' clause");
-      mtc_type = mtc_ref->chk_comptype_ref();
+    else { // not in a class method
+      // checking the `runs on' clause
+      if (runs_on_ref) {
+        Error_Context cntxt2(runs_on_ref, "In `runs on' clause");
+        runs_on_type = runs_on_ref->chk_comptype_ref();
+      }
+
+      // checking the `mtc' clause
+      if (mtc_ref) {
+        Error_Context cntxt2(mtc_ref, "In `mtc' clause");
+        mtc_type = mtc_ref->chk_comptype_ref();
+      }
+
+      // checking the `system' clause
+      if (system_ref) {
+        Error_Context cntxt2(system_ref, "In `system' clause");
+        system_type = system_ref->chk_comptype_ref();
+      }
     }
     
-    // checking the `system' clause
-    if (system_ref) {
-      Error_Context cntxt2(system_ref, "In `system' clause");
-      system_type = system_ref->chk_comptype_ref();
-    }
+    // create scope units for the `runs on', `mtc' and `system' components,
+    // and link them in a row between the function's scope and the
+    // formal parameter list's scope
+    Scope* current_scope = my_scope;
+    if (system_type != NULL) {
+      Scope *system_scope = get_runs_on_scope(system_type);
+      system_scope->set_parent_scope(current_scope);
+      current_scope = system_scope;
+    }
+    if (mtc_type != NULL) {
+      Scope *mtc_scope = get_runs_on_scope(mtc_type);
+      mtc_scope->set_parent_scope(current_scope);
+      current_scope = mtc_scope;
+    }
+    if (runs_on_type != NULL) {
+      Scope *runs_on_scope = get_runs_on_scope(runs_on_type);
+      runs_on_scope->set_parent_scope(current_scope);
+      current_scope = runs_on_scope;
+    }
+    fp_list->set_my_scope(current_scope);
     
     // checking the formal parameter list, the check must come before the 
     // chk_prototype() function call.
diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh
index 695ddf5e3..deee24153 100644
--- a/compiler2/ttcn3/AST_ttcn3.hh
+++ b/compiler2/ttcn3/AST_ttcn3.hh
@@ -250,13 +250,15 @@ namespace Ttcn {
     /** Indicates whether the last array index refers to an element of a
      * string value. */
     bool refs_str_element;
+    Common::Scope* my_scope; ///< %Scope. Not owned
   public:
-    FieldOrArrayRefs() : Node(), refs(), refs_str_element(false) { }
+    FieldOrArrayRefs() : Node(), refs(), refs_str_element(false), my_scope(NULL) { }
     FieldOrArrayRefs(const FieldOrArrayRefs& p);
     ~FieldOrArrayRefs();
     FieldOrArrayRefs *clone() const;
     virtual void set_fullname(const string& p_fullname);
     virtual void set_my_scope(Scope *p_scope);
+    Scope *get_my_scope() const { return my_scope; }
     void add(FieldOrArrayRef *p_ref) { refs.add(p_ref); }
     size_t get_nof_refs() const { return refs.size(); }
     FieldOrArrayRef* get_ref(size_t i) const { return refs[i]; }
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 47ddccab1..37443c049 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -3247,8 +3247,12 @@ error:
     if (t_ass->get_asstype() == Common::Assignment::A_VAR) {
       // it could be a class object method
       Common::Assignment* last_method = NULL;
-      t_ass->get_Type()->get_field_type(ref_pard->get_subrefs(),
+      Common::Type* end_type = t_ass->get_Type()->get_field_type(ref_pard->get_subrefs(),
         Type::EXPECTED_DYNAMIC_VALUE, 0, false, &last_method);
+      if (end_type == NULL && last_method == NULL) {
+        // invalid subreferences (the error has already been reported)
+        return;
+      }
       if (last_method == NULL) {
         ref_pard->error("Reference to a function or altstep was expected");
       }
diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc
index ffd71a721..4770a8adc 100644
--- a/compiler2/ttcn3/TtcnTemplate.cc
+++ b/compiler2/ttcn3/TtcnTemplate.cc
@@ -31,7 +31,7 @@
 #include "../main.hh"
 #include "../../common/dbgnew.hh"
 #include "Attributes.hh"
-#include "Ttcnstuff.cc"
+#include "Ttcnstuff.hh"
 
 namespace Ttcn {
 
diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc
index d8954480e..9a2e25891 100644
--- a/compiler2/ttcn3/Ttcnstuff.cc
+++ b/compiler2/ttcn3/Ttcnstuff.cc
@@ -2986,7 +2986,8 @@ namespace Ttcn {
                                Reference* p_mtc_ref, Reference* p_system_ref,
                                Definitions* p_members, StatementBlock* p_finally_block)
   : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final), abstract(p_abstract),
-    base_type(p_base_type), runs_on_ref(p_runs_on_ref), mtc_ref(p_mtc_ref), system_ref(p_system_ref),
+    base_type(p_base_type), runs_on_ref(p_runs_on_ref), runs_on_type(NULL),
+    mtc_ref(p_mtc_ref), mtc_type(NULL), system_ref(p_system_ref), system_type(NULL),
     members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false),
     default_constructor(false)
   {
@@ -3035,7 +3036,7 @@ namespace Ttcn {
   {
     Common::Scope::set_fullname(p_fullname);
     if (base_type != NULL) {
-      base_type->set_fullname(p_fullname + ".<base_type>");
+      base_type->set_fullname(p_fullname + ".<superclass>");
     }
     if (runs_on_ref != NULL) {
       runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>");
@@ -3099,10 +3100,36 @@ namespace Ttcn {
   
   Def_Constructor* ClassTypeBody::get_constructor()
   {
-    chk();
+    if (!checked) {
+      chk();
+    }
     return constructor;
   }
   
+  Type* ClassTypeBody::get_RunsOnType()
+  {
+    if (!checked) {
+      chk();
+    }
+    return runs_on_type;
+  }
+  
+  Type* ClassTypeBody::get_MtcType()
+  {
+    if (!checked) {
+      chk();
+    }
+    return mtc_type;
+  }
+  
+  Type* ClassTypeBody::get_SystemType()
+  {
+    if (!checked) {
+      chk();
+    }
+    return system_type;
+  }
+  
   bool ClassTypeBody::is_parent_class(const ClassTypeBody* p_class) const
   {
     if (this == p_class) {
@@ -3144,6 +3171,37 @@ namespace Ttcn {
     return ass;
   }
   
+  bool ClassTypeBody::chk_visibility(Common::Assignment* ass,
+                                     Common::Location* usage_loc,
+                                     Common::Scope* usage_scope)
+  {
+    if (ass->get_visibility() == PUBLIC) {
+      // it's public, so it doesn't matter where it's accessed from
+      return true;
+    }
+
+    const ClassTypeBody* ref_scope_class = usage_scope->get_scope_class();
+    const ClassTypeBody* ass_scope_class = ass->get_my_scope()->get_scope_class();
+    if (ass_scope_class == NULL) {
+      FATAL_ERROR("ClassTypeBody::chk_visibility()");
+    }
+    if (ref_scope_class == ass_scope_class) {
+      // the reference is inside the same class as the assignment => any visibility is fine
+      return true;
+    }
+
+    if (ref_scope_class != NULL &&
+        ass->get_visibility() == NOCHANGE && // i.e. protected
+        ref_scope_class->is_parent_class(ass_scope_class)) {
+      return true;
+    }
+
+    usage_loc->error("The %s definition `%s' in class type `%s' is not visible "
+      "in this scope", ass->get_FormalParList() != NULL ? "method" : "member",
+      ass->get_id().get_dispname().c_str(), class_id->get_dispname().c_str());
+    return false;
+  }
+  
   Common::Assignment* ClassTypeBody::get_ass_bySRef(Common::Ref_simple* p_ref)
   {
     if (p_ref == NULL || parent_scope == NULL) {
@@ -3179,28 +3237,13 @@ namespace Ttcn {
         if (ass == NULL) {
           FATAL_ERROR("ClassTypeBody::get_ass_bySRef()");
         }
-
-        if (ass->get_visibility() == PUBLIC) {
-          // it's public, so it doesn't matter where it's accessed from
-          return ass;
-        }
         
-        const ClassTypeBody* ref_scope_class = p_ref->get_my_scope()->get_scope_class();
-        if (ref_scope_class == this) {
-          // the reference is inside this class => any visibility is fine
+        if (chk_visibility(ass, p_ref, p_ref->get_my_scope())) {
           return ass;
         }
-        
-        if (ref_scope_class != NULL &&
-            ass->get_visibility() == NOCHANGE && // i.e. protected
-            ref_scope_class->is_parent_class(this)) {
-          return ass;
+        else {
+          return NULL;
         }
-
-        p_ref->error("The member definition `%s' in class type `%s'"
-          " is not visible in this scope", id->get_dispname().c_str(),
-            class_id->get_dispname().c_str());
-        return NULL;
       }
     }
     return parent_scope->get_ass_bySRef(p_ref);
@@ -3214,20 +3257,32 @@ namespace Ttcn {
     checked = true;
     // TODO: external? final? abstract?
     if (base_type != NULL) {
+      Error_Context cntxt(base_type, "In superclass definition");
       base_type->chk();
+      if (base_type->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) {
+        if (base_type->get_typetype() != Common::Type::T_ERROR) {
+          base_type->error("Class type expected instead of `%s'",
+            base_type->get_typename().c_str());
+        }
+        delete base_type;
+        base_type = NULL;
+      }
       // TODO: additional checks for the base type
     }
 
     if (runs_on_ref != NULL) {
-      Common::Assignment* ass = runs_on_ref->get_refd_assignment(true);
+      Error_Context cntxt(runs_on_ref, "In `runs on' clause");
+      runs_on_type = runs_on_ref->chk_comptype_ref();
       // TODO
     }
     if (mtc_ref != NULL) {
-      Common::Assignment* ass = mtc_ref->get_refd_assignment(true);
+      Error_Context cntxt(mtc_ref, "In `mtc' clause");
+      mtc_type = mtc_ref->chk_comptype_ref();
       // TODO
     }
     if (system_ref != NULL) {
-      Common::Assignment* ass = system_ref->get_refd_assignment(true);
+      Error_Context cntxt(system_ref, "In `system' clause");
+      system_type = system_ref->chk_comptype_ref();
       // TODO
     }
 
@@ -3253,24 +3308,26 @@ namespace Ttcn {
       if (base_type != NULL) {
         ClassTypeBody* base_class = base_type->get_type_refd_last()->
           get_class_type_body();
-        FormalParList* base_fp_list = base_class->get_constructor()->
-          get_FormalParList();
-        fp_list = base_fp_list->clone();
-        ParsedActualParameters* parsed_ap_list = new ParsedActualParameters();
-        for (size_t i = 0; i < base_fp_list->get_nof_fps(); ++i) {
-          // the actual parameters are references to the formal parameters of
-          // the base constructor (also present in this constructor)
-          Reference* ref = new Reference(NULL,
-            base_fp_list->get_fp_byIndex(i)->get_id().clone());
-          Common::Value* val = new Value(Common::Value::V_REFD, ref);
-          Template* temp = new Template(val);
-          TemplateInstance* ti = new TemplateInstance(NULL, NULL, temp);
-          parsed_ap_list->add_ti(ti);
+        Def_Constructor* base_constructor = base_class->get_constructor();
+        if (base_constructor != NULL) {
+          FormalParList* base_fp_list = base_constructor->get_FormalParList();
+          fp_list = base_fp_list->clone();
+          ParsedActualParameters* parsed_ap_list = new ParsedActualParameters();
+          for (size_t i = 0; i < base_fp_list->get_nof_fps(); ++i) {
+            // the actual parameters are references to the formal parameters of
+            // the base constructor (also present in this constructor)
+            Reference* ref = new Reference(NULL,
+              base_fp_list->get_fp_byIndex(i)->get_id().clone());
+            Common::Value* val = new Value(Common::Value::V_REFD, ref);
+            Template* temp = new Template(val);
+            TemplateInstance* ti = new TemplateInstance(NULL, NULL, temp);
+            parsed_ap_list->add_ti(ti);
+          }
+          base_call = new Reference(base_class->get_scope_mod()->get_modid().clone(),
+            base_class->get_id()->clone(), parsed_ap_list);
         }
-        base_call = new Reference(base_class->get_scope_mod()->get_modid().clone(),
-          base_class->get_id()->clone(), parsed_ap_list);
       }
-      else {
+      if (fp_list == NULL) {
         fp_list = new FormalParList;
       }
       StatementBlock* block = new StatementBlock();
@@ -3315,6 +3372,27 @@ namespace Ttcn {
     }
   }
   
+  void ClassTypeBody::chk_recursions(ReferenceChain& refch)
+  {
+    if (base_type != NULL) {
+      base_type->chk_recursions(refch);
+    }
+    
+    for (size_t i = 0; i < members->get_nof_asss(); ++i) {
+      Common::Assignment* def = members->get_ass_byIndex(i);
+      switch (def->get_asstype()) {
+      case Common::Assignment::A_CONST:
+      case Common::Assignment::A_VAR:
+      case Common::Assignment::A_TEMPLATE:
+      case Common::Assignment::A_VAR_TEMPLATE:
+        def->get_Type()->chk_recursions(refch);
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  
   void ClassTypeBody::generate_code(output_struct* target)
   {
     target->header.class_decls = mputprintf(target->header.class_decls,
diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh
index 7bad71098..9ad4794da 100644
--- a/compiler2/ttcn3/Ttcnstuff.hh
+++ b/compiler2/ttcn3/Ttcnstuff.hh
@@ -762,8 +762,11 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
   boolean abstract;
   Common::Type* base_type;
   Reference* runs_on_ref;
+  Type* runs_on_type;
   Reference* mtc_ref;
+  Type* mtc_type;
   Reference* system_ref;
+  Type* system_type;
   Definitions* members;
   StatementBlock* finally_block;
   /** set during semantic analysis to either a pointer to the constructor in
@@ -788,17 +791,24 @@ public:
   void dump(unsigned level) const;
   
   virtual bool is_class_scope() const { return true; }
-  virtual const ClassTypeBody* get_scope_class() const { return this; }
+  virtual ClassTypeBody* get_scope_class() { return this; }
   Common::Identifier* get_id() const { return class_id; }
   Def_Constructor* get_constructor();
   Common::Type* get_base_type() const { return base_type; }
   
+  Type* get_RunsOnType();
+  Type* get_MtcType();
+  Type* get_SystemType();
+  
   bool is_parent_class(const ClassTypeBody* p_class) const;
   bool has_local_ass_withId(const Identifier& p_id);
   Common::Assignment* get_local_ass_byId(const Identifier& p_id);
   Common::Assignment* get_ass_bySRef(Common::Ref_simple* p_ref);
   
+  bool chk_visibility(Common::Assignment* ass, Common::Location* usage_loc,
+    Common::Scope* usage_scope);
   void chk();
+  void chk_recursions(ReferenceChain& refch);
   
   void generate_code(output_struct* target);
 };
diff --git a/function_test/Semantic_Analyser/oop/.gitignore b/function_test/Semantic_Analyser/oop/.gitignore
new file mode 100644
index 000000000..e2d293255
--- /dev/null
+++ b/function_test/Semantic_Analyser/oop/.gitignore
@@ -0,0 +1,2 @@
+!Makefile
+!*.ttcn
diff --git a/function_test/Semantic_Analyser/oop/Makefile b/function_test/Semantic_Analyser/oop/Makefile
new file mode 100644
index 000000000..16a160593
--- /dev/null
+++ b/function_test/Semantic_Analyser/oop/Makefile
@@ -0,0 +1,14 @@
+##############################################################################
+# Copyright (c) 2000-2020 Ericsson Telecom AB
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+#
+# Contributors:
+#   Baranyi, Botond
+#
+##############################################################################
+include ../common.mk
+
+COMPILER_FLAGS += -k
diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
new file mode 100644
index 000000000..42a4732a5
--- /dev/null
+++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
@@ -0,0 +1,217 @@
+/******************************************************************************
+ * Copyright (c) 2000-2020 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+ *
+ * Contributors:
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+
+module oop_SE { //^In TTCN-3 module//
+
+type component Comp {
+  var integer cv_comp;
+  const integer cc_comp := -1;
+}
+
+type port Port message {
+  inout integer
+}
+with {
+  extension "internal"
+}
+
+type record Rec {
+  integer num,
+  charstring str
+}
+
+const integer c := 3;
+
+type class C0 { }
+
+type class C1 extends Nonexistent { } //^In type definition// //^In superclass definition// //There is no local or imported definition with name `Nonexistent'//
+
+type class C2 extends c { } //^In type definition// //^In superclass definition// //`c' is not a reference to a type//
+
+type class C3 extends Rec { } //^In type definition// //^In superclass definition// //Class type expected instead of `@oop_SE.Rec'//
+
+
+type class C4 {
+  private var integer m_private_inherited;
+  /*protected*/ var charstring m_protected_inherited;
+  public var Rec m_public_inherited;
+  private function f_private_inherited() {}
+  /*protected*/ function f_protected_inherited() {}
+  public function f_public_inherited() {}
+}
+
+type class C5 extends C4 { //^In type definition//
+  private var boolean m_private_own;
+  /*protected*/ var float m_protected_own;
+  public var octetstring m_public_own;
+  private function f_private_own() {}
+  /*protected*/ function f_protected_own() {}
+  public function f_public_own() {}
+  
+  public function f_member_access_inside() { //^In function definition//
+    log(m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope//
+    log(m_protected_inherited);
+    log(m_public_inherited);
+    log(m_private_own);
+    log(m_protected_own);
+    log(m_public_own);
+    log(m_nonexistent); //^In log statement// //There is no local or imported definition with name `m_nonexistent'//
+    f_private_inherited(); //^In function or altstep instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope//
+    f_protected_inherited();
+    f_public_inherited();
+    f_private_own();
+    f_protected_own();
+    f_public_own();
+    f_nonexistent(); //^In function or altstep instance// //There is no local or imported definition with name `f_nonexistent'//
+  }
+}
+
+function f_member_access_outside() { //^In function definition//
+  var C5 obj := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O);
+  log(obj.m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope//
+  log(obj.m_protected_inherited); //^In log statement// //The member definition `m_protected_inherited' in class type `C5' is not visible in this scope//
+  log(obj.m_public_inherited);
+  log(obj.m_private_own); //^In log statement// //The member definition `m_private_own' in class type `C5' is not visible in this scope//
+  log(obj.m_protected_own); //^In log statement// //The member definition `m_protected_own' in class type `C5' is not visible in this scope//
+  log(obj.m_public_own);
+  log(obj.m_nonexistent); //^In log statement// //Reference to non-existent member `m_nonexistent' in class type `@oop_SE.C5'//
+  obj.f_private_inherited(); //^In function instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope//
+  obj.f_protected_inherited(); //^In function instance// //The method definition `f_protected_inherited' in class type `C5' is not visible in this scope//
+  obj.f_public_inherited();
+  obj.f_private_own(); //^In function instance// //The method definition `f_private_own' in class type `C5' is not visible in this scope//
+  obj.f_protected_own(); //^In function instance// //The method definition `f_protected_own' in class type `C5' is not visible in this scope//
+  obj.f_public_own();
+  obj.f_nonexistent(); //^In function instance// //Reference to non-existent method `f_nonexistent' in class type `@oop_SE.C5'//
+}
+
+type class C6 { //^In type definition//
+  public function f_member_access_other_class() { //^In function definition//
+    var C5 obj := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O);
+    log(obj.m_private_inherited); //^In log statement// //The member definition `m_private_inherited' in class type `C5' is not visible in this scope//
+    log(obj.m_protected_inherited); //^In log statement// //The member definition `m_protected_inherited' in class type `C5' is not visible in this scope//
+    log(obj.m_public_inherited);
+    log(obj.m_private_own); //^In log statement// //The member definition `m_private_own' in class type `C5' is not visible in this scope//
+    log(obj.m_protected_own); //^In log statement// //The member definition `m_protected_own' in class type `C5' is not visible in this scope//
+    log(obj.m_public_own);
+    log(obj.m_nonexistent); //^In log statement// //Reference to non-existent member `m_nonexistent' in class type `@oop_SE.C5'//
+    obj.f_private_inherited(); //^In function instance// //The method definition `f_private_inherited' in class type `C5' is not visible in this scope//
+    obj.f_protected_inherited(); //^In function instance// //The method definition `f_protected_inherited' in class type `C5' is not visible in this scope//
+    obj.f_public_inherited();
+    obj.f_private_own(); //^In function instance// //The method definition `f_private_own' in class type `C5' is not visible in this scope//
+    obj.f_protected_own(); //^In function instance// //The method definition `f_protected_own' in class type `C5' is not visible in this scope//
+    obj.f_public_own();
+    obj.f_nonexistent(); //^In function instance// //Reference to non-existent method `f_nonexistent' in class type `@oop_SE.C5'//
+  }
+}
+
+
+type class C7 extends C9 { //^In type definition// //^In superclass definition//
+  public const integer x1 := 1;
+}
+
+type class C8 extends C7 { //^In type definition// //While checking embedded recursions\: Circular reference\: `@oop_SE.C8' -> `@oop_SE.C8.<superclass>' -> `@oop_SE.C7' -> `@oop_SE.C7.<superclass>' -> `@oop_SE.C9' -> `@oop_SE.C9.<superclass>' -> `@oop_SE.C8'//
+  private var integer x2;
+}
+
+type class C9 extends C8 {} //^In type definition// //^In superclass definition//
+
+external const C0 ec_obj; //^In external constant definition// //External constant cannot be defined for class type `@oop_SE.C0'//
+modulepar C0 mp_obj; //^In module parameter definition// //Type of module parameter cannot be or embed class type `@oop_SE.C0'//
+modulepar template C0 mpt_obj; //^In template module parameter definition// //Type of template module parameter cannot be class type `@oop_SE.C0'//
+
+function f_defs() { //^In function definition//
+  const C0 c_obj := null; //^In constant definition// //Constant cannot be defined for class type `@oop_SE.C0'//
+  var C0 v_obj;
+  template C0 t_obj := *; //^In template definition// //Template cannot be defined for class type `@oop_SE.C0'//
+  var template C0 vt_obj; //^In template variable definition// //Template variable cannot be defined for class type `@oop_SE.C0'//
+}
+
+
+type record RecClass { //^In type definition//
+  C0 x //^In record field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+}
+
+type set SetClass { //^In type definition//
+  C0 x //^In set field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+}
+
+type record of C0 RecOfClass; //^In type definition// //^In embedded type of record of// //Class type `@oop_SE.C0' cannot be embedded into another type//
+
+type set of C0 SetOfClass; //^In type definition// //^In embedded type of set of// //Class type `@oop_SE.C0' cannot be embedded into another type//
+
+type union UniClass { //^In type definition//
+  C0 x //^In union field// //Class type `@oop_SE.C0' cannot be embedded into another type//
+}
+
+function f_embedded_types() { //^In function definition//
+  var RecClass v_rec := { x := C0.create };
+  var SetClass v_set := { x := C0.create };
+  var RecOfClass v_recof := { C0.create };
+  var SetOfClass v_setof := { C0.create };
+  var UniClass v_uni := { x := C0.create };
+  var anytype v_any; //^In variable definition// //^In type definition//
+  v_any.C0 := C0.create; //^In variable assignment// //Reference to non-existent field `C0' in type `@oop_SE.anytype'//
+}
+
+
+function f_type_compatibility() { //^In function definition//
+  var C4 x1 := C4.create(1, "a", { 2, "b" });
+  var C5 y1 := C4.create(1, "a", { 2, "b" }); //^In variable definition// //Incompatible class types: operation `create' should refer to `@oop_SE.C5' instead of `@oop_SE.C4'//
+  var C4 x2 := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O);
+  var C5 y2 := C5.create(1, "a", { 2, "b" }, true, 0.1, '12'O);
+  var C4 x3 := y1;
+  var C5 y3 := x1; //^In variable definition// //Type mismatch: a value of type `@oop_SE.C5' was expected instead of `@oop_SE.C4'//
+  x3 := y2;
+  y3 := x2; //^In variable assignment// //Type mismatch: a value of type `@oop_SE.C5' was expected instead of `@oop_SE.C4'//
+  log(x1.m_public_inherited);
+  log(y1.m_public_inherited);
+  log(x1.m_public_own); //^In log statement// //Reference to non-existent member `m_public_own' in class type `@oop_SE.C4'//
+  log(y1.m_public_own);
+  x1.f_public_inherited();
+  y1.f_public_inherited();
+  x1.f_public_own(); //^In function instance// //Reference to non-existent method `f_public_own' in class type `@oop_SE.C4'//
+  y1.f_public_own();
+}
+
+
+type component CT_RunsOn {
+  var integer cv_runs_on;
+  const integer cc_runs_on := 0;
+}
+
+type component CT_Mtc {
+  var integer cv_mtc;
+  const integer cc_mtc := 1;
+}
+
+type component CT_System {
+  var integer cv_system;
+  const integer cc_system := 2;
+}
+
+type class C10 runs on CT_RunsOn mtc CT_Mtc system CT_System { //^In type definition//
+  public function f_comp_visibility(in integer p1 := cc_runs_on, //^In function definition// //^In formal parameter list//
+                                    in integer p2 := cc_mtc,
+                                    in integer p3 := cc_system,
+                                    in integer p4 := cc_comp) { //^In parameter// //^In default value// //There is no local or imported definition with name `cc_comp'//
+    log(cv_runs_on);
+    log(cv_mtc);
+    log(cv_system);
+    log(cv_comp); //^In log statement// //There is no local or imported definition with name `cv_comp'//
+  }
+}
+
+
+}
+with {
+  extension "anytype C0" //Class type `@oop_SE.C0' cannot be added to the anytype//
+}
diff --git a/function_test/Semantic_Analyser/oop/t b/function_test/Semantic_Analyser/oop/t
new file mode 100755
index 000000000..3a4b58ec1
--- /dev/null
+++ b/function_test/Semantic_Analyser/oop/t
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+# note this is called through "perl -w"
+use strict;
+
+my $self = $0;
+$self =~ s!/t!!;
+
+exec('make check --no-print-directory -s -C ' . $self);
+
-- 
GitLab