diff -r 000000000000 -r 1918ee327afb tools/qdoc3/cppcodemarker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/qdoc3/cppcodemarker.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + cppcodemarker.cpp +*/ + +#include +#include "atom.h" +#include "cppcodemarker.h" +#include "node.h" +#include "text.h" +#include "tree.h" + +QT_BEGIN_NAMESPACE + +static int insertTagAround(QString &result, int pos, int len, const QString &tagName, + const QString &attributes = QString()) +{ + QString s; + //s.reserve(result.size() + tagName.size() * 2 + attributes.size() + 20); + s += result.midRef(0, pos); + s += QLatin1Char('<'); + s += tagName; + if (!attributes.isEmpty()) { + s += QLatin1Char(' '); + s += attributes; + } + s += QLatin1Char('>'); + s += result.midRef(pos, len); + s += QLatin1String("'); + s += result.midRef(pos + len); + int diff = s.length() - result.length(); + result = s; + return diff; +} + +/*! + 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& ext) +{ + return ext == "c" || + ext == "c++" || + 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 == "C" || lang == "Cpp"; +} + +/*! + Returns the \a node name, or "()" if \a node is a + Node::Function node. + */ +QString CppCodeMarker::plainName(const Node *node) +{ + QString name = node->name(); + if (node->type() == Node::Function) + name += "()"; + return name; +} + +QString CppCodeMarker::plainFullName(const Node *node, const Node *relative) +{ + if (node->name().isEmpty()) { + return "global"; + } + else { + QString fullName; + for (;;) { + fullName.prepend(plainName(node)); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + fullName.prepend("::"); + node = node->parent(); + } + return fullName; + } +} + +QString CppCodeMarker::markedUpCode(const QString &code, + const Node *relative, + const QString &dirPath) +{ + return addMarkUp(protect(code), relative, dirPath); +} + +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: + func = (const FunctionNode *) node; + if (style != SeparateList && !func->returnType().isEmpty()) + synopsis = typified(func->returnType()) + " "; + synopsis += name; + if (func->metaness() != FunctionNode::MacroWithoutParams) { + synopsis += " ("; + if (!func->parameters().isEmpty()) { + synopsis += " "; + QList::ConstIterator p = func->parameters().begin(); + while (p != func->parameters().end()) { + if (p != func->parameters().begin()) + synopsis += ", "; + synopsis += typified((*p).leftType()); + if (style != SeparateList && !(*p).name().isEmpty()) + synopsis += + " <@param>" + protect((*p).name()) + ""; + synopsis += protect((*p).rightType()); + if (style != SeparateList && !(*p).defaultValue().isEmpty()) + synopsis += " = " + protect((*p).defaultValue()); + ++p; + } + synopsis += " "; + } + synopsis += ")"; + } + 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 == SeparateList) { + 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(" ") + "]"; + } + 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 += " "; + synopsis += "}"; + } + 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 == SeparateList) { + synopsis = name + " : " + typified(variable->dataType()); + } + else { + synopsis = typified(variable->leftType()) + " " + + 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; +} + +#ifdef QDOC_QML +/*! + */ +QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) +{ + QString name = taggedQmlNode(node); + if (summary) { + name = linkTag(node,name); + } + name = "<@name>" + name + ""; + QString synopsis = name; + if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast(node); + synopsis += " : " + typified(pn->dataType()); + } + + 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; +} +#endif + +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()) + 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.begin(); + while (inc != includes.end()) { + code += "#include <<@headerfile>" + *inc + ">\n"; + ++inc; + } + return addMarkUp(code, 0, ""); +} + +QString CppCodeMarker::functionBeginRegExp(const QString& funcName) +{ + return "^" + QRegExp::escape(funcName) + "$"; + +} + +QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) +{ + return "^\\}$"; +} + +#if 0 + FastSection privateReimpFuncs(classe, + "Private Reimplemented Functions", + "private reimplemented function", + "private reimplemented functions"); + FastSection protectedReimpFuncs(classe, + "Protected Reimplemented Functions", + "protected reimplemented function", + "protected reimplemented functions"); + FastSection publicReimpFuncs(classe, + "Public Reimplemented Functions", + "public reimplemented function", + "public reimplemented functions"); +#endif + +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", + "private function", + "private functions"); + FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); + FastSection privateTypes(classe, "Private Types", "private type", "private types"); + FastSection protectedFunctions(classe, + "Protected Functions", + "protected function", + "protected functions"); + FastSection protectedSlots(classe, + "Protected Slots", + "protected slot", + "protected slots"); + FastSection protectedTypes(classe, + "Protected Types", + "protected type", + "protected types"); + FastSection protectedVariables(classe, + "Protected Variables", + "protected type", + "protected variables"); + FastSection publicFunctions(classe, + "Public Functions", + "public function", + "public functions"); + FastSection publicSignals(classe, "Signals", "signal", "signals"); + FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); + FastSection publicTypes(classe, "Public Types", "public type", "public types"); + FastSection publicVariables(classe, + "Public Variables", + "public type", + "public variables"); + FastSection properties(classe, "Properties", "property", "properties"); + FastSection relatedNonMembers(classe, + "Related Non-Members", + "related non-member", + "related non-members"); + FastSection staticPrivateMembers(classe, + "Static Private Members", + "static private member", + "static private members"); + FastSection staticProtectedMembers(classe, + "Static Protected Members", + "static protected member", + "static protected members"); + FastSection staticPublicMembers(classe, + "Static Public Members", + "static public member", + "static public members"); + FastSection macros(inner, "Macros", "macro", "macros"); + + NodeList::ConstIterator r = classe->relatedNodes().begin(); + while (r != classe->relatedNodes().end()) { + 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().begin(); + while (c != ancestorClass->childNodes().end()) { + 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(); + } + 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().begin(); + while (r != ancestorClass->baseClasses().end()) { + 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"); + FastSection memberTypes(classe,"Member Type Documentation"); + FastSection memberVariables(classe,"Member Variable Documentation"); + FastSection properties(classe,"Property Documentation"); + FastSection relatedNonMembers(classe,"Related Non-Members"); + FastSection macros(classe,"Macro Documentation"); + + NodeList::ConstIterator r = classe->relatedNodes().begin(); + while (r != classe->relatedNodes().end()) { + 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().begin(); + while (c != classe->childNodes().end()) { + 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); + + QStack stack; + stack.push(classe); + + while (!stack.isEmpty()) { + const ClassNode *ancestorClass = stack.pop(); + + NodeList::ConstIterator c = ancestorClass->childNodes().begin(); + while (c != ancestorClass->childNodes().end()) { + if ((*c)->access() != Node::Private && + (*c)->type() != Node::Property) + insert(all, *c, style, status); + ++c; + } + + QList::ConstIterator r = + ancestorClass->baseClasses().begin(); + while (r != ancestorClass->baseClasses().end()) { + stack.prepend((*r).node); + ++r; + } + } + append(sections, all); + } + } + else { + if (style == Summary || style == Detailed) { + FastSection namespaces(inner, + "Namespaces", + "namespace", + "namespaces"); + FastSection classes(inner, + "Classes", + "class", + "classes"); + FastSection types(inner, + style == Summary ? + "Types" : "Type Documentation", + "type", + "types"); + FastSection functions(inner, + style == Summary ? + "Functions" : "Function Documentation", + "function", + "functions"); + FastSection macros(inner, + style == Summary ? + "Macros" : "Macro Documentation", + "macro", + "macros"); + + NodeList nodeList = inner->childNodes(); + nodeList += inner->relatedNodes(); + + NodeList::ConstIterator n = nodeList.begin(); + while (n != nodeList.end()) { + 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; +} + +const Node *CppCodeMarker::resolveTarget(const QString &target, + const Tree *tree, + const Node *relative) +{ + if (target.endsWith("()")) { + const FunctionNode *func; + QString funcName = target; + funcName.chop(2); + + QStringList path = funcName.split("::"); + if ((func = tree->findFunctionNode(path, + relative, + Tree::SearchBaseClasses)) + && func->metaness() != FunctionNode::MacroWithoutParams) + return func; + } + else if (target.contains("#")) { + // ### this doesn't belong here; get rid of TargetNode hack + int hashAt = target.indexOf("#"); + QString link = target.left(hashAt); + QString ref = target.mid(hashAt + 1); + const Node *node; + if (link.isEmpty()) { + node = relative; + } + else { + QStringList path(link); + node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses); + } + if (node && node->isInnerNode()) { + const Atom *atom = node->doc().body().firstAtom(); + while (atom) { + if (atom->type() == Atom::Target && atom->string() == ref) { + Node *parentNode = const_cast(node); + return new TargetNode(static_cast(parentNode), + ref); + } + atom = atom->next(); + } + } + } + else { + QStringList path = target.split("::"); + const Node *node; + if ((node = tree->findNode(path, + relative, + Tree::SearchBaseClasses | + Tree::SearchEnumValues | + Tree::NonFunction))) + return node; + } + return 0; +} + +QString CppCodeMarker::addMarkUp(const QString& protectedCode, + const Node * /* relative */, + const QString& /* dirPath */) +{ + static QRegExp globalInclude("#include +<([^<>&]+)>"); + static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)" + "(?:<[^;{}]+>)?(?: *(?:\\*|&) *| +)" + "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]"); + static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)"); + static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|->|,[ \n]*S(?:IGNAL|LOT)\\() *" + "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()"); + static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()"); + static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?" + "([a-zA-Z_][a-zA-Z_0-9]*)"); + static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); + static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); + multiLineComment.setMinimal(true); + static QRegExp singleLineComment("//(?!!)[^!\n]*"); + static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" + "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); + static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" + "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'"); + + QString result = protectedCode; + int pos; + + if (!hurryUp()) { + /* + Mark global includes. For example: + + #include <<@headerfile>QString + */ + pos = 0; + while ((pos = result.indexOf(globalInclude, pos)) != -1) + pos += globalInclude.matchedLength() + + insertTagAround(result, + globalInclude.pos(1), + globalInclude.cap(1).length(), + "@headerfile"); + + /* + Look for variable definitions and similar constructs, mark + the data type, and remember the type of the variable. + */ + QMap > typesForVariable; + pos = 0; + while ((pos = yHasTypeX.indexIn(result, pos)) != -1) { + QString x = yHasTypeX.cap(1); + QString y = yHasTypeX.cap(2); + + if (!y.isEmpty()) + typesForVariable[y].insert(x); + + /* + Without the minus one at the end, 'void member(Class + var)' would give 'member' as a variable of type 'void', + but would ignore 'Class var'. (### Is that true?) + */ + pos += yHasTypeX.matchedLength() + + insertTagAround(result, + yHasTypeX.pos(1), + x.length(), + "@type") - 1; + } + + /* + Do syntax highlighting of preprocessor directives. + */ + pos = 0; + while ((pos = preprocessor.indexIn(result, pos)) != -1) + pos += preprocessor.matchedLength() + + insertTagAround(result, + preprocessor.pos(1), + preprocessor.cap(1).length(), + "@preprocessor"); + + /* + Deal with string and character literals. + */ + pos = 0; + while ((pos = literals.indexIn(result, pos)) != -1) + pos += literals.matchedLength() + + insertTagAround(result, + pos, + literals.matchedLength(), + result.at(pos) == + QLatin1Char(' ') ? "@string" : "@char"); + + /* + Look for 'var = new Class'. + */ + pos = 0; + while ((pos = xNewY.indexIn(result, pos)) != -1) { + QString x = xNewY.cap(1); + QString y = xNewY.cap(2); + typesForVariable[x].insert(y); + + pos += xNewY.matchedLength() + insertTagAround(result, + xNewY.pos(2), + y.length(), + "@type"); + } + + /* + Insert some stuff that cannot harm. + */ + typesForVariable["qApp"].insert("QApplication"); + + /* + Add link to ': Class'. + */ + pos = 0; + while ((pos = classX.indexIn(result, pos)) != -1) + pos += classX.matchedLength() + + insertTagAround(result, + classX.pos(1), + classX.cap(1).length(), + "@type") - 1; + + /* + Find use of any of + + var.method() + var->method() + var, SIGNAL(method()) + var, SLOT(method()). + */ + pos = 0; + while ((pos = xDotY.indexIn(result, pos)) != -1) { + QString x = xDotY.cap(1); + QString y = xDotY.cap(2); + + QSet types = typesForVariable.value(x); + pos += xDotY.matchedLength() + + insertTagAround(result, + xDotY.pos(2), + xDotY.cap(2).length(), + "@func", + (types.count() == 1) ? "target=\"" + + protect(*types.begin() + "::" + y) + + "()\"" : QString()); + } + + /* + Add link to 'Class::method()'. + */ + pos = 0; + while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) { + QString x = xIsStaticZOfY.cap(1); + QString z = xIsStaticZOfY.cap(3); + + pos += insertTagAround(result, + xIsStaticZOfY.pos(3), + z.length(), + "@func", + "target=\"" + protect(x) + "()\""); + pos += insertTagAround(result, + xIsStaticZOfY.pos(2), + xIsStaticZOfY.cap(2).length(), + "@type"); + pos += xIsStaticZOfY.matchedLength() - 1; + } + + /* + Add link to 'globalFunction()'. + */ + pos = 0; + while ((pos = globalX.indexIn(result, pos)) != -1) { + QString x = globalX.cap(1); + if (x != "QT_FORWARD_DECLARE_CLASS") { + pos += globalX.matchedLength() + + insertTagAround(result, + globalX.pos(1), + x.length(), + "@func", + "target=\"" + protect(x) + "()\"") - 1; + } + else + pos += globalX.matchedLength(); + } + } + + /* + Do syntax highlighting of comments. Also alter the code in a + minor way, so that we can include comments in documentation + comments. + */ + pos = 0; + while (pos != -1) { + int mlpos; + int slpos; + int len; + slpos = singleLineComment.indexIn(result, pos); + mlpos = multiLineComment.indexIn(result, pos); + + if (slpos == -1 && mlpos == -1) + break; + + if (slpos == -1) { + pos = mlpos; + len = multiLineComment.matchedLength(); + } + else if (mlpos == -1) { + pos = slpos; + len = singleLineComment.matchedLength(); + } + else { + if (slpos < mlpos) { + pos = slpos; + len = singleLineComment.matchedLength(); + } + else { + pos = mlpos; + len = multiLineComment.matchedLength(); + } + } + + if (result.at(pos + 1) == QLatin1Char(' ')) { + result.remove(pos + len - 2, 1); + result.remove(pos + 1, 1); + len -= 2; + + forever { + int endcodePos = result.indexOf("\\ endcode", pos); + if (endcodePos == -1 || endcodePos >= pos + len) + break; + result.remove(endcodePos + 1, 1); + len -= 1; + } + } + pos += len + insertTagAround(result, pos, len, "@comment"); + } + + return result; +} + +#ifdef QDOC_QML +/*! + This function is for documenting QML properties. It returns + the list of documentation sections for the children of the + \a qmlClassNode. + + Currently, it only handles QML property groups. + */ +QList
CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style) +{ + QList
sections; + if (qmlClassNode) { + if (style == Summary) { + FastSection qmlproperties(qmlClassNode, + "QML Properties", + "property", + "properties"); + FastSection qmlattachedproperties(qmlClassNode, + "QML Attached Properties", + "property", + "properties"); + FastSection qmlsignals(qmlClassNode, + "QML Signals", + "signal", + "signals"); + FastSection qmlmethods(qmlClassNode, + "QML Methods", + "method", + "methods"); + + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast(*c); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + 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) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlattachedproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + else if (style == Detailed) { + FastSection qmlproperties(qmlClassNode,"QML Property Documentation"); + FastSection qmlattachedproperties(qmlClassNode,"QML Attached Property Documentation"); + FastSection qmlsignals(qmlClassNode,"QML Signal Documentation"); + FastSection qmlmethods(qmlClassNode,"QML Method Documentation"); + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* pgn = static_cast(*c); + if (pgn->isAttached()) + insert(qmlattachedproperties,*c,style,Okay); + else + insert(qmlproperties,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlattachedproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + } + + return sections; +} +#endif + +QT_END_NAMESPACE