#include "ast_valuetype.h" #include "ast_typedef.h" #include "ast_factory.h" #include "ast_visitor.h" #include "ast_extern.h" #include "ast_field.h" #include "ast_param_holder.h" #include "utl_err.h" #include "utl_identifier.h" #include "utl_indenter.h" #include "utl_string.h" #include "global_extern.h" #include "nr_extern.h" #include "ace/streams.h" AST_Decl::NodeType const AST_ValueType::NT = AST_Decl::NT_valuetype; AST_ValueType::AST_ValueType (UTL_ScopedName *n, AST_Type **inherits, long n_inherits, AST_Type *inherits_concrete, AST_Interface **inherits_flat, long n_inherits_flat, AST_Type **supports, long n_supports, AST_Type *supports_concrete, bool abstract, bool truncatable, bool custom) : COMMON_Base (false, abstract), AST_Decl (AST_Decl::NT_valuetype, n), AST_Type (AST_Decl::NT_valuetype, n), UTL_Scope (AST_Decl::NT_valuetype), AST_Interface (n, inherits, n_inherits, inherits_flat, n_inherits_flat, false, abstract), pd_supports (supports), pd_n_supports (n_supports), pd_inherits_concrete (inherits_concrete), pd_supports_concrete (supports_concrete), pd_truncatable (truncatable), pd_custom (custom) { // Enqueue the param holders (if any) for later destruction. // By the time our destroy() is called, it will be too late // to iterate over pd_inherits. // Also check for illegal template module scope reference, // as long as we're iterating. for (long i = 0; i < n_supports; ++i) { if (supports[i]->node_type () == AST_Decl::NT_param_holder) { this->param_holders_.enqueue_tail (supports[i]); } FE_Utils::tmpl_mod_ref_check (this, supports[i]); } if (inherits_concrete != nullptr) { if (inherits_concrete->node_type () == AST_Decl::NT_param_holder) { this->param_holders_.enqueue_tail (inherits_concrete); } } } AST_ValueType::~AST_ValueType () { } bool AST_ValueType::in_recursion (ACE_Unbounded_Queue &list) { bool self_test = (list.size () == 0); // We should calculate this only once. If it has already been // done, just return it. if (self_test && this->in_recursion_ != -1) { return (this->in_recursion_ == 1); } if (list.size ()) { if (match_names (this, list)) { // A valuetype may contain itself as a member (nesting == 1) // which is not a problem., but we could also match ourselves when // we are not recursed ourselves but instead are part of another // recursive type. if (list.size () == 1) { idl_global->recursive_type_seen_ = true; return true; } else { // get the head element which is the type being tested AST_Type** recursable_type = nullptr; list.get (recursable_type, 0); // Check if we are the possibly recursive type being tested if (!ACE_OS::strcmp (this->full_name (), (*recursable_type)->full_name ())) { // match, so we're recursive idl_global->recursive_type_seen_ = true; return true; } else { return false; } } } } list.enqueue_tail(this); for (UTL_ScopeActiveIterator si (this, UTL_Scope::IK_decls); !si.is_done (); si.next()) { AST_Decl *d = si.item (); if (!d) { ACE_ERROR_RETURN ((LM_ERROR, "(%N:%l) be_valuetype::in_recursion - " "bad node in this scope\n"), 0); } AST_Field *field = dynamic_cast (d); if (field == nullptr) { continue; } AST_Type *type = field->field_type (); if (type == nullptr) { ACE_ERROR_RETURN ((LM_ERROR, "(%N:%l) be_valuetype::in_recursion - " "bad base type\n"), 0); } if (type->node_type () == AST_Decl::NT_typedef) { AST_Typedef *td = dynamic_cast (type); type = td->primitive_base_type (); } // Now hand over to our field type. if (type->in_recursion (list)) { if (self_test) this->in_recursion_ = 1; idl_global->recursive_type_seen_ = true; return true; } } // end of for loop // Not in recursion. if (self_test) this->in_recursion_ = 0; return false; } void AST_ValueType::redefine (AST_Interface *from) { AST_ValueType *vt = dynamic_cast (from); if (vt == nullptr) { idl_global->err ()->redef_error (from->local_name ()->get_string (), this->local_name ()->get_string ()); return; } // Copy over all the base class members. this->AST_Interface::redefine (from); this->pd_inherits_concrete = vt->pd_inherits_concrete; this->pd_supports_concrete = vt->pd_supports_concrete; this->pd_truncatable = vt->pd_truncatable; } AST_Type ** AST_ValueType::supports () const { return this->pd_supports; } long AST_ValueType::n_supports () const { return this->pd_n_supports; } AST_Type * AST_ValueType::inherits_concrete () const { return this->pd_inherits_concrete; } AST_Type * AST_ValueType::supports_concrete () const { return this->pd_supports_concrete; } bool AST_ValueType::truncatable () const { return this->pd_truncatable; } bool AST_ValueType::custom () const { return this->pd_custom; } bool AST_ValueType::will_have_factory () { return false; } // Look through supported interface list. AST_Decl * AST_ValueType::look_in_supported (UTL_ScopedName *e, bool full_def_only) { AST_Decl *d = nullptr; AST_Decl *d_before = nullptr; AST_Type **is = nullptr; long nis = -1; // Can't look in an interface which was not yet defined. if (!this->is_defined ()) { return nullptr; } // OK, loop through supported interfaces. // (Don't leave the inheritance hierarchy, no module or global ...) // Find all and report ambiguous results as error. for (nis = this->n_supports (), is = this->supports (); nis > 0; nis--, is++) { if ((*is)->node_type () == AST_Decl::NT_param_holder) { continue; } AST_Interface *i = dynamic_cast (*is); d = (i)->lookup_by_name_r (e, full_def_only); if (d != nullptr) { if (d_before == nullptr) { // First result found. d_before = d; } else { // Conflict against further results? if (d != d_before) { ACE_ERROR ((LM_ERROR, "warning in %C line %d: ", idl_global->filename ()->get_string (), idl_global->lineno ())); e->dump (*ACE_DEFAULT_LOG_STREAM); ACE_ERROR ((LM_ERROR, " is ambiguous in scope.\n" "Found ")); d->name ()->dump (*ACE_DEFAULT_LOG_STREAM); ACE_ERROR ((LM_ERROR, " and ")); d_before->name ()->dump (*ACE_DEFAULT_LOG_STREAM); ACE_ERROR ((LM_ERROR, ".\n")); } } } } return d_before; } AST_Decl * AST_ValueType::special_lookup (UTL_ScopedName *e, bool full_def_only, AST_Decl *&/*final_parent_decl*/) { AST_Decl *d = this->look_in_inherited (e, full_def_only); if (d == nullptr) { d = this->look_in_supported (e, full_def_only); } return d; } bool AST_ValueType::legal_for_primary_key () const { AST_ValueType *pk_base = this->lookup_primary_key_base (); if (!this->derived_from_primary_key_base (this, pk_base)) { return false; } bool has_public_member = false; bool retval = true; if (!this->recursing_in_legal_pk_) { this->recursing_in_legal_pk_ = true; for (UTL_ScopeActiveIterator i (const_cast (this), UTL_Scope::IK_decls); !i.is_done (); i.next ()) { AST_Field *f = dynamic_cast (i.item ()); // We're not interested in any valuetype decls that aren't fields. if (f == nullptr) { continue; } // Private members are not allowed in primary keys. if (f->visibility () == AST_Field::vis_PRIVATE) { retval = false; break; } else { // Returns false for interfaces, components, homes. // Called recursively on valuetypes and on members of // structs, unions, sequences, typedefs and arrays. Returns // TRUE otherwise. if (!f->field_type ()->legal_for_primary_key ()) { retval = false; break; } has_public_member = true; } } this->recursing_in_legal_pk_ = false; } // Must have at least one public member, unless we are // short-circuiting the test because we are in recursion. return retval && (has_public_member || this->recursing_in_legal_pk_); } void AST_ValueType::destroy () { this->AST_Interface::destroy (); delete [] this->pd_supports; this->pd_supports = nullptr; this->pd_n_supports = 0; } void AST_ValueType::dump (ACE_OSTREAM_TYPE &o) { if (this->is_abstract ()) { this->dump_i (o, "abstract "); } else if (this->pd_truncatable) { this->dump_i (o, "truncatable "); } this->dump_i (o, "valuetype "); this->local_name ()->dump (o); this->dump_i (o, " "); if (this->pd_n_inherits > 0) { this->dump_i (o, ": "); for (long i = 0; i < this->pd_n_inherits; ++i) { this->pd_inherits[i]->local_name ()->dump (o); if (i < this->pd_n_inherits - 1) { this->dump_i (o, ", "); } } } this->dump_i (o, "\n\n"); if (this->pd_n_supports > 0) { this->dump_i (o, "supports "); for (long i = 0; i < this->pd_n_supports; ++i) { this->pd_supports[i]->local_name ()->dump (o); if (i < this->pd_n_supports - 1) { this->dump_i (o, ", "); } } } this->dump_i (o, " {\n"); UTL_Scope::dump (o); idl_global->indent ()->skip_to (o); this->dump_i (o, "}"); } int AST_ValueType::ast_accept (ast_visitor *visitor) { return visitor->visit_valuetype (this); } AST_Field * AST_ValueType::fe_add_field (AST_Field *t) { return this->fe_add_ref_decl (t); } AST_Factory * AST_ValueType::fe_add_factory (AST_Factory *f) { return dynamic_cast (this->fe_add_decl (f)); } bool AST_ValueType::derived_from_primary_key_base (const AST_ValueType *node, const AST_ValueType *pk_base) const { if (nullptr == node) { return false; } if (node == pk_base) { return true; } AST_ValueType *concrete_parent = dynamic_cast (node->inherits_concrete ()); if (this->derived_from_primary_key_base (concrete_parent, pk_base)) { return true; } AST_Type **v = node->pd_inherits; for (long i = 0; i < node->pd_n_inherits; ++i) { AST_ValueType *tmp = dynamic_cast (v[i]); if (this->derived_from_primary_key_base (tmp, pk_base)) { return true; } } return false; } AST_ValueType * AST_ValueType::lookup_primary_key_base () const { AST_ValueType *retval = idl_global->primary_key_base (); if (retval == nullptr) { Identifier local_id ("PrimaryKeyBase"); UTL_ScopedName local_name (&local_id, nullptr); Identifier scope_name ("Components"); UTL_ScopedName pk_name (&scope_name, &local_name); AST_Decl *d = const_cast (this)->lookup_by_name (&pk_name, true); local_id.destroy (); scope_name.destroy (); if (d == nullptr) { idl_global->err ()->lookup_error (&pk_name); return nullptr; } retval = dynamic_cast (d); if (retval == nullptr) { idl_global->err ()->valuetype_expected (d); return nullptr; } idl_global->primary_key_base (retval); } return retval; }