void openScopes(Entry * object)
    {
        int cur_scope_separator_pos = 0;
        int last_scope_separator_pos = 0;
        while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos)))
        {
            QString scope = object->name.mid(last_scope_separator_pos,
                                             cur_scope_separator_pos - last_scope_separator_pos);
            last_scope_separator_pos = cur_scope_separator_pos + 2;

            Entry * current_namespace = openNamespace(scope);

            if (!m_scopeStack.isEmpty())
            { m_scopeStack.last()->scope->addSubEntry(current_namespace); }

            m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount));
        }

        QCString scoped_name(getCurrentScope());
        if (!scoped_name.isEmpty())
        { scoped_name.append("::"); }
        scoped_name.append(object->name.mid(last_scope_separator_pos));

        object->name = scoped_name;

        if (!m_scopeStack.isEmpty())
        { m_scopeStack.last()->scope->addSubEntry(object); }
        m_scopeStack.append(new ScopeData(object, m_scopeCount));

        ++m_scopeCount;
    }
    void addNamedType(const QCString &type)
    {
        QCString scoped_name(getCurrentScope());

        if (m_namedTypeMap.contains(scoped_name))
        {
            DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name));
            return;
        }

        m_namedTypeMap.insert(scoped_name, type);
    }
    Entry * openNamespace(const QString & name)
    {
        Entry * current_namespace = createEntry();
        QCString scoped_name(getCurrentScope());
        if (!scoped_name.isEmpty())
        { scoped_name.append("::"); }
        scoped_name.append(name.utf8());
        current_namespace->name = scoped_name;
        current_namespace->section = Entry::NAMESPACE_SEC;
        current_namespace->type = "namespace" ;

        return current_namespace;
    }
Beispiel #4
0
void
FE_Utils::create_uses_multiple_stuff (AST_Component *c,
                                      AST_Uses *u,
                                      const char *prefix)
{
  ACE_CString struct_name (prefix);

  if (!struct_name.empty ())
    {
      struct_name += '_';
    }

  struct_name += u->local_name ()->get_string ();
  struct_name += "Connection";
  Identifier struct_id (struct_name.c_str ());
  UTL_ScopedName sn (&struct_id, 0);

  // In case this call comes from the backend. We
  // will pop the scope before returning.
  idl_global->scopes ().push (c);

  AST_Structure *connection =
    idl_global->gen ()->create_structure (&sn, 0, 0);

  struct_id.destroy ();

  /// If the field type is a param holder, we want
  /// to use the lookup to create a fresh one,
  /// since the field will own it and destroy it.
  UTL_ScopedName *fn = u->uses_type ()->name ();
  AST_Decl *d =
    idl_global->root ()->lookup_by_name (fn, true, false);
  AST_Type *ft = AST_Type::narrow_from_decl (d);

  Identifier object_id ("objref");
  UTL_ScopedName object_name (&object_id,
                              0);
  AST_Field *object_field =
    idl_global->gen ()->create_field (ft,
                                      &object_name,
                                      AST_Field::vis_NA);
  (void) DeclAsScope (connection)->fe_add_field (object_field);
  object_id.destroy ();

  Identifier local_id ("Cookie");
  UTL_ScopedName local_name (&local_id,
                             0);
  Identifier module_id ("Components");
  UTL_ScopedName scoped_name (&module_id,
                              &local_name);

  d = c->lookup_by_name (&scoped_name, true);
  local_id.destroy ();
  module_id.destroy ();

  if (d == 0)
    {
      // This would happen if we haven't included Components.idl.
      idl_global->err ()->lookup_error (&scoped_name);
      return;
    }

  AST_ValueType *cookie = AST_ValueType::narrow_from_decl (d);

  Identifier cookie_id ("ck");
  UTL_ScopedName cookie_name (&cookie_id,
                              0);
  AST_Field *cookie_field =
    idl_global->gen ()->create_field (cookie,
                                      &cookie_name,
                                      AST_Field::vis_NA);
  (void) DeclAsScope (connection)->fe_add_field (cookie_field);
  cookie_id.destroy ();

  (void) c->fe_add_structure (connection);

  ACE_CDR::ULong bound = 0;
  AST_Expression *bound_expr =
    idl_global->gen ()->create_expr (bound,
                                     AST_Expression::EV_ulong);
  AST_Sequence *sequence =
    idl_global->gen ()->create_sequence (bound_expr,
                                         connection,
                                         0,
                                         0,
                                         0);

  ACE_CString seq_string (struct_name);
  seq_string += 's';
  Identifier seq_id (seq_string.c_str ());
  UTL_ScopedName seq_name (&seq_id,
                           0);
  AST_Typedef *connections =
    idl_global->gen ()->create_typedef (sequence,
                                        &seq_name,
                                        0,
                                        0);
  seq_id.destroy ();

  (void) c->fe_add_typedef (connections);

  // In case this call comes from the backend.
  idl_global->scopes ().pop ();
}
Beispiel #5
0
// Create a dynamic meta-object for a Python type by introspecting its
// attributes.  Note that it leaks if the type is deleted.
static int create_dynamic_metaobject(pyqtWrapperType *pyqt_wt)
{
    PyTypeObject *pytype = (PyTypeObject *)pyqt_wt;
    qpycore_metaobject *qo = new qpycore_metaobject;
    QMetaObjectBuilder builder;

    // Get any class info.
    QList<ClassInfo> class_info_list = qpycore_get_class_info_list();

    // Get any enums/flags.
    QList<EnumsFlags> enums_flags_list = qpycore_get_enums_flags_list();

    // Get the super-type's meta-object.
    builder.setSuperClass(get_qmetaobject((pyqtWrapperType *)pytype->tp_base));

    // Get the name of the type.  Dynamic types have simple names.
    builder.setClassName(pytype->tp_name);

    // Go through the class hierarchy getting all PyQt properties, slots and
    // signals.

    QList<const qpycore_pyqtSignal *> psigs;
    QMap<uint, PropertyData> pprops;

    if (trawl_hierarchy(pytype, qo, builder, psigs, pprops) < 0)
        return -1;

    qo->nr_signals = psigs.count();

    // Initialise the header section of the data table.  Note that Qt v4.5
    // introduced revision 2 which added constructors.  However the design is
    // broken in that the static meta-call function doesn't provide enough
    // information to determine which Python sub-class of a Qt class is to be
    // created.  So we stick with revision 1 (and don't allow pyqtSlot() to
    // decorate __init__).

    // Set up any class information.
    for (int i = 0; i < class_info_list.count(); ++i)
    {
        const ClassInfo &ci = class_info_list.at(i);

        builder.addClassInfo(ci.first, ci.second);
    }

    // Set up any enums/flags.
    for (int i = 0; i < enums_flags_list.count(); ++i)
    {
        const EnumsFlags &ef = enums_flags_list.at(i);

        QByteArray scoped_name(pytype->tp_name);
        scoped_name.append("::");
        scoped_name.append(ef.name);
        QMetaEnumBuilder enum_builder = builder.addEnumerator(scoped_name);

        enum_builder.setIsFlag(ef.isFlag);

        QHash<QByteArray, int>::const_iterator it = ef.keys.constBegin();

        while (it != ef.keys.constEnd())
        {
            enum_builder.addKey(it.key(), it.value());
            ++it;
        }
    }

    // Add the signals to the meta-object.
    for (int g = 0; g < qo->nr_signals; ++g)
    {
        const qpycore_pyqtSignal *ps = psigs.at(g);

        QMetaMethodBuilder signal_builder = builder.addSignal(
                ps->parsed_signature->signature.mid(1));

        if (ps->parameter_names)
            signal_builder.setParameterNames(*ps->parameter_names);

        signal_builder.setRevision(ps->revision);
    }

    // Add the slots to the meta-object.
    for (int s = 0; s < qo->pslots.count(); ++s)
    {
        const Chimera::Signature *slot_signature = qo->pslots.at(s)->slotSignature();
        const QByteArray &sig = slot_signature->signature;

        QMetaMethodBuilder slot_builder = builder.addSlot(sig);

        // Add any type.
        if (slot_signature->result)
            slot_builder.setReturnType(slot_signature->result->name());

        slot_builder.setRevision(slot_signature->revision);
    }

    // Add the properties to the meta-object.
    QMapIterator<uint, PropertyData> it(pprops);

    for (int p = 0; it.hasNext(); ++p)
    {
        it.next();

        const PropertyData &pprop = it.value();
        const char *prop_name = SIPBytes_AS_STRING(pprop.first);
        qpycore_pyqtProperty *pp = (qpycore_pyqtProperty *)pprop.second;
        int notifier_id;

        if (pp->pyqtprop_notify)
        {
            qpycore_pyqtSignal *ps = (qpycore_pyqtSignal *)pp->pyqtprop_notify;
            const QByteArray &sig = ps->parsed_signature->signature;

            notifier_id = builder.indexOfSignal(sig.mid(1));

            if (notifier_id < 0)
            {
                PyErr_Format(PyExc_TypeError,
                        "the notify signal '%s' was not defined in this class",
                        sig.constData() + 1);

                // Note that we leak the property name.
                return -1;
            }
        }
        else
        {
            notifier_id = -1;
        }

        // A Qt v5 revision 7 meta-object holds the QMetaType::Type of the type
        // or its name if it is unresolved (ie. not known to the type system).
        // In Qt v4 both are held.  For QObject sub-classes Chimera will fall
        // back to the QMetaType::QObjectStar if there is no specific meta-type
        // for the sub-class.  This means that, for Qt v4,
        // QMetaProperty::read() can handle the type.  However, Qt v5 doesn't
        // know that the unresolved type is a QObject sub-class.  Therefore we
        // have to tell it that the property is a QObject, rather than the
        // sub-class.  This means that QMetaProperty.typeName() will always
        // return "QObject*".
        QByteArray prop_type;

        if (pp->pyqtprop_parsed_type->metatype() == QMetaType::QObjectStar)
        {
            // However, if the type is a Python sub-class of QObject then we
            // use the name of the Python type.  This anticipates that the type
            // is one that will be proxied by QML at some point.
            if (pp->pyqtprop_parsed_type->typeDef() == sipType_QObject)
            {
                prop_type = ((PyTypeObject *)pp->pyqtprop_parsed_type->py_type())->tp_name;
                prop_type.append('*');
            }
            else
            {
                prop_type = "QObject*";
            }
        }
        else
        {
            prop_type = pp->pyqtprop_parsed_type->name();
        }

        QMetaPropertyBuilder prop_builder = builder.addProperty(prop_name,
                prop_type, notifier_id);

        // Reset the defaults.
        prop_builder.setReadable(false);
        prop_builder.setWritable(false);

        // Enum or flag.
        if (pp->pyqtprop_parsed_type->isEnum() || pp->pyqtprop_parsed_type->isFlag())
        {
            prop_builder.setEnumOrFlag(true);
        }

        if (pp->pyqtprop_get && PyCallable_Check(pp->pyqtprop_get))
        {
            // Readable.
            prop_builder.setReadable(true);
        }

        if (pp->pyqtprop_set && PyCallable_Check(pp->pyqtprop_set))
        {
            // Writable.
            prop_builder.setWritable(true);

            // See if the name of the setter follows the Designer convention.
            // If so tell the UI compilers not to use setProperty().
            PyObject *setter_name_obj = PyObject_GetAttr(pp->pyqtprop_set,
                    qpycore_dunder_name);

            if (setter_name_obj)
            {
                PyObject *ascii_obj = setter_name_obj;
                const char *ascii = sipString_AsASCIIString(&ascii_obj);
                Py_DECREF(setter_name_obj);

                if (ascii)
                {
                    if (qstrlen(ascii) > 3 && ascii[0] == 's' &&
                            ascii[1] == 'e' && ascii[2] == 't' &&
                            ascii[3] == toupper(prop_name[0]) &&
                            qstrcmp(&ascii[4], &prop_name[1]) == 0)
                        prop_builder.setStdCppSet(true);
                }

                Py_DECREF(ascii_obj);
            }

            PyErr_Clear();
        }

        if (pp->pyqtprop_reset && PyCallable_Check(pp->pyqtprop_reset))
        {
            // Resetable.
            prop_builder.setResettable(true);
        }

        // Add the property flags.  Note that Qt4 always seems to have
        // ResolveEditable set but QMetaObjectBuilder doesn't provide an API
        // call to do it.
        prop_builder.setDesignable(pp->pyqtprop_flags & 0x00001000);
        prop_builder.setScriptable(pp->pyqtprop_flags & 0x00004000);
        prop_builder.setStored(pp->pyqtprop_flags & 0x00010000);
        prop_builder.setUser(pp->pyqtprop_flags & 0x00100000);
        prop_builder.setConstant(pp->pyqtprop_flags & 0x00000400);
        prop_builder.setFinal(pp->pyqtprop_flags & 0x00000800);

        prop_builder.setRevision(pp->pyqtprop_revision);

        // Save the property data for qt_metacall().  (We already have a
        // reference.)
        qo->pprops.append(pp);

        // We've finished with the property name.
        Py_DECREF(pprop.first);
    }

    // Initialise the rest of the meta-object.
    qo->mo = builder.toMetaObject();

    // Save the meta-object.
    pyqt_wt->metaobject = qo;

    return 0;
}