From b8a7cdf8d2a7128bcbaa60eda097ed4ab37a66a9 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 26 Apr 2017 17:55:55 +0200
Subject: [PATCH] JSON 'encode' attributes on subtypes and field/element types
 are now properly handled (bug 515584)

Change-Id: I6926000b765c983dc2a4f9f69c93290d8ab1efeb
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/Type.cc                    | 121 ++++++++++++++---
 compiler2/Type.hh                    |  18 ++-
 compiler2/Type_chk.cc                |   4 +-
 compiler2/Type_codegen.cc            |  12 +-
 compiler2/ttcn3/Attributes.cc        |   6 +
 regression_test/json/Functions.ttcn  | 121 +++++++++++++++++
 regression_test/json/Makefile        |   2 +-
 regression_test/json/OtherTypes.ttcn |  84 ++++++++++++
 regression_test/json/Testcases.ttcn  | 188 +++++++++++++++++++++++++++
 9 files changed, 525 insertions(+), 31 deletions(-)
 create mode 100644 regression_test/json/OtherTypes.ttcn

diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 5cd91e852..931068249 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -607,6 +607,7 @@ namespace Common {
     chk_finished = false;
     pard_type_instance = false;
     needs_any_from_done = false;
+    gen_json_coder_functions = false;
     default_encoding.type = CODING_UNSET;
     default_decoding.type = CODING_UNSET;
   }
@@ -1759,8 +1760,7 @@ namespace Common {
           t->u.array.dimension->chk_index(index_value, expected_index);
         } else {
           // perform a generic index check for other types
-          if (refch == 0 // variable assignment
-            || index_value->get_valuetype() != Value::V_NOTUSED) {
+          if (index_value->get_valuetype() != Value::V_NOTUSED) {
             Error_Context cntxt(index_value, "In index value");
             index_value->chk_expr_int(expected_index);
           }
@@ -3120,6 +3120,7 @@ namespace Common {
       case T_SEQ_A:
       case T_SET_T:
       case T_SET_A:
+      case T_ANYTYPE:
         jsonattrib = new JsonAST;
         break;
       default:
@@ -5631,20 +5632,14 @@ namespace Common {
   
   bool Type::hasEncodeAttr(const char* encoding_name)
   {
-    if (0 == strcmp(encoding_name, "JSON") && (implicit_json_encoding
-        || is_asn1() || (is_ref() && get_type_refd()->is_asn1()))) {
+    if (0 == strcmp(encoding_name, "JSON") &&
+        (implicit_json_encoding || is_asn1())) {
       // ASN.1 types automatically support JSON encoding
       return true;
     }
-    // Check the type itself first, then the root type
-    WithAttribPath *aps[2] = { 0, 0 };
-    size_t num_aps = ((aps[0] = get_attrib_path()) != 0);
-    // assign, compare, then add 0 or 1
-    if (is_ref()) {
-      num_aps += ((aps[num_aps] = get_type_refd()->get_attrib_path()) != 0);
-    }
-    for (size_t a = 0; a < num_aps; ++a) {
-      const vector<SingleWithAttrib>& real = aps[a]->get_real_attrib();
+    WithAttribPath* ap = get_attrib_path();
+    if (ap != NULL) {
+      const vector<SingleWithAttrib>& real = ap->get_real_attrib();
       const size_t num_atr = real.size();
       for (size_t i = 0; i < num_atr; ++i) {
         const SingleWithAttrib& s = *real[i];
@@ -5655,13 +5650,64 @@ namespace Common {
           }
         } // if ENCODE
       } // for
-    } // next a
+    } // if ap
+    
+    if ((ownertype == OT_COMP_FIELD || ownertype == OT_RECORD_OF ||
+        ownertype == OT_ARRAY) && parent_type != NULL &&
+        parent_type->get_attrib_path() != NULL &&
+        parent_type->hasEncodeAttrForType(this, encoding_name)) {
+      // the encode attribute might be in the parent type
+      return true;
+    }
+    return false;
+  }
+  
+  bool Type::hasEncodeAttrForType(Type* target_type, const char* encoding_name)
+  {
+    // if this type has an encode attribute, that also extends to its
+    // fields/elements
+    if (hasEncodeAttr(encoding_name)) {
+      return true;
+    }
+    // otherwise search this type's qualified attributes
+    MultiWithAttrib* mwa = get_attrib_path()->get_with_attr();
+    if (mwa != NULL) {
+      for (size_t i = 0; i < mwa->get_nof_elements(); ++i) {
+        const SingleWithAttrib* swa = mwa->get_element(i);
+        if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE &&
+            swa->get_attribSpec().get_spec() == encoding_name) {
+          // search the attribute's qualifiers for one that refers to the
+          // target type
+          Ttcn::Qualifiers* quals = swa->get_attribQualifiers();
+          for (size_t j = 0; j < quals->get_nof_qualifiers(); ++j) {
+            Ttcn::Qualifier* qual = const_cast<Ttcn::Qualifier*>(
+              quals->get_qualifier(j));
+            if (get_field_type(qual, EXPECTED_CONSTANT) == target_type) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+    if ((ownertype == OT_COMP_FIELD || ownertype == OT_RECORD_OF ||
+        ownertype == OT_ARRAY) && parent_type != NULL &&
+        parent_type->get_attrib_path() != NULL) {
+      return parent_type->hasEncodeAttrForType(target_type, encoding_name);
+    }
     return false;
   }
 
   namespace { // unnamed
 
-  enum state { PROCESSING = -1, ANSWER_NO, ANSWER_YES };
+  enum state {
+    PROCESSING = -1, // the type is now being checked
+    ANSWER_NO, // the type (and any types referencing this type) can never have
+    // the desired encoding type
+    ANSWER_YES, // the type (and any types referencing this type) has the
+    // desired encoding type
+    MISSING_ATTRIBUTE // the type does not have the desired encoding type, but a
+    // type referencing this type still could, with the right 'encode' attribute
+  };
 
   struct memoizer : private map<Type*, state> {
     memoizer() : map<Type*, state>() {}
@@ -5732,6 +5778,8 @@ namespace Common {
           return false;
         case ANSWER_YES:
           return true;
+        case MISSING_ATTRIBUTE:
+          FATAL_ERROR("Type::has_encoding");
         }
       }
 
@@ -5800,6 +5848,8 @@ namespace Common {
                 case ANSWER_YES:
                   subresult = true;
                   break;
+                case MISSING_ATTRIBUTE:
+                  FATAL_ERROR("Type::has_encoding");
                 }
               }
               else {
@@ -5837,6 +5887,8 @@ namespace Common {
               case ANSWER_YES:
                 subresult = true;
                 break;
+              case MISSING_ATTRIBUTE:
+                FATAL_ERROR("Type::has_encoding");
               }
             }
             else {
@@ -5960,7 +6012,8 @@ namespace Common {
         }
       }
       
-    case CT_JSON:
+    case CT_JSON: {
+      Type* type_w_enc_attr = NULL;
       while (true) {
         if (json_mem.has_key(t)) {
           switch (*json_mem.get(t)) {
@@ -5968,13 +6021,23 @@ namespace Common {
             break;
           case ANSWER_NO:
             return false;
+          case MISSING_ATTRIBUTE:
           case ANSWER_YES:
-            return true;
+            if (type_w_enc_attr != NULL) {
+              return json_mem.remember(type_w_enc_attr, ANSWER_YES);
+            }
+            return *json_mem.get(t) == ANSWER_YES;
           }
         }
         if (t->jsonattrib) {
+          t->get_type_refd_last()->set_gen_json_coder_functions();
           return json_mem.remember(t, ANSWER_YES);
         }
+        // an 'encode' attribute is not enough, structured types must still be
+        // checked; this keeps track of which type had the 'encode' attribute
+        if (type_w_enc_attr == NULL && t->hasEncodeAttr(get_encoding_name(CT_JSON))) {
+          type_w_enc_attr = t;
+        }
         if (t->is_ref()) {
           t = t->get_type_refd();
         }
@@ -6033,6 +6096,7 @@ namespace Common {
                   // Avoids infinite recursion for self-referencing types. 
                   continue;
                 case ANSWER_NO:
+                case MISSING_ATTRIBUTE:
                   // One field is not OK => the structure is not OK
                   return json_mem.remember(t, ANSWER_NO);
                 }
@@ -6062,6 +6126,7 @@ namespace Common {
                 // can always be broken with an empty record-of.
                 break;
               case ANSWER_NO:
+              case MISSING_ATTRIBUTE:
                 return json_mem.remember(t, ANSWER_NO);
                 break;
               }
@@ -6083,14 +6148,27 @@ namespace Common {
           default:
             return json_mem.remember(t, ANSWER_NO);
           } // switch
-          return json_mem.remember(t, hasEncodeAttr(get_encoding_name(CT_JSON)) ? ANSWER_YES : ANSWER_NO);
+          if (type_w_enc_attr != NULL) {
+            t->set_gen_json_coder_functions();
+            return json_mem.remember(type_w_enc_attr, ANSWER_YES);
+          }
+          return json_mem.remember(t, MISSING_ATTRIBUTE);
         } // else
       } // while
-      
+    } // case
     case CT_CUSTOM:
       // the encoding name parameter has to be the same as the encoding name
       // specified for the type
-      return custom_encoding ? hasEncodeAttr(custom_encoding->c_str()) : false;
+      if (custom_encoding == NULL) {
+        return false;
+      }
+      if (hasEncodeAttr(custom_encoding->c_str())) {
+        return true;
+      }
+      if (is_ref()) {
+        return get_type_refd()->has_encoding(encoding_type, custom_encoding);
+      }
+      return false;
 
     default:
       FATAL_ERROR("Type::has_encoding()");
@@ -6530,6 +6608,7 @@ namespace Common {
        * descriptor.
        */
       if (t->is_tagged() || t->rawattrib || t->textattrib || t->jsonattrib ||
+          (!is_asn1() && t->hasEncodeAttr(get_encoding_name(CT_JSON))) ||
           (t->xerattrib && !t->xerattrib->empty() ))
       {
         return t->get_genname_own(p_scope);
@@ -6651,7 +6730,7 @@ namespace Common {
   {
     Type *t = this;
     while (true) {
-      if (t->jsonattrib) return t->get_genname_own(my_scope);
+      if (t->has_encoding(CT_JSON)) return t->get_genname_own(my_scope);
       else if (t->is_ref()) t = t->get_type_refd();
       else break;
     }
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index 746710b63..ffb0e605d 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -440,6 +440,12 @@ namespace Common {
       * 'any from' clause) of the 'done' function needs to be generated for
       * this type. */
     bool needs_any_from_done;
+    
+    /** True if JSON coder functions need to be generated for this type.
+      * This is not the same as enabling JSON encoding, since other types that
+      * refer to this type may have JSON encoding, in which case this type needs
+      * to have JSON coder functions to code them. */
+    bool gen_json_coder_functions;
 
     /** Copy constructor, for the use of Type::clone() only. */
     Type(const Type& p);
@@ -1065,8 +1071,16 @@ namespace Common {
     bool hasNeedofXerAttrs();
     bool hasVariantAttrs();
     /** Returns whether the type has the encoding attribute specified by
-      * the parameter (either in its own 'with' statement or in the module's) */
+      * the parameter. The function also checks the qualified attributes of
+      * parent types. Always returns true for ASN.1 types, when checking for a
+      * JSON encoding attribute. */
     bool hasEncodeAttr(const char* encoding_name);
+    /** Helper function for hasEncodeAttr. Checks this type's qualified encoding
+      * attributes that refer to the specified type (target_type) and returns
+      * true if any of them match the specified encoding (encoding_name).
+      * Recursive function (calls the parent type's hasEncodeAttrForType function
+      * if no matching attributes are found). */
+    bool hasEncodeAttrForType(Type* target_type, const char* encoding_name);
     /** Returns whether \a this can be encoded according to rules
      * \a p_encoding.
      * @note Should be called only during code generation, after the entire
@@ -1252,6 +1266,8 @@ namespace Common {
     
     inline void set_needs_any_from_done() { needs_any_from_done = true; }
     
+    inline void set_gen_json_coder_functions() { gen_json_coder_functions = true; }
+    
     /** Calculates the type's display name from the genname (replaces double
       * underscore characters with single ones) */
     string get_dispname() const;
diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index 8d70834b3..3e8d4c034 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -121,7 +121,7 @@ void Type::chk()
       textattrib = new TextAST;
     if(!xerattrib && hasVariantAttrs() &&  hasNeedofXerAttrs())
       xerattrib = new XerAttributes;
-    if (!jsonattrib && (hasVariantAttrs() || hasEncodeAttr(get_encoding_name(CT_JSON)) || hasNeedofJsonAttrs())) {
+    if (!jsonattrib && hasVariantAttrs() && hasNeedofJsonAttrs()) {
       jsonattrib = new JsonAST;
     }
     break;
@@ -258,7 +258,7 @@ void Type::parse_attributes()
   }
 
   if ((hasVariantAttrs())
-      && (enable_text() || enable_raw() || enable_xer())) {
+      && (enable_text() || enable_raw() || enable_xer() || enable_json())) {
 #ifndef NDEBUG
     if (rawAST_debug) {
       const char *fn = get_fullname().c_str();
diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc
index 91bba9d30..295f0cf25 100644
--- a/compiler2/Type_codegen.cc
+++ b/compiler2/Type_codegen.cc
@@ -276,8 +276,8 @@ void Type::generate_code_typedescriptor(output_struct *target)
   // FIXME: force_xer should be elminated. if a type needs a descriptor,
   // it should say so via get_genname_typedescriptor()
 
-  /* genname{type,ber,raw,text,xer}descriptor == gennameown is true if
-   * the type needs its own {type,ber,raw,text,xer}descriptor
+  /* genname{type,ber,raw,text,xer,json}descriptor == gennameown is true if
+   * the type needs its own {type,ber,raw,text,xer,json}descriptor
    * and can't use the descriptor of one of the built-in types.
    */
   if (gennametypedescriptor == gennameown
@@ -1102,7 +1102,7 @@ void Type::generate_code_Enum(output_struct *target)
   e_def.hasText = textattrib!=NULL;
   e_def.hasRaw = rawattrib!=NULL;
   e_def.hasXer = has_encoding(CT_XER);
-  e_def.hasJson = has_encoding(CT_JSON);
+  e_def.hasJson = gen_json_coder_functions;
   if (xerattrib) {
     e_def.xerUseNumber = xerattrib->useNumber_;
   }
@@ -1143,7 +1143,7 @@ void Type::generate_code_Choice(output_struct *target)
   sdef.isASN1 = is_asn1();
   sdef.hasText = textattrib!=NULL;
   sdef.hasXer = has_encoding(CT_XER);
-  sdef.hasJson = has_encoding(CT_JSON);
+  sdef.hasJson = gen_json_coder_functions;
   sdef.has_opentypes = get_has_opentypes();
   sdef.opentype_outermost = get_is_opentype_outermost();
   sdef.ot = generate_code_ot(pool);
@@ -1544,7 +1544,7 @@ void Type::generate_code_Se(output_struct *target)
   sdef.opentype_outermost = get_is_opentype_outermost();
   sdef.ot = NULL;
   sdef.hasXer = has_encoding(CT_XER);
-  sdef.hasJson = has_encoding(CT_JSON);
+  sdef.hasJson = gen_json_coder_functions;
   if (xerattrib){
     Module *my_module = get_my_scope()->get_scope_mod();
     sdef.xerHasNamespaces = my_module->get_nof_ns() != 0;
@@ -2005,7 +2005,7 @@ void Type::generate_code_SeOf(output_struct *target)
   sofdef.isASN1 = is_asn1();
   sofdef.hasText = textattrib!=NULL;
   sofdef.hasXer = has_encoding(CT_XER);
-  sofdef.hasJson = has_encoding(CT_JSON);
+  sofdef.hasJson = gen_json_coder_functions;
   if (xerattrib) {
     //sofdef.xerList      = xerattrib->list_;
     sofdef.xerAttribute = xerattrib->attribute_;
diff --git a/compiler2/ttcn3/Attributes.cc b/compiler2/ttcn3/Attributes.cc
index 4e1932708..d94f4eb4e 100644
--- a/compiler2/ttcn3/Attributes.cc
+++ b/compiler2/ttcn3/Attributes.cc
@@ -1155,6 +1155,12 @@ namespace Ttcn {
       {
         case SingleWithAttrib::AT_ENCODE:
         {
+          if (temp_attrib->get_attribQualifiers() != NULL &&
+              temp_attrib->get_attribQualifiers()->get_nof_qualifiers() != 0) {
+            // TODO: check the attributes grouped per qualifier (for now
+            // ignoring this check for attributes with qualifiers is enough)
+            break;
+          }
           if(has_encode)
           {
             temp_attrib->warning("Only the last encode "
diff --git a/regression_test/json/Functions.ttcn b/regression_test/json/Functions.ttcn
index 314b6505f..40f0690e4 100644
--- a/regression_test/json/Functions.ttcn
+++ b/regression_test/json/Functions.ttcn
@@ -15,6 +15,7 @@ module Functions
 
 import from Types all;
 import from JsonData language "ASN.1" all;
+import from OtherTypes all;
 
 //=================== Encoders =====================================
 
@@ -135,6 +136,66 @@ external function f_enc_meta_setof(in MetainfoSetOf x) return octetstring
 
 external function f_enc_meta_arr(in MetainfoArray x) return octetstring
   with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_type_alias_rec(in SupportedRec x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_type_alias_list(in SupportedList x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_type_alias_uni(in SupportedUni x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_type_alias_enum(in SupportedEnum x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_type_alias_any(in SupportedAny x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_field_rec(in RecWithEncAttrInFields.rec x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_field_list(in RecWithEncAttrInFields.list x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_field_uni(in RecWithEncAttrInFields.uni x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_field_enum(in RecWithEncAttr.en x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_field_any(in RecWithEncAttr.at x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_elem_rec(in RecOfRec[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_elem_list(in RecOfList[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_elem_uni(in RecOfUni[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_elem_enum(in RecOfEnum[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_elem_any(in RecOfAny[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_embedded_rec(in UniWithEmbEncAttr.rec.rec x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_embedded_list(in UniWithEmbEncAttr.rec.list x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_embedded_uni(in UniWithEmbEncAttr.uni_list[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_embedded_enum(in UniWithEmbEncAttr.emb_list[-].en x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
+  
+external function f_enc_embedded_any(in UniWithEmbEncAttr.emb_list[-].at_list[-] x) return octetstring
+  with { extension "prototype(convert) encode(JSON)" }
 
 // for ASN.1 types
 external function f_enc_seqofint(in SeqOfInt x) return octetstring
@@ -268,6 +329,66 @@ external function f_dec_meta_setof(in octetstring x) return MetainfoSetOf
   
 external function f_dec_meta_arr(in octetstring x) return MetainfoArray
   with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_type_alias_rec(in octetstring x) return SupportedRec
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_type_alias_list(in octetstring x) return SupportedList
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_type_alias_uni(in octetstring x) return SupportedUni
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_type_alias_enum(in octetstring x) return SupportedEnum
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_type_alias_any(in octetstring x) return SupportedAny
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_field_rec(in octetstring x) return RecWithEncAttrInFields.rec
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_field_list(in octetstring x) return RecWithEncAttrInFields.list
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_field_uni(in octetstring x) return RecWithEncAttrInFields.uni
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_field_enum(in octetstring x) return RecWithEncAttr.en
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_field_any(in octetstring x) return RecWithEncAttr.at
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_elem_rec(in octetstring x) return RecOfRec[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_elem_list(in octetstring x) return RecOfList[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_elem_uni(in octetstring x) return RecOfUni[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_elem_enum(in octetstring x) return RecOfEnum[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_elem_any(in octetstring x) return RecOfAny[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_embedded_rec(in octetstring x) return UniWithEmbEncAttr.rec.rec
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_embedded_list(in octetstring x) return UniWithEmbEncAttr.rec.list
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_embedded_uni(in octetstring x) return UniWithEmbEncAttr.uni_list[-]
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_embedded_enum(in octetstring x) return UniWithEmbEncAttr.emb_list[-].en
+  with { extension "prototype(convert) decode(JSON)" }
+  
+external function f_dec_embedded_any(in octetstring x) return UniWithEmbEncAttr.emb_list[-].at_list[-]
+  with { extension "prototype(convert) decode(JSON)" }
 
 // for ASN.1 types
 external function f_dec_seqofint(in octetstring x) return SeqOfInt
diff --git a/regression_test/json/Makefile b/regression_test/json/Makefile
index 53dd0318d..6362c3932 100644
--- a/regression_test/json/Makefile
+++ b/regression_test/json/Makefile
@@ -19,7 +19,7 @@ include $(TOPDIR)/Makefile.regression
 
 TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX)
 
-TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn SemanticCheck.ttcn
+TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn SemanticCheck.ttcn OtherTypes.ttcn
 
 ASN1_MODULES = JsonData.asn
 
diff --git a/regression_test/json/OtherTypes.ttcn b/regression_test/json/OtherTypes.ttcn
new file mode 100644
index 000000000..b55ebad06
--- /dev/null
+++ b/regression_test/json/OtherTypes.ttcn
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * Copyright (c) 2000-2017 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Baranyi, Botond
+ *
+ ******************************************************************************/
+
+// more type definitions, but this time there's not 'encode' attribute at module-level
+module OtherTypes {
+
+// 'base' types that do not support JSON encoding
+type record NotSuppRec {
+  integer x
+}
+
+type set of charstring NotSuppList;
+
+type union NotSuppUni {
+  integer x
+}
+
+type enumerated NotSuppEnum { val1 };
+
+// type aliases that give JSON encoding support to the 'base' types
+type NotSuppRec SupportedRec with { encode "JSON" };
+type NotSuppList SupportedList with { encode "JSON" };
+type NotSuppUni SupportedUni with { encode "JSON" };
+type NotSuppEnum SupportedEnum with { encode "JSON" };
+type anytype SupportedAny with { encode "JSON" };
+
+// types that use the 'base' types as fields/elements, and give them JSON encoding support
+type record RecWithEncAttrInFields {
+  NotSuppRec rec,
+  NotSuppList list,
+  NotSuppUni uni
+}
+with {
+  encode (rec) "JSON";
+  encode (list) "JSON";
+  encode (uni) "JSON";
+}
+
+type record RecWithEncAttr {
+  NotSuppEnum en,
+  anytype at
+}
+with {
+  encode "JSON";
+}
+
+type record of NotSuppRec RecOfRec with { encode "JSON" };
+type record of NotSuppList RecOfList with { encode "JSON" };
+type record of NotSuppUni RecOfUni with { encode ([-]) "JSON" };
+type record of NotSuppEnum RecOfEnum with { encode ([-]) "JSON" };
+type record of anytype RecOfAny with { encode ([-]) "JSON" };
+
+type union UniWithEmbEncAttr {
+  record {
+    NotSuppRec rec optional,
+    NotSuppList list optional
+  } rec,
+  record of NotSuppUni uni_list,
+  record of record {
+    SupportedEnum en optional,
+    record of anytype at_list optional
+  } emb_list
+}
+with {
+  encode (rec.rec) "JSON";
+  encode (rec.list) "JSON";
+  encode (uni_list[-]) "JSON";
+  encode (emb_list[-].en) "JSON";
+  encode (emb_list[-].at_list[-]) "JSON";
+}
+
+}
+with {
+  extension "anytype integer, charstring"
+}
diff --git a/regression_test/json/Testcases.ttcn b/regression_test/json/Testcases.ttcn
index 185ada5ed..1c890c262 100644
--- a/regression_test/json/Testcases.ttcn
+++ b/regression_test/json/Testcases.ttcn
@@ -15,6 +15,7 @@ module Testcases {
 import from Functions all;
 import from Types all;
 import from JsonData language "ASN.1" all;
+import from OtherTypes all;
 
 modulepar R tsp_r := {
   i:= 1,
@@ -632,6 +633,172 @@ testcase tc_binary_strings_with_invalid_chars() runs on MTC {
   }
 }
 
+// Coding a type alias with JSON encoding, whose base type is a record with no JSON encoding support.
+testcase tc_type_alias_record() runs on MTC {
+  var SupportedRec x := { x := 1 };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_type_alias_rec(x), expected := os);
+  f_bool2verdict(match(f_dec_type_alias_rec(os), x));
+}
+
+// Coding a type alias with JSON encoding, whose base type is a 'set of' with no JSON encoding support.
+testcase tc_type_alias_setof() runs on MTC {
+  var SupportedList x := { "abc", "xyz" };
+  var octetstring os := char2oct("[\"abc\",\"xyz\"]");
+  f_check_encoding(encoded:= f_enc_type_alias_list(x), expected := os);
+  f_bool2verdict(match(f_dec_type_alias_list(os), x));
+}
+
+// Coding a type alias with JSON encoding, whose base type is a union with no JSON encoding support.
+testcase tc_type_alias_union() runs on MTC {
+  var SupportedUni x := { x := 1 };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_type_alias_uni(x), expected := os);
+  f_bool2verdict(match(f_dec_type_alias_uni(os), x));
+}
+
+// Coding a type alias with JSON encoding, whose base type is an enumerated with no JSON encoding support.
+testcase tc_type_alias_enumerated() runs on MTC {
+  var SupportedEnum x := val1;
+  var octetstring os := char2oct("\"val1\"");
+  f_check_encoding(encoded:= f_enc_type_alias_enum(x), expected := os);
+  f_bool2verdict(match(f_dec_type_alias_enum(os), x));
+}
+
+// Coding a type alias with JSON encoding, whose base type is an anytype with no JSON encoding support.
+testcase tc_type_alias_anytype() runs on MTC {
+  var SupportedAny x := { integer := 1 };
+  var octetstring os := char2oct("{\"integer\":1}");
+  f_check_encoding(encoded:= f_enc_type_alias_any(x), expected := os);
+  f_bool2verdict(match(f_dec_type_alias_any(os), x));
+}
+
+const RecWithEncAttrInFields c_fields := {
+  rec := { x := 1 },
+  list := { "abc", "xyz" },
+  uni := { x := 1 }
+}
+
+const RecWithEncAttr c_fields2 := {
+  en := val1,
+  at := { integer := 1 }
+}
+
+// Coding a record field with JSON encoding, whose base type is a record with no JSON encoding support.
+testcase tc_field_record() runs on MTC {
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_field_rec(c_fields.rec), expected := os);
+  f_bool2verdict(match(f_dec_field_rec(os), c_fields.rec));
+}
+
+// Coding a record field with JSON encoding, whose base type is a 'set of' with no JSON encoding support.
+testcase tc_field_setof() runs on MTC {
+  var octetstring os := char2oct("[\"abc\",\"xyz\"]");
+  f_check_encoding(encoded:= f_enc_field_list(c_fields.list), expected := os);
+  f_bool2verdict(match(f_dec_field_list(os), c_fields.list));
+}
+
+// Coding a record field with JSON encoding, whose base type is a union with no JSON encoding support.
+testcase tc_field_union() runs on MTC {
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_field_uni(c_fields.uni), expected := os);
+  f_bool2verdict(match(f_dec_field_uni(os), c_fields.uni));
+}
+
+// Coding a record field with JSON encoding, whose base type is an enumerated with no JSON encoding support.
+testcase tc_field_enumerated() runs on MTC {
+  var octetstring os := char2oct("\"val1\"");
+  f_check_encoding(encoded:= f_enc_field_enum(c_fields2.en), expected := os);
+  f_bool2verdict(match(f_dec_field_enum(os), c_fields2.en));
+}
+
+// Coding a record field with JSON encoding, whose base type is an anytype with no JSON encoding support.
+testcase tc_field_anytype() runs on MTC {
+  var octetstring os := char2oct("{\"integer\":1}");
+  f_check_encoding(encoded:= f_enc_field_any(c_fields2.at), expected := os);
+  f_bool2verdict(match(f_dec_field_any(os), c_fields2.at));
+}
+
+// Coding a 'record of' element with JSON encoding, whose base type is a record with no JSON encoding support.
+testcase tc_elem_record() runs on MTC {
+  var RecOfRec x := { { x := 1 } };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_elem_rec(x[0]), expected := os);
+  f_bool2verdict(match(f_dec_elem_rec(os), x[0]));
+}
+
+// Coding a 'record of' element with JSON encoding, whose base type is a 'set of' with no JSON encoding support.
+testcase tc_elem_setof() runs on MTC {
+  var RecOfList x := { { "abc", "xyz" } };
+  var octetstring os := char2oct("[\"abc\",\"xyz\"]");
+  f_check_encoding(encoded:= f_enc_elem_list(x[0]), expected := os);
+  f_bool2verdict(match(f_dec_elem_list(os), x[0]));
+}
+
+// Coding a 'record of' element with JSON encoding, whose base type is a union with no JSON encoding support.
+testcase tc_elem_union() runs on MTC {
+  var RecOfUni x := { { x := 1 } };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_elem_uni(x[0]), expected := os);
+  f_bool2verdict(match(f_dec_elem_uni(os), x[0]));
+}
+
+// Coding a 'record of' element with JSON encoding, whose base type is an enumerated with no JSON encoding support.
+testcase tc_elem_enumerated() runs on MTC {
+  var RecOfEnum x := { val1 };
+  var octetstring os := char2oct("\"val1\"");
+  f_check_encoding(encoded:= f_enc_elem_enum(x[0]), expected := os);
+  f_bool2verdict(match(f_dec_elem_enum(os), x[0]));
+}
+
+// Coding a 'record of' element with JSON encoding, whose base type is an anytype with no JSON encoding support.
+testcase tc_elem_anytype() runs on MTC {
+  var RecOfAny x := { { integer := 1 } };
+  var octetstring os := char2oct("{\"integer\":1}");
+  f_check_encoding(encoded:= f_enc_elem_any(x[0]), expected := os);
+  f_bool2verdict(match(f_dec_elem_any(os), x[0]));
+}
+
+// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is a record with no JSON encoding support.
+testcase tc_embedded_record() runs on MTC {
+  var UniWithEmbEncAttr x := { rec := { rec := { x := 1 }, list := omit } };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_embedded_rec(x.rec.rec), expected := os);
+  f_bool2verdict(match(f_dec_embedded_rec(os), x.rec.rec));
+}
+
+// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is a 'set of' with no JSON encoding support.
+testcase tc_embedded_setof() runs on MTC {
+  var UniWithEmbEncAttr x := { rec := { rec := omit, list := { "abc", "xyz" } } };
+  var octetstring os := char2oct("[\"abc\",\"xyz\"]");
+  f_check_encoding(encoded:= f_enc_embedded_list(x.rec.list), expected := os);
+  f_bool2verdict(match(f_dec_embedded_list(os), x.rec.list));
+}
+
+// Coding an embedded element type (in a multi-level structure) with JSON encoding, whose base type is a union with no JSON encoding support.
+testcase tc_embedded_union() runs on MTC {
+  var UniWithEmbEncAttr x := { uni_list := { { x := 1 } } };
+  var octetstring os := char2oct("{\"x\":1}");
+  f_check_encoding(encoded:= f_enc_embedded_uni(x.uni_list[0]), expected := os);
+  f_bool2verdict(match(f_dec_embedded_uni(os), x.uni_list[0]));
+}
+
+// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is an enumerated with no JSON encoding support.
+testcase tc_embedded_enumerated() runs on MTC {
+  var UniWithEmbEncAttr x := { emb_list := { { en := val1, at_list := omit } } };
+  var octetstring os := char2oct("\"val1\"");
+  f_check_encoding(encoded:= f_enc_embedded_enum(x.emb_list[0].en), expected := os);
+  f_bool2verdict(match(f_dec_embedded_enum(os), x.emb_list[0].en));
+}
+
+// Coding an embedded element type (in a multi-level structure) with JSON encoding, whose base type is an anytype with no JSON encoding support.
+testcase tc_embedded_anytype() runs on MTC {
+  var UniWithEmbEncAttr x := { emb_list := { { en := omit, at_list := { { integer := 1 } } } } };
+  var octetstring os := char2oct("{\"integer\":1}");
+  f_check_encoding(encoded:= f_enc_embedded_any(x.emb_list[0].at_list[0]), expected := os);
+  f_bool2verdict(match(f_dec_embedded_any(os), x.emb_list[0].at_list[0]));
+}
+
 //=========================================================================
 // Control
 //=========================================================================
@@ -698,6 +865,27 @@ control {
   
   execute(tc_binary_strings_with_white_spaces());
   execute(tc_binary_strings_with_invalid_chars());
+  
+  execute(tc_type_alias_record());
+  execute(tc_type_alias_setof());
+  execute(tc_type_alias_union());
+  execute(tc_type_alias_enumerated());
+  execute(tc_type_alias_anytype());
+  execute(tc_field_record());
+  execute(tc_field_setof());
+  execute(tc_field_union());
+  execute(tc_field_enumerated());
+  execute(tc_field_anytype());
+  execute(tc_elem_record());
+  execute(tc_elem_setof());
+  execute(tc_elem_union());
+  execute(tc_elem_enumerated());
+  execute(tc_elem_anytype());
+  execute(tc_embedded_record());
+  execute(tc_embedded_setof());
+  execute(tc_embedded_union());
+  execute(tc_embedded_enumerated());
+  execute(tc_embedded_anytype());
 }
 
 
-- 
GitLab