Commit 55528f72 authored by Kristof Szabados's avatar Kristof Szabados Committed by Gerrit Code Review
Browse files

Merge "Implemented the 'override' and '@local' modifiers in the new codec handling (bug 517843)"

parents 21311e6f bb7d1e4b
......@@ -61,7 +61,7 @@ extern Ttcn::ExtensionAttributes * parse_extattributes(
namespace Common {
map<Type*, void> Type::CodingCheckTracker::types;
map<Type*, void> Type::RecursionTracker::types;
using Ttcn::MultiWithAttrib;
using Ttcn::SingleWithAttrib;
......@@ -615,6 +615,7 @@ namespace Common {
default_encoding.type = CODING_UNSET;
default_decoding.type = CODING_UNSET;
checked_incorrect_field = false;
encode_attrib_mod_conflict = false;
}
void Type::clean_up()
......@@ -1216,6 +1217,11 @@ namespace Common {
Type::truth Type::is_charenc()
{
// this helps avoid infinite recursions in self-referencing types
if (RecursionTracker::is_happening(this)) {
return Maybe;
}
RecursionTracker tracker(this);
switch(typetype) {
case T_CHOICE_A:
case T_CHOICE_T:
......@@ -3265,12 +3271,17 @@ namespace Common {
}
}
void Type::add_coding(const string& name, bool silent)
void Type::add_coding(const string& name, Ttcn::attribute_modifier_t modifier, bool silent)
{
if (legacy_codec_handling) {
FATAL_ERROR("Type::add_coding");
}
for (size_t i = 0; i < coding_table.size(); ++i) {
if (!encode_attrib_mod_conflict && modifier != coding_table[i]->modifier) {
encode_attrib_mod_conflict = true;
error("All 'encode' attributes of a type must have the same modifier "
"('override', '@local' or none)");
}
const char* coding_name = coding_table[i]->built_in ?
get_encoding_name(coding_table[i]->built_in_coding) :
coding_table[i]->custom_coding.name;
......@@ -3283,6 +3294,7 @@ namespace Common {
if (get_type_refd_last()->can_have_coding(built_in_coding)) {
coding_t* new_coding = new coding_t;
new_coding->built_in = TRUE;
new_coding->modifier = modifier;
new_coding->built_in_coding = built_in_coding;
coding_table.add(new_coding);
get_type_refd_last()->set_gen_coder_functions(built_in_coding);
......@@ -3297,6 +3309,7 @@ namespace Common {
else {
coding_t* new_coding = new coding_t;
new_coding->built_in = FALSE;
new_coding->modifier = modifier;
new_coding->custom_coding.name = mcopystr(name.c_str());
new_coding->custom_coding.encoders = new map<Type*, coder_function_t>;
new_coding->custom_coding.decoders = new map<Type*, coder_function_t>;
......@@ -3380,35 +3393,72 @@ namespace Common {
return NULL; // not found
}
Type* Type::get_type_w_coding_table()
Type* Type::get_type_w_coding_table(bool ignore_local /* = false */)
{
// only return the type if it has a non-empty coding table
if (coding_table.size() != 0) {
// 1st priority: if local attributes are not ignored, and if the type
// has its own 'encode' attributes (its coding table is not empty), then
// return the type
if (!ignore_local && coding_table.size() != 0) {
return this;
}
// first, check referenced types
// 2nd priority: if this is a field or element type, and one of its parents
// has an 'encode' attribute with the 'override' modifier, then return the
// parent type
Type* t_parent = NULL;
if (parent_type != NULL && (ownertype == OT_COMP_FIELD ||
ownertype == OT_RECORD_OF || ownertype == OT_ARRAY)) {
// note: if one of the parent types has an overriding 'encode' attribute,
// then this returns the furthest parent with an overriding 'encode';
// if none of the 'encode' attributes are overriding, then the nearest
// parent with at least one 'encode' attribute is returned
t_parent = parent_type->get_type_w_coding_table(true);
}
if (t_parent != NULL) {
for (size_t i = 0; i < t_parent->coding_table.size(); ++i) {
if (t_parent->coding_table[i]->modifier == Ttcn::MOD_OVERRIDE) {
return t_parent;
}
}
}
// 3rd priority: if local attributes are ignored, and if the type has its
// own (non-local) 'encode' attributes, then return the type
if (ignore_local && coding_table.size() != 0) {
bool local = false;
for (size_t i = 0; i < coding_table.size(); ++i) {
if (coding_table[i]->modifier == Ttcn::MOD_LOCAL) {
local = true;
break;
}
}
if (!local) {
return this;
}
}
// 4th priority, if a referenced type has an 'encode' attribute, then return
// the referenced type
if (is_ref()) {
Type* t = get_type_refd()->get_type_w_coding_table();
// note: this always returns the nearest referenced type with at least one
// 'encode' attribute
Type* t = get_type_refd()->get_type_w_coding_table(false);
if (t != NULL) {
return t;
}
}
// second, check the parent type if this is a field or element type
if (parent_type != NULL && (ownertype == OT_COMP_FIELD ||
ownertype == OT_RECORD_OF || ownertype == OT_ARRAY)) {
return parent_type->get_type_w_coding_table();
}
// if none of the above have a non-empty coding table, then return null
return NULL;
// otherwise return the parent type pointer (whether it's null or not)
return t_parent;
}
bool Type::can_have_coding(MessageEncodingType_t coding)
{
// this helps avoid infinite recursions in self-referencing types
if (CodingCheckTracker::is_happening(this)) {
if (RecursionTracker::is_happening(this)) {
return true;
}
CodingCheckTracker tracker(this);
RecursionTracker tracker(this);
// check whether the codec has been disabled by a compiler option or by
// the license
......
......@@ -76,6 +76,13 @@ namespace Ttcn {
class PortTypeBody;
class Def_Type;
class Ref_pard;
/** Stores the modifier of an attribute */
enum attribute_modifier_t {
MOD_NONE, ///< no modifier
MOD_OVERRIDE, ///< 'override' modifier
MOD_LOCAL ///< '@local' modifier
};
} // namespace Ttcn
// not defined here
......@@ -303,6 +310,7 @@ namespace Common {
* codec handling. */
struct coding_t {
boolean built_in; ///< built-in or user defined codec
Ttcn::attribute_modifier_t modifier; ///< the 'encode' attribute's modifier
union {
MessageEncodingType_t built_in_coding; ///< built-in codec
struct {
......@@ -478,14 +486,18 @@ namespace Common {
* method. */
vector<MessageEncodingType_t> coders_to_generate;
/** Helper class that tracks the execution of a type's 'can_have_coding'
* function to prevent infinite recursions. */
class CodingCheckTracker {
/** Indicates whether an 'encode' attribute modifier conflict error has
* already been displayed for the type. */
bool encode_attrib_mod_conflict;
/** Helper class that tracks the execution of recursive functions in the
* Type class in order to prevent infinite recursions. */
class RecursionTracker {
static map<Type*, void> types;
Type* key;
public:
CodingCheckTracker(Type* t): key(t) { types.add(t, NULL); }
~CodingCheckTracker() { types.erase(key); }
RecursionTracker(Type* t): key(t) { types.add(t, NULL); }
~RecursionTracker() { types.erase(key); }
static bool is_happening(Type* t) { return types.has_key(t); }
};
......@@ -512,6 +524,13 @@ namespace Common {
static void destroy_pooltypes();
/** Returns the TTCN-3 equivalent of \a p_tt. */
static typetype_t get_typetype_ttcn3(typetype_t p_tt);
/** Fills the list parameter with the types that have an empty coding table.
* The types considered are the type itself and its field and element types.
* Recursive.
* @param only_own_table if true, then only the type's own coding table is
* checked, otherwise inherited coding tables are also checked */
void get_types_w_no_coding_table(vector<Type>& type_list, bool only_own_table);
public:
/** @name Constructors
......@@ -652,7 +671,7 @@ namespace Common {
* if the type can have that encoding.
* @param name name of the encoding as it appears in the 'encode' attribute;
* this may be the name of a built-in or a user-defined encoding */
void add_coding(const string& name, bool silent);
void add_coding(const string& name, Ttcn::attribute_modifier_t modifier, bool silent);
/** Sets the encoder or decoder function for the user-defined encoding with
* the specified name (when using new codec handling). */
......@@ -666,8 +685,10 @@ namespace Common {
/** Returns the type that contains this type's coding table (since types
* with no 'encode' attributes of their own inherit the 'encode' attributes
* of a referenced type or a parent type).
* @param ignore_local indicates whether to ignore attributes with the
* '@local' modifier
* Only used with new codec handling. */
Type* get_type_w_coding_table();
Type* get_type_w_coding_table(bool ignore_local = false);
const vector<coding_t>& get_coding_table() const { return coding_table; }
......
......@@ -338,7 +338,7 @@ void Type::parse_attributes()
// see if there's an encode with override
for(size_t i = real_attribs.size(); i > 0 && !override_ref; i--)
{
if(real_attribs[i-1]->has_override()
if(real_attribs[i-1]->get_modifier() == Ttcn::MOD_OVERRIDE
&& real_attribs[i-1]->get_attribKeyword()
!= SingleWithAttrib::AT_ENCODE)
override_ref = true;
......@@ -491,7 +491,7 @@ void Type::parse_attributes()
// Copy the attribute without qualifiers
const SingleWithAttrib* swaref = self_attribs->get_element(i);
swa = new SingleWithAttrib(swaref->get_attribKeyword(),
swaref->has_override(), 0, swaref->get_attribSpec().clone());
swaref->get_modifier(), 0, swaref->get_attribSpec().clone());
new_self_attribs->add_element(swa);
}
}
......@@ -558,7 +558,7 @@ void Type::parse_attributes()
// A copy of temp_single, with new qualifiers
SingleWithAttrib* temp_single2
= new SingleWithAttrib(temp_single->get_attribKeyword(),
temp_single->has_override(),
temp_single->get_modifier(),
calculated_qualifiers,
temp_single->get_attribSpec().clone());
temp_single2->set_location(*temp_single);
......@@ -670,6 +670,37 @@ void change_name(string &name, XerAttributes::NameChange change) {
} // switch for NAME
}
void Type::get_types_w_no_coding_table(vector<Type>& type_list, bool only_own_table)
{
// this helps avoid infinite recursions in self-referencing types
if (RecursionTracker::is_happening(this)) {
return;
}
RecursionTracker tracker(this);
if ((only_own_table && coding_table.size() == 0) ||
(!only_own_table && get_type_w_coding_table() == NULL)) {
type_list.add(this);
}
switch (get_typetype_ttcn3()) {
case T_SEQ_T:
case T_SET_T:
case T_CHOICE_T:
case T_ANYTYPE:
case T_OPENTYPE:
for (size_t j = 0; j < get_nof_comps(); ++j) {
get_comp_byIndex(j)->get_type()->get_types_w_no_coding_table(type_list, only_own_table);
}
break;
case T_SEQOF:
case T_SETOF:
case T_ARRAY:
get_ofType()->get_types_w_no_coding_table(type_list, only_own_table);
break;
default:
break;
}
}
void Type::chk_encodings()
{
if (legacy_codec_handling) {
......@@ -703,6 +734,7 @@ void Type::chk_encodings()
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) {
Ttcn::attribute_modifier_t mod = swa->get_modifier();
Ttcn::Qualifiers* quals = swa->get_attribQualifiers();
if (quals != NULL && quals->get_nof_qualifiers() != 0) {
for (size_t j = 0; j < quals->get_nof_qualifiers(); ++j) {
......@@ -715,26 +747,75 @@ void Type::chk_encodings()
"refers to a type from a different type definition");
}
else {
t->add_coding(swa->get_attribSpec().get_spec(), false);
t->add_coding(swa->get_attribSpec().get_spec(), mod, false);
}
}
}
}
else {
add_coding(swa->get_attribSpec().get_spec(), false);
add_coding(swa->get_attribSpec().get_spec(), mod, false);
}
}
}
}
if (get_type_w_coding_table() == NULL) {
// if there are no 'encode' attributes in this type, the referenced
// types, or the parent type, then try the nearest group or the module
const vector<SingleWithAttrib>& real = ap->get_real_attrib();
WithAttribPath* global_ap = NULL;
Ttcn::Def_Type* def = static_cast<Ttcn::Def_Type*>(owner);
Ttcn::Group* nearest_group = def->get_parent_group();
if (nearest_group != NULL) { // there is a group
global_ap = nearest_group->get_attrib_path();
}
else { // no group, use the module
Common::Module* mymod = my_scope->get_scope_mod();
// OT_TYPE_DEF is always from a TTCN-3 module
Ttcn::Module* my_ttcn_module = static_cast<Ttcn::Module *>(mymod);
global_ap = my_ttcn_module->get_attrib_path();
}
if (global_ap != NULL) {
bool has_global_override = false;
bool modifier_conflict = false;
Ttcn::attribute_modifier_t first_mod = Ttcn::MOD_NONE;
const vector<SingleWithAttrib>& real = global_ap->get_real_attrib();
for (size_t i = 0; i < real.size(); ++i) {
const SingleWithAttrib* swa = real[i];
if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE) {
add_coding(swa->get_attribSpec().get_spec(), true);
Ttcn::attribute_modifier_t mod = swa->get_modifier();
if (i == 0) {
first_mod = mod;
}
else if (!modifier_conflict && mod != first_mod) {
modifier_conflict = true;
swa->error("All 'encode' attributes of a group or module must "
"have the same modifier ('override', '@local' or none)");
}
if (mod == Ttcn::MOD_OVERRIDE) {
has_global_override = true;
}
if (has_global_override && modifier_conflict) {
break;
}
}
}
// make a list of the type and its field and element types that inherit
// the global 'encode' attributes
// overriding global attributes are inherited by types with no coding
// table (no 'encode' attributes) of their own
// non-overriding global attributes are inherited by types that have
// no coding table of their own and cannot use the coding table of any
// other type (get_type_w_coding_table() == NULL)
vector<Type> type_list;
get_types_w_no_coding_table(type_list, has_global_override);
if (type_list.size() != 0) {
for (size_t i = 0; i < real.size(); ++i) {
const SingleWithAttrib* swa = real[i];
if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE) {
for (size_t j = 0; j < type_list.size(); ++j) {
type_list[j]->add_coding(swa->get_attribSpec().get_spec(),
Ttcn::MOD_NONE, true);
}
}
}
type_list.clear();
}
}
}
......@@ -746,12 +827,12 @@ void Type::chk_encodings()
case OT_COMP_FIELD:
case OT_SELTYPE:
// ASN.1 types automatically have BER, PER, XER and JSON encoding
add_coding(string("BER:2002"), true);
add_coding(string(get_encoding_name(CT_PER)), true);
add_coding(string(get_encoding_name(CT_JSON)), true);
add_coding(string("BER:2002"), Ttcn::MOD_NONE, true);
add_coding(string(get_encoding_name(CT_PER)), Ttcn::MOD_NONE, true);
add_coding(string(get_encoding_name(CT_JSON)), Ttcn::MOD_NONE, true);
if (asn1_xer) {
// XER encoding for ASN.1 types can be disabled with a command line option
add_coding(string(get_encoding_name(CT_XER)), true);
add_coding(string(get_encoding_name(CT_XER)), Ttcn::MOD_NONE, true);
}
break;
default:
......
......@@ -6848,26 +6848,28 @@ namespace Ttcn {
// First collect the fields of a record, set, union type which
// does not support the encoding, then write it in the error message.
char* message = NULL;
Type *t = input_type;
if (t->is_ref()) t = t->get_type_refd();
switch(t->get_typetype()) {
case Type::T_SEQ_T:
case Type::T_SET_T:
case Type::T_CHOICE_T: {
for (size_t i = 0; i < t->get_nof_comps(); i++) {
if (!t->get_comp_byIndex(i)->get_type()->has_encoding(encoding_type, encoding_options)) {
if (i == 0) {
message = mputprintf(message, " The following fields do not support %s encoding: ",
Type::get_encoding_name(encoding_type));
} else {
message = mputstr(message, ", ");
if (legacy_codec_handling) {
Type *t = input_type;
if (t->is_ref()) t = t->get_type_refd();
switch(t->get_typetype()) {
case Type::T_SEQ_T:
case Type::T_SET_T:
case Type::T_CHOICE_T: {
for (size_t i = 0; i < t->get_nof_comps(); i++) {
if (!t->get_comp_byIndex(i)->get_type()->has_encoding(encoding_type, encoding_options)) {
if (i == 0) {
message = mputprintf(message, " The following fields do not support %s encoding: ",
Type::get_encoding_name(encoding_type));
} else {
message = mputstr(message, ", ");
}
message = mputstr(message, t->get_comp_id_byIndex(i).get_ttcnname().c_str());
}
message = mputstr(message, t->get_comp_id_byIndex(i).get_ttcnname().c_str());
}
}
break; }
default:
break;
break; }
default:
break;
}
}
input_type->error("Input type `%s' does not support %s encoding.%s",
input_type->get_typename().c_str(),
......
......@@ -905,17 +905,17 @@ namespace Ttcn {
SingleWithAttrib::SingleWithAttrib(const SingleWithAttrib& p)
: Node(p), Location(p), attribKeyword(p.attribKeyword),
hasOverride(p.hasOverride)
modifier(p.modifier)
{
attribQualifiers = p.attribQualifiers ? p.attribQualifiers->clone() : 0;
attribSpec = p.attribSpec->clone();
}
SingleWithAttrib::SingleWithAttrib(
attribtype_t p_attribKeyword, bool p_hasOverride,
attribtype_t p_attribKeyword, attribute_modifier_t p_modifier,
Qualifiers *p_attribQualifiers, AttributeSpec* p_attribSpec)
: Node(), Location(), attribKeyword(p_attribKeyword),
hasOverride(p_hasOverride), attribQualifiers(p_attribQualifiers),
modifier(p_modifier), attribQualifiers(p_attribQualifiers),
attribSpec(p_attribSpec)
{
if(!p_attribSpec)
......@@ -971,7 +971,8 @@ namespace Ttcn {
FATAL_ERROR("SingleWithAttrib::dump()");
}
DEBUG(level + 1, hasOverride ? "has override" : "hasn't got override");
DEBUG(level + 1, "modifier: %s", modifier == MOD_NONE ? "none" :
(modifier == MOD_OVERRIDE ? "override" : "@local"));
if(attribSpec)
attribSpec->dump(level + 1);
......@@ -1045,7 +1046,8 @@ namespace Ttcn {
WithAttribPath::WithAttribPath(const WithAttribPath& p)
: Node(p), had_global_variants(false), attributes_checked(false),
cached(false), s_o_encode(false), parent(p.parent)
global_attrib_checked(false), cached(false), s_o_encode(false),
parent(p.parent)
{
m_w_attrib = p.m_w_attrib ? p.m_w_attrib->clone() : 0;
}
......@@ -1131,7 +1133,7 @@ namespace Ttcn {
*/
void WithAttribPath::chk_global_attrib(bool erroneous_allowed)
{
if(!m_w_attrib)
if(!m_w_attrib || global_attrib_checked)
return;
if (!erroneous_allowed) {
......@@ -1177,7 +1179,7 @@ namespace Ttcn {
break;
case SingleWithAttrib::AT_ERRONEOUS:
{
if (temp_attrib->has_override()) {
if (temp_attrib->get_modifier() == MOD_OVERRIDE) {
temp_attrib->error("Override cannot be used with erroneous");
}
}
......@@ -1190,6 +1192,22 @@ namespace Ttcn {
for(size_t i = 0; i < m_w_attrib->get_nof_elements();)
{
const SingleWithAttrib* const temp_attrib = m_w_attrib->get_element(i);
if (temp_attrib->get_modifier() == MOD_LOCAL) {
if (legacy_codec_handling) {
temp_attrib->error("The '@local' modifier cannot be used with legacy "
"codec handling");
}
else if (temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_ENCODE) {
temp_attrib->warning("The '@local' modifier only affects 'encode' "
"attributes. Modifier ignored.");
}
}
if (!temp_attrib->get_attribSpec().get_encoding().empty() &&
(legacy_codec_handling ||
temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_VARIANT)) {
temp_attrib->error("Invalid attribute format. Dot notation is only "
"allowed for variant attributes when using the new codec handling.");
}
switch(temp_attrib->get_attribKeyword())
{
case SingleWithAttrib::AT_VARIANT:
......@@ -1200,7 +1218,7 @@ namespace Ttcn {
" variant of the with statement will have effect");
m_w_attrib->delete_element(i);
}else{
if(temp_attrib->has_override())
if(temp_attrib->get_modifier() == MOD_OVERRIDE)
has_override_variant = true;
i++;
}
......@@ -1214,7 +1232,7 @@ namespace Ttcn {
" display of the with statement will have effect");
m_w_attrib->delete_element(i);
}else{
if(temp_attrib->has_override())
if(temp_attrib->get_modifier() == MOD_OVERRIDE)
has_override_display = true;
i++;
}
......@@ -1228,7 +1246,7 @@ namespace Ttcn {
" extension of the with statement will have effect");
m_w_attrib->delete_element(i);
}else{
if(temp_attrib->has_override())
if(temp_attrib->get_modifier() == MOD_OVERRIDE)
has_override_extension = true;
i++;
}
......@@ -1248,7 +1266,7 @@ namespace Ttcn {
" optional of the with statement will have effect");
m_w_attrib->delete_element(i);
}else{
if(temp_attrib->has_override())
if(temp_attrib->get_modifier() == MOD_OVERRIDE)
has_override_optional = true;
i++;
}
......@@ -1259,6 +1277,7 @@ namespace Ttcn {
break;
} // switch
} // next i
global_attrib_checked = true;
}
void WithAttribPath::set_with_attr(MultiWithAttrib* p_m_w_attr)
......@@ -1266,6 +1285,7 @@ namespace Ttcn {
if(m_w_attrib) FATAL_ERROR("WithAttribPath::set_with_attr()");
m_w_attrib = p_m_w_attr;
attributes_checked = false;
global_attrib_checked = false;
}
/**
......@@ -1370,7 +1390,7 @@ namespace Ttcn {
{
case SingleWithAttrib::AT_ENCODE:
par_has_encode = true;
par_has_override_encode |= act_single->has_override();
par_has_override_encode |= act_single->get_modifier() == MOD_OVERRIDE;
if(self_encode_index != -1)
{
// We also have an encode. See if they differ.
......@@ -1381,16 +1401,16 @@ namespace Ttcn {
break;
case SingleWithAttrib::AT_VARIANT:
par_has_override_variant |= act_single->has_override();
par_has_override_variant |= act_single->get_modifier() == MOD_OVERRIDE;
break;
case SingleWithAttrib::AT_DISPLAY:
par_has_override_display |= act_single->has_override();
par_has_override_display |= act_single->get_modifier() == MOD_OVERRIDE;
break;
case SingleWithAttrib::AT_EXTENSION:
par_has_override_extension |= act_single->has_override();
par_has_override_extension |= act_single->get_modifier() == MOD_OVERRIDE;
break;
case SingleWithAttrib::AT_OPTIONAL:
par_has_override_optional |= act_single->has_override();
par_has_override_optional |= act_single->get_modifier() == MOD_OVERRIDE;
break;
case SingleWithAttrib::AT_ERRONEOUS:
case SingleWithAttrib::AT_INVALID:
......
......@@ -267,21 +267,21 @@ namespace Ttcn {
};
private:
attribtype_t attribKeyword;
/// True if the \c override keyword was used
bool hasOverride;