/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /* cppcodemarker.cpp */ #include "atom.h" #include "cppcodemarker.h" #include "node.h" #include "text.h" #include "tree.h" #include #include QT_BEGIN_NAMESPACE /*! The constructor does nothing. */ CppCodeMarker::CppCodeMarker() { // nothing. } /*! The destructor does nothing. */ CppCodeMarker::~CppCodeMarker() { // nothing. } /*! Returns true. */ bool CppCodeMarker::recognizeCode(const QString & /* code */) { return true; } /*! Returns true if \a ext is any of a list of file extensions for the C++ language. */ bool CppCodeMarker::recognizeExtension(const QString& extension) { QByteArray ext = extension.toLatin1(); return ext == "c" || ext == "c++" || ext == "qdoc" || ext == "qtt" || ext == "qtx" || ext == "cc" || ext == "cpp" || ext == "cxx" || ext == "ch" || ext == "h" || ext == "h++" || ext == "hh" || ext == "hpp" || ext == "hxx"; } /*! Returns true if \a lang is either "C" or "Cpp". */ bool CppCodeMarker::recognizeLanguage(const QString &lang) { return lang == QLatin1String("C") || lang == QLatin1String("Cpp"); } /*! Returns the type of atom used to represent C++ code in the documentation. */ Atom::Type CppCodeMarker::atomType() const { return Atom::Code; } QString CppCodeMarker::markedUpCode(const QString &code, const Node *relative, const Location &location) { return addMarkUp(code, relative, location); } QString CppCodeMarker::markedUpSynopsis(const Node *node, const Node * /* relative */, SynopsisStyle style) { const int MaxEnumValues = 6; const FunctionNode *func; const PropertyNode *property; const VariableNode *variable; const EnumNode *enume; const TypedefNode *typedeff; QString synopsis; QString extra; QString name; name = taggedNode(node); if (style != Detailed) name = linkTag(node, name); name = "<@name>" + name + ""; if (style == Detailed && !node->parent()->name().isEmpty() && node->type() != Node::Property) name.prepend(taggedNode(node->parent()) + "::"); switch (node->type()) { case Node::Namespace: synopsis = "namespace " + name; break; case Node::Class: synopsis = "class " + name; break; case Node::Function: case Node::QmlSignal: case Node::QmlSignalHandler: case Node::QmlMethod: func = (const FunctionNode *) node; if (style != Subpage && !func->returnType().isEmpty()) synopsis = typified(func->returnType()) + QLatin1Char(' '); synopsis += name; if (func->metaness() != FunctionNode::MacroWithoutParams) { synopsis += "("; if (!func->parameters().isEmpty()) { //synopsis += QLatin1Char(' '); QList::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; synopsis += typified((*p).leftType()); if (style != Subpage && !(*p).name().isEmpty()) synopsis += "<@param>" + protect((*p).name()) + ""; synopsis += protect((*p).rightType()); if (style != Subpage && !(*p).defaultValue().isEmpty()) synopsis += " = " + protect((*p).defaultValue()); ++p; } //synopsis += QLatin1Char(' '); } synopsis += QLatin1Char(')'); } if (func->isConst()) synopsis += " const"; if (style == Summary || style == Accessors) { if (func->virtualness() != FunctionNode::NonVirtual) synopsis.prepend("virtual "); if (func->virtualness() == FunctionNode::PureVirtual) synopsis.append(" = 0"); } else if (style == Subpage) { if (!func->returnType().isEmpty() && func->returnType() != "void") synopsis += " : " + typified(func->returnType()); } else { QStringList bracketed; if (func->isStatic()) { bracketed += "static"; } else if (func->virtualness() != FunctionNode::NonVirtual) { if (func->virtualness() == FunctionNode::PureVirtual) bracketed += "pure"; bracketed += "virtual"; } if (func->access() == Node::Protected) { bracketed += "protected"; } else if (func->access() == Node::Private) { bracketed += "private"; } if (func->metaness() == FunctionNode::Signal) { bracketed += "signal"; } else if (func->metaness() == FunctionNode::Slot) { bracketed += "slot"; } if (!bracketed.isEmpty()) extra += " [" + bracketed.join(" ") + QLatin1Char(']'); } break; case Node::Enum: enume = static_cast(node); synopsis = "enum " + name; if (style == Summary) { synopsis += " { "; QStringList documentedItems = enume->doc().enumItemNames(); if (documentedItems.isEmpty()) { foreach (const EnumItem &item, enume->items()) documentedItems << item.name(); } QStringList omitItems = enume->doc().omitEnumItemNames(); foreach (const QString &item, omitItems) documentedItems.removeAll(item); if (documentedItems.size() <= MaxEnumValues) { for (int i = 0; i < documentedItems.size(); ++i) { if (i != 0) synopsis += ", "; synopsis += documentedItems.at(i); } } else { for (int i = 0; i < documentedItems.size(); ++i) { if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { if (i != 0) synopsis += ", "; synopsis += documentedItems.at(i); } else if (i == MaxEnumValues - 1) { synopsis += ", ..."; } } } if (!documentedItems.isEmpty()) synopsis += QLatin1Char(' '); synopsis += QLatin1Char('}'); } break; case Node::Typedef: typedeff = static_cast(node); if (typedeff->associatedEnum()) { synopsis = "flags " + name; } else { synopsis = "typedef " + name; } break; case Node::Property: property = static_cast(node); synopsis = name + " : " + typified(property->qualifiedDataType()); break; case Node::Variable: variable = static_cast(node); if (style == Subpage) { synopsis = name + " : " + typified(variable->dataType()); } else { synopsis = typified(variable->leftType()) + QLatin1Char(' ') + name + protect(variable->rightType()); } break; default: synopsis = name; } if (style == Summary) { if (node->status() == Node::Preliminary) { extra += " (preliminary)"; } else if (node->status() == Node::Deprecated) { extra += " (deprecated)"; } else if (node->status() == Node::Obsolete) { extra += " (obsolete)"; } } if (!extra.isEmpty()) { extra.prepend("<@extra>"); extra.append(""); } return synopsis + extra; } /*! */ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) { QString name = taggedQmlNode(node); if (summary) name = linkTag(node,name); else if (node->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(node); if (pn->isAttached()) name.prepend(pn->element() + QLatin1Char('.')); } name = "<@name>" + name + ""; QString synopsis; if (node->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(node); synopsis = name + " : " + typified(pn->dataType()); } else if ((node->type() == Node::QmlMethod) || (node->type() == Node::QmlSignal) || (node->type() == Node::QmlSignalHandler)) { const FunctionNode* func = static_cast(node); if (!func->returnType().isEmpty()) synopsis = typified(func->returnType()) + QLatin1Char(' ') + name; else synopsis = name; synopsis += QLatin1Char('('); if (!func->parameters().isEmpty()) { QList::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; synopsis += typified((*p).leftType()); if (!(*p).name().isEmpty()) { if (!synopsis.endsWith(QLatin1Char('('))) synopsis += QLatin1Char(' '); synopsis += "<@param>" + protect((*p).name()) + ""; } synopsis += protect((*p).rightType()); ++p; } } synopsis += QLatin1Char(')'); } else synopsis = name; QString extra; if (summary) { if (node->status() == Node::Preliminary) { extra += " (preliminary)"; } else if (node->status() == Node::Deprecated) { extra += " (deprecated)"; } else if (node->status() == Node::Obsolete) { extra += " (obsolete)"; } } if (!extra.isEmpty()) { extra.prepend("<@extra>"); extra.append(""); } return synopsis + extra; } QString CppCodeMarker::markedUpName(const Node *node) { QString name = linkTag(node, taggedNode(node)); if (node->type() == Node::Function) name += "()"; return name; } QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative) { if (node->name().isEmpty()) { return "global"; } else { QString fullName; for (;;) { fullName.prepend(markedUpName(node)); if (node->parent() == relative || node->parent()->name().isEmpty()) break; fullName.prepend("<@op>::"); node = node->parent(); } return fullName; } } QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, const Node *relative) { const Node *node = relative->parent(); QString fullName; while (node->parent()) { fullName.prepend(markedUpName(node)); if (node->parent() == relative || node->parent()->name().isEmpty() || node->parent()->isCollisionNode()) break; fullName.prepend("<@op>::"); node = node->parent(); } if (!fullName.isEmpty()) fullName.append("<@op>::"); fullName.append(enumValue); return fullName; } QString CppCodeMarker::markedUpIncludes(const QStringList& includes) { QString code; QStringList::ConstIterator inc = includes.constBegin(); while (inc != includes.constEnd()) { code += "<@preprocessor>#include <<@headerfile>" + *inc + ">\n"; ++inc; } return code; } QString CppCodeMarker::functionBeginRegExp(const QString& funcName) { return QLatin1Char('^') + QRegExp::escape(funcName) + QLatin1Char('$'); } QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) { return "^\\}$"; } QList
CppCodeMarker::sections(const InnerNode *inner, SynopsisStyle style, Status status) { QList
sections; if (inner->type() == Node::Class) { const ClassNode *classe = static_cast(inner); if (style == Summary) { FastSection privateFunctions(classe, "Private Functions", QString(), "private function", "private functions"); FastSection privateSlots(classe, "Private Slots", QString(), "private slot", "private slots"); FastSection privateTypes(classe, "Private Types", QString(), "private type", "private types"); FastSection protectedFunctions(classe, "Protected Functions", QString(), "protected function", "protected functions"); FastSection protectedSlots(classe, "Protected Slots", QString(), "protected slot", "protected slots"); FastSection protectedTypes(classe, "Protected Types", QString(), "protected type", "protected types"); FastSection protectedVariables(classe, "Protected Variables", QString(), "protected type", "protected variables"); FastSection publicFunctions(classe, "Public Functions", QString(), "public function", "public functions"); FastSection publicSignals(classe, "Signals", QString(), "signal", "signal"); FastSection publicSlots(classe, "Public Slots", QString(), "public slot", "public slots"); FastSection publicTypes(classe, "Public Types", QString(), "public type", "public types"); FastSection publicVariables(classe, "Public Variables", QString(), "public variable", "public variables"); FastSection properties(classe, "Properties", QString(), "property", "properties"); FastSection relatedNonMembers(classe, "Related Non-Members", QString(), "related non-member", "related non-members"); FastSection staticPrivateMembers(classe, "Static Private Members", QString(), "static private member", "static private members"); FastSection staticProtectedMembers(classe, "Static Protected Members", QString(), "static protected member", "static protected members"); FastSection staticPublicMembers(classe, "Static Public Members", QString(), "static public member", "static public members"); FastSection macros(inner, "Macros", QString(), "macro", "macros"); NodeList::ConstIterator r = classe->relatedNodes().constBegin(); while (r != classe->relatedNodes().constEnd()) { if ((*r)->type() == Node::Function) { FunctionNode *func = static_cast(*r); if (func->isMacro()) insert(macros, *r, style, status); else insert(relatedNonMembers, *r, style, status); } else { insert(relatedNonMembers, *r, style, status); } ++r; } QStack stack; stack.push(classe); while (!stack.isEmpty()) { const ClassNode *ancestorClass = stack.pop(); NodeList::ConstIterator c = ancestorClass->childNodes().constBegin(); while (c != ancestorClass->childNodes().constEnd()) { bool isSlot = false; bool isSignal = false; bool isStatic = false; if ((*c)->type() == Node::Function) { const FunctionNode *func = (const FunctionNode *) *c; isSlot = (func->metaness() == FunctionNode::Slot); isSignal = (func->metaness() == FunctionNode::Signal); isStatic = func->isStatic(); if (func->associatedProperty()) { if (func->associatedProperty()->status() == Node::Obsolete) { ++c; continue; } } } else if ((*c)->type() == Node::Variable) { const VariableNode *var = static_cast(*c); isStatic = var->isStatic(); } switch ((*c)->access()) { case Node::Public: if (isSlot) { insert(publicSlots, *c, style, status); } else if (isSignal) { insert(publicSignals, *c, style, status); } else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) insert(staticPublicMembers,*c,style,status); } else if ((*c)->type() == Node::Property) { insert(properties, *c, style, status); } else if ((*c)->type() == Node::Variable) { if (!(*c)->doc().isEmpty()) insert(publicVariables, *c, style, status); } else if ((*c)->type() == Node::Function) { if (!insertReimpFunc(publicFunctions,*c,status)) insert(publicFunctions, *c, style, status); } else { insert(publicTypes, *c, style, status); } break; case Node::Protected: if (isSlot) { insert(protectedSlots, *c, style, status); } else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) insert(staticProtectedMembers,*c,style,status); } else if ((*c)->type() == Node::Variable) { if (!(*c)->doc().isEmpty()) insert(protectedVariables,*c,style,status); } else if ((*c)->type() == Node::Function) { if (!insertReimpFunc(protectedFunctions,*c,status)) insert(protectedFunctions, *c, style, status); } else { insert(protectedTypes, *c, style, status); } break; case Node::Private: if (isSlot) { insert(privateSlots, *c, style, status); } else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) insert(staticPrivateMembers,*c,style,status); } else if ((*c)->type() == Node::Function) { if (!insertReimpFunc(privateFunctions,*c,status)) insert(privateFunctions, *c, style, status); } else { insert(privateTypes,*c,style,status); } } ++c; } QList::ConstIterator r = ancestorClass->baseClasses().constBegin(); while (r != ancestorClass->baseClasses().constEnd()) { stack.prepend((*r).node); ++r; } } append(sections, publicTypes); append(sections, properties); append(sections, publicFunctions); append(sections, publicSlots); append(sections, publicSignals); append(sections, publicVariables); append(sections, staticPublicMembers); append(sections, protectedTypes); append(sections, protectedFunctions); append(sections, protectedSlots); append(sections, protectedVariables); append(sections, staticProtectedMembers); append(sections, privateTypes); append(sections, privateFunctions); append(sections, privateSlots); append(sections, staticPrivateMembers); append(sections, relatedNonMembers); append(sections, macros); } else if (style == Detailed) { FastSection memberFunctions(classe,"Member Function Documentation","func","member","members"); FastSection memberTypes(classe,"Member Type Documentation","types","member","members"); FastSection memberVariables(classe,"Member Variable Documentation","vars","member","members"); FastSection properties(classe,"Property Documentation","prop","member","members"); FastSection relatedNonMembers(classe,"Related Non-Members","relnonmem","member","members"); FastSection macros(classe,"Macro Documentation","macros","member","members"); NodeList::ConstIterator r = classe->relatedNodes().constBegin(); while (r != classe->relatedNodes().constEnd()) { if ((*r)->type() == Node::Function) { FunctionNode *func = static_cast(*r); if (func->isMacro()) insert(macros, *r, style, status); else insert(relatedNonMembers, *r, style, status); } else { insert(relatedNonMembers, *r, style, status); } ++r; } NodeList::ConstIterator c = classe->childNodes().constBegin(); while (c != classe->childNodes().constEnd()) { if ((*c)->type() == Node::Enum || (*c)->type() == Node::Typedef) { insert(memberTypes, *c, style, status); } else if ((*c)->type() == Node::Property) { insert(properties, *c, style, status); } else if ((*c)->type() == Node::Variable) { if (!(*c)->doc().isEmpty()) insert(memberVariables, *c, style, status); } else if ((*c)->type() == Node::Function) { FunctionNode *function = static_cast(*c); if (!function->associatedProperty()) insert(memberFunctions, function, style, status); } ++c; } append(sections, memberTypes); append(sections, properties); append(sections, memberFunctions); append(sections, memberVariables); append(sections, relatedNonMembers); append(sections, macros); } else { FastSection all(classe,QString(),QString(),"member","members"); QStack stack; stack.push(classe); while (!stack.isEmpty()) { const ClassNode *ancestorClass = stack.pop(); NodeList::ConstIterator c = ancestorClass->childNodes().constBegin(); while (c != ancestorClass->childNodes().constEnd()) { if ((*c)->access() != Node::Private && (*c)->type() != Node::Property) insert(all, *c, style, status); ++c; } QList::ConstIterator r = ancestorClass->baseClasses().constBegin(); while (r != ancestorClass->baseClasses().constEnd()) { stack.prepend((*r).node); ++r; } } append(sections, all); } } else { if (style == Summary || style == Detailed) { FastSection namespaces(inner, "Namespaces", style == Detailed ? "nmspace" : QString(), "namespace", "namespaces"); FastSection classes(inner, "Classes", style == Detailed ? "classes" : QString(), "class", "classes"); FastSection types(inner, style == Summary ? "Types" : "Type Documentation", style == Detailed ? "types" : QString(), "type", "types"); FastSection functions(inner, style == Summary ? "Functions" : "Function Documentation", style == Detailed ? "func" : QString(), "function", "functions"); FastSection macros(inner, style == Summary ? "Macros" : "Macro Documentation", style == Detailed ? "macros" : QString(), "macro", "macros"); NodeList nodeList = inner->childNodes(); nodeList += inner->relatedNodes(); NodeList::ConstIterator n = nodeList.constBegin(); while (n != nodeList.constEnd()) { switch ((*n)->type()) { case Node::Namespace: insert(namespaces, *n, style, status); break; case Node::Class: insert(classes, *n, style, status); break; case Node::Enum: case Node::Typedef: insert(types, *n, style, status); break; case Node::Function: { FunctionNode *func = static_cast(*n); if (func->isMacro()) insert(macros, *n, style, status); else insert(functions, *n, style, status); } break; default: ; } ++n; } append(sections, namespaces); append(sections, classes); append(sections, types); append(sections, functions); append(sections, macros); } } return sections; } static const char * const typeTable[] = { "bool", "char", "double", "float", "int", "long", "short", "signed", "unsigned", "uint", "ulong", "ushort", "uchar", "void", "qlonglong", "qulonglong", "qint", "qint8", "qint16", "qint32", "qint64", "quint", "quint8", "quint16", "quint32", "quint64", "qreal", "cond", 0 }; static const char * const keywordTable[] = { "and", "and_eq", "asm", "auto", "bitand", "bitor", "break", "case", "catch", "class", "compl", "const", "const_cast", "continue", "default", "delete", "do", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "for", "friend", "goto", "if", "include", "inline", "monitor", "mutable", "namespace", "new", "not", "not_eq", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "sizeof", "static", "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", "typedef", "typeid", "typename", "union", "using", "virtual", "volatile", "wchar_t", "while", "xor", "xor_eq", "synchronized", // Qt specific "signals", "slots", "emit", 0 }; /* @char @class @comment @function @keyword @number @op @preprocessor @string @type */ QString CppCodeMarker::addMarkUp(const QString &in, const Node * /* relative */, const Location & /* location */) { #define readChar() \ ch = (i < (int)code.length()) ? code[i++].cell() : EOF QString code = in; QMap types; QMap keywords; int j = 0; while (typeTable[j] != 0) { types.insert(QString(typeTable[j]), 0); j++; } j = 0; while (keywordTable[j] != 0) { keywords.insert(QString(keywordTable[j]), 0); j++; } QString out; int braceDepth = 0; int parenDepth = 0; int i = 0; int start = 0; int finish = 0; QChar ch; QRegExp classRegExp("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)"); QRegExp functionRegExp("q([A-Z][a-z]+)+"); readChar(); while (ch != EOF) { QString tag; bool target = false; if (ch.isLetter() || ch == '_') { QString ident; do { ident += ch; finish = i; readChar(); } while (ch.isLetterOrNumber() || ch == '_'); if (classRegExp.exactMatch(ident)) { tag = QLatin1String("type"); } else if (functionRegExp.exactMatch(ident)) { tag = QLatin1String("func"); target = true; } else if (types.contains(ident)) { tag = QLatin1String("type"); } else if (keywords.contains(ident)) { tag = QLatin1String("keyword"); } else if (braceDepth == 0 && parenDepth == 0) { if (QString(code.unicode() + i - 1, code.length() - (i - 1)) .indexOf(QRegExp(QLatin1String("^\\s*\\("))) == 0) tag = QLatin1String("func"); target = true; } } else if (ch.isDigit()) { do { finish = i; readChar(); } while (ch.isLetterOrNumber() || ch == '.'); tag = QLatin1String("number"); } else { switch (ch.unicode()) { case '+': case '-': case '!': case '%': case '^': case '&': case '*': case ',': case '.': case '<': case '=': case '>': case '?': case '[': case ']': case '|': case '~': finish = i; readChar(); tag = QLatin1String("op"); break; case '"': finish = i; readChar(); while (ch != EOF && ch != '"') { if (ch == '\\') readChar(); readChar(); } finish = i; readChar(); tag = QLatin1String("string"); break; case '#': finish = i; readChar(); while (ch != EOF && ch != '\n') { if (ch == '\\') readChar(); finish = i; readChar(); } tag = QLatin1String("preprocessor"); break; case '\'': finish = i; readChar(); while (ch != EOF && ch != '\'') { if (ch == '\\') readChar(); readChar(); } finish = i; readChar(); tag = QLatin1String("char"); break; case '(': finish = i; readChar(); parenDepth++; break; case ')': finish = i; readChar(); parenDepth--; break; case ':': finish = i; readChar(); if (ch == ':') { finish = i; readChar(); tag = QLatin1String("op"); } break; case '/': finish = i; readChar(); if (ch == '/') { do { finish = i; readChar(); } while (ch != EOF && ch != '\n'); tag = QLatin1String("comment"); } else if (ch == '*') { bool metAster = false; bool metAsterSlash = false; finish = i; readChar(); while (!metAsterSlash) { if (ch == EOF) break; if (ch == '*') metAster = true; else if (metAster && ch == '/') metAsterSlash = true; else metAster = false; finish = i; readChar(); } tag = QLatin1String("comment"); } else { tag = QLatin1String("op"); } break; case '{': finish = i; readChar(); braceDepth++; break; case '}': finish = i; readChar(); braceDepth--; break; default: finish = i; readChar(); } } QString text; text = code.mid(start, finish - start); start = finish; if (!tag.isEmpty()) { out += QLatin1String("<@") + tag; if (target) out += QLatin1String(" target=\"") + text + QLatin1String("()\""); out += QLatin1Char('>'); } out += protect(text); if (!tag.isEmpty()) out += QLatin1String("'); } if (start < code.length()) { out += protect(code.mid(start)); } return out; } /*! This function is for documenting QML properties. It returns the list of documentation sections for the children of the \a qmlClassNode. */ QList
CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, SynopsisStyle style) { QList
sections; if (qmlClassNode) { if (style == Summary) { FastSection qmlproperties(qmlClassNode, "Properties", QString(), "property", "properties"); FastSection qmlattachedproperties(qmlClassNode, "Attached Properties", QString(), "property", "properties"); FastSection qmlsignals(qmlClassNode, "Signals", QString(), "signal", "signals"); FastSection qmlsignalhandlers(qmlClassNode, "Signal Handlers", QString(), "signal handler", "signal handlers"); FastSection qmlattachedsignals(qmlClassNode, "Attached Signals", QString(), "signal", "signals"); FastSection qmlmethods(qmlClassNode, "Methods", QString(), "method", "methods"); FastSection qmlattachedmethods(qmlClassNode, "Attached Methods", QString(), "method", "methods"); const QmlClassNode* qcn = qmlClassNode; while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { if ((*c)->subType() == Node::QmlPropertyGroup) { const QmlPropGroupNode* qpgn = static_cast(*c); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(*p); if (pn->isAttached()) insert(qmlattachedproperties,*p,style,Okay); else insert(qmlproperties,*p,style,Okay); } ++p; } } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(*c); if (pn->qmlPropNodes().isEmpty()) { if (pn->isAttached()) insert(qmlattachedproperties,*c,style,Okay); else insert(qmlproperties,*c,style,Okay); } else { NodeList::ConstIterator p = pn->qmlPropNodes().constBegin(); while (p != pn->qmlPropNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(*p); if (pn->isAttached()) insert(qmlattachedproperties,*p,style,Okay); else insert(qmlproperties,*p,style,Okay); } ++p; } } } else if ((*c)->type() == Node::QmlSignal) { const FunctionNode* sn = static_cast(*c); if (sn->isAttached()) insert(qmlattachedsignals,*c,style,Okay); else insert(qmlsignals,*c,style,Okay); } else if ((*c)->type() == Node::QmlSignalHandler) { insert(qmlsignalhandlers,*c,style,Okay); } else if ((*c)->type() == Node::QmlMethod) { const FunctionNode* mn = static_cast(*c); if (mn->isAttached()) insert(qmlattachedmethods,*c,style,Okay); else insert(qmlmethods,*c,style,Okay); } ++c; } if (qcn->qmlBase() != 0) { qcn = static_cast(qcn->qmlBase()); if (!qcn->isAbstract()) qcn = 0; } else qcn = 0; } append(sections,qmlproperties); append(sections,qmlattachedproperties); append(sections,qmlsignals); append(sections,qmlsignalhandlers); append(sections,qmlattachedsignals); append(sections,qmlmethods); append(sections,qmlattachedmethods); } else if (style == Detailed) { FastSection qmlproperties(qmlClassNode, "Property Documentation","qmlprop","member","members"); FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation","qmlattprop", "member","members"); FastSection qmlsignals(qmlClassNode,"Signal Documentation","qmlsig","signal","signals"); FastSection qmlsignalhandlers(qmlClassNode,"Signal Handler Documentation","qmlsighan","signal handler","signal handlers"); FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation","qmlattsig", "signal","signals"); FastSection qmlmethods(qmlClassNode,"Method Documentation","qmlmeth","member","members"); FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation","qmlattmeth", "member","members"); const QmlClassNode* qcn = qmlClassNode; while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { if ((*c)->subType() == Node::QmlPropertyGroup) { bool attached = false; const QmlPropGroupNode* pgn = static_cast(*c); NodeList::ConstIterator C = pgn->childNodes().constBegin(); while (C != pgn->childNodes().constEnd()) { if ((*C)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(*C); if (pn->isAttached()) { attached = true; break; } } ++C; } if (attached) insert(qmlattachedproperties,*c,style,Okay); else insert(qmlproperties,*c,style,Okay); } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast(*c); if (pn->isAttached()) insert(qmlattachedproperties,*c,style,Okay); else insert(qmlproperties,*c,style,Okay); } else if ((*c)->type() == Node::QmlSignal) { const FunctionNode* sn = static_cast(*c); if (sn->isAttached()) insert(qmlattachedsignals,*c,style,Okay); else insert(qmlsignals,*c,style,Okay); } else if ((*c)->type() == Node::QmlSignalHandler) { insert(qmlsignalhandlers,*c,style,Okay); } else if ((*c)->type() == Node::QmlMethod) { const FunctionNode* mn = static_cast(*c); if (mn->isAttached()) insert(qmlattachedmethods,*c,style,Okay); else insert(qmlmethods,*c,style,Okay); } ++c; } if (qcn->qmlBase() != 0) { qcn = static_cast(qcn->qmlBase()); if (!qcn->isAbstract()) qcn = 0; } else qcn = 0; } append(sections,qmlproperties); append(sections,qmlattachedproperties); append(sections,qmlsignals); append(sections,qmlsignalhandlers); append(sections,qmlattachedsignals); append(sections,qmlmethods); append(sections,qmlattachedmethods); } else { FastSection all(qmlClassNode,QString(),QString(),"member","members"); const QmlClassNode* current = qmlClassNode; while (current != 0) { NodeList::ConstIterator c = current->childNodes().constBegin(); while (c != current->childNodes().constEnd()) { if ((*c)->subType() == Node::QmlPropertyGroup) { const QmlPropGroupNode* qpgn = static_cast(*c); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { QString key = current->name() + "::" + (*p)->name(); key = sortName(*p, &key); if (!all.memberMap.contains(key)) all.memberMap.insert(key,*p); //insert(all,*p,style,Okay); } ++p; } } else { QString key = current->name() + "::" + (*c)->name(); key = sortName(*c, &key); if (!all.memberMap.contains(key)) all.memberMap.insert(key,*c); //insert(all,*c,style,Okay); } ++c; } const DocNode* dn = current->qmlBase(); if (dn) { if (dn->subType() == Node::QmlClass) current = static_cast(dn); else { dn->doc().location().warning(tr("Base class of QML class '%1' is ambgiguous").arg(current->name())); current = 0; } } else current = 0; } append(sections, all, true); } } return sections; } QT_END_NAMESPACE